summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorVladimír Čunát <vcunat@gmail.com>2016-03-08 09:57:58 +0100
committerVladimír Čunát <vcunat@gmail.com>2016-03-08 09:58:19 +0100
commit09af15654f0c8091f1b9e0bbb2e523cdee194442 (patch)
treee648edef1ce4c64c533f2593aa22b8015cf0e506 /nixos
parentf306e67e15bdbe9a8358c9f81319fc4fcbadc2eb (diff)
parent0ee75214f336474e127c2e3546c0406a0c4d5fa7 (diff)
downloadnixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar
nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.gz
nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.bz2
nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.lz
nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.xz
nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.zst
nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.zip
Merge master into closure-size
The kde-5 stuff still didn't merge well.
I hand-fixed what I saw, but there may be more problems.
Diffstat (limited to 'nixos')
-rw-r--r--nixos/default.nix16
-rw-r--r--nixos/doc/manual/configuration/configuration.xml2
-rw-r--r--nixos/doc/manual/default.nix2
-rw-r--r--nixos/doc/manual/installation/installing.xml5
-rw-r--r--nixos/doc/manual/release-notes/release-notes.xml2
-rw-r--r--nixos/doc/manual/release-notes/rl-1603.xml (renamed from nixos/doc/manual/release-notes/rl-unstable.xml)87
-rw-r--r--nixos/lib/make-iso9660-image.nix2
-rw-r--r--nixos/modules/config/gtk-exe-env.nix41
-rw-r--r--nixos/modules/config/qt-plugin-env.nix37
-rw-r--r--nixos/modules/config/vpnc.nix20
-rw-r--r--nixos/modules/hardware/all-firmware.nix2
-rw-r--r--nixos/modules/hardware/network/intel-2200bg.nix2
-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/sd-image-armv7l-multiplatform.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image.nix10
-rw-r--r--nixos/modules/installer/tools/auto-upgrade.nix2
-rw-r--r--nixos/modules/misc/ids.nix9
-rw-r--r--nixos/modules/misc/locate.nix4
-rw-r--r--nixos/modules/misc/nixos.nix82
-rw-r--r--nixos/modules/misc/nixos.xml84
-rw-r--r--nixos/modules/module-list.nix22
-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.nix3
-rw-r--r--nixos/modules/programs/uim.nix31
-rw-r--r--nixos/modules/programs/venus.nix4
-rw-r--r--nixos/modules/rename.nix6
-rw-r--r--nixos/modules/security/acme.nix2
-rw-r--r--nixos/modules/security/ca.nix25
-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/hardware/sane.nix17
-rw-r--r--nixos/modules/services/hardware/udev.nix8
-rw-r--r--nixos/modules/services/logging/logstash.nix6
-rw-r--r--nixos/modules/services/mail/dovecot.nix2
-rw-r--r--nixos/modules/services/mail/dspam.nix6
-rw-r--r--nixos/modules/services/mail/opendkim.nix9
-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/gitlab.nix390
-rw-r--r--nixos/modules/services/misc/gitlab.xml103
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix1
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix2
-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/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/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/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/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/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/ssh/sshd.nix4
-rw-r--r--nixos/modules/services/networking/syncthing.nix21
-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/wpa_supplicant.nix10
-rw-r--r--nixos/modules/services/networking/zerotierone.nix7
-rw-r--r--nixos/modules/services/printing/cupsd.nix2
-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.nix1
-rw-r--r--nixos/modules/services/torrent/transmission.nix2
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix3
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/moodle.nix10
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/owncloud.nix1
-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/gnome3.nix57
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix6
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix29
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix4
-rw-r--r--nixos/modules/services/x11/hardware/libinput.nix230
-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/openbox.nix2
-rw-r--r--nixos/modules/services/x11/xserver.nix17
-rw-r--r--nixos/modules/system/activation/activation-script.nix25
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl14
-rw-r--r--nixos/modules/system/activation/top-level.nix11
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh25
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh20
-rw-r--r--nixos/modules/system/boot/systemd.nix2
-rw-r--r--nixos/modules/testing/test-instrumentation.nix13
-rw-r--r--nixos/modules/virtualisation/azure-agent.nix12
-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/ec2-data.nix24
-rw-r--r--nixos/release-combined.nix4
-rw-r--r--nixos/release.nix65
-rw-r--r--nixos/tests/avahi.nix25
-rw-r--r--nixos/tests/boot.nix8
-rw-r--r--nixos/tests/chromium.nix135
-rw-r--r--nixos/tests/installer.nix2
-rw-r--r--nixos/tests/networking.nix741
-rw-r--r--nixos/tests/nixos-pin-version.nix57
-rw-r--r--nixos/tests/printing.nix5
-rw-r--r--nixos/tests/virtualbox.nix220
129 files changed, 3834 insertions, 1980 deletions
diff --git a/nixos/default.nix b/nixos/default.nix
index 6359d10c880..5d69b79e13a 100644
--- a/nixos/default.nix
+++ b/nixos/default.nix
@@ -1,20 +1,12 @@
 { configuration ? import ./lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
 , system ? builtins.currentSystem
-, extraModules ? []
-  # This attribute is used to specify a different nixos version, a different
-  # system or additional modules which might be set conditionally.
-, reEnter ? false
 }:
 
 let
-  reEnterModule = {
-    config.nixos.path = with (import ../lib); mkIf reEnter (mkForce null);
-    config.nixos.configuration = configuration;
-  };
 
   eval = import ./lib/eval-config.nix {
     inherit system;
-    modules = [ configuration reEnterModule ] ++ extraModules;
+    modules = [ configuration ];
   };
 
   inherit (eval) pkgs;
@@ -22,14 +14,14 @@ let
   # This is for `nixos-rebuild build-vm'.
   vmConfig = (import ./lib/eval-config.nix {
     inherit system;
-    modules = [ configuration reEnterModule ./modules/virtualisation/qemu-vm.nix ] ++ extraModules;
+    modules = [ configuration ./modules/virtualisation/qemu-vm.nix ];
   }).config;
 
   # This is for `nixos-rebuild build-vm-with-bootloader'.
   vmWithBootLoaderConfig = (import ./lib/eval-config.nix {
     inherit system;
     modules =
-      [ configuration reEnterModule
+      [ configuration
         ./modules/virtualisation/qemu-vm.nix
         { virtualisation.useBootLoader = true; }
       ];
@@ -38,7 +30,7 @@ let
 in
 
 {
-  inherit (eval.config.nixos.reflect) config options;
+  inherit (eval) config options;
 
   system = eval.config.system.build.toplevel;
 
diff --git a/nixos/doc/manual/configuration/configuration.xml b/nixos/doc/manual/configuration/configuration.xml
index 1e488b59343..caba8fb1f4a 100644
--- a/nixos/doc/manual/configuration/configuration.xml
+++ b/nixos/doc/manual/configuration/configuration.xml
@@ -26,8 +26,8 @@ effect after you run <command>nixos-rebuild</command>.</para>
 
 <!-- FIXME: auto-include NixOS module docs -->
 <xi:include href="postgresql.xml" />
+<xi:include href="gitlab.xml" />
 <xi:include href="acme.xml" />
-<xi:include href="nixos.xml" />
 
 <!-- Apache; libvirtd virtualisation -->
 
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix
index 0f080947833..4c0e5518f1e 100644
--- a/nixos/doc/manual/default.nix
+++ b/nixos/doc/manual/default.nix
@@ -56,8 +56,8 @@ let
       cp -prd $sources/* . # */
       chmod -R u+w .
       cp ${../../modules/services/databases/postgresql.xml} configuration/postgresql.xml
+      cp ${../../modules/services/misc/gitlab.xml} configuration/gitlab.xml
       cp ${../../modules/security/acme.xml} configuration/acme.xml
-      cp ${../../modules/misc/nixos.xml} configuration/nixos.xml
       ln -s ${optionsDocBook} options-db.xml
       echo "${version}" > version
     '';
diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml
index 9aec57fb6d5..7e71df28cdb 100644
--- a/nixos/doc/manual/installation/installing.xml
+++ b/nixos/doc/manual/installation/installing.xml
@@ -22,7 +22,10 @@
   (with empty password).</para></listitem>
 
   <listitem><para>If you downloaded the graphical ISO image, you can
-  run <command>start display-manager</command> to start KDE.</para></listitem>
+  run <command>start display-manager</command> to start KDE. If you
+  want to continue on the terminal, you can use
+  <command>loadkeys</command> to switch to your preferred keyboard layout.
+  (We even provide neo2 via <command>loadkeys de neo</command>!)</para></listitem>
 
   <listitem><para>The boot process should have brought up networking (check
   <command>ip a</command>).  Networking is necessary for the
diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml
index 6ed99315a7a..2beaab00800 100644
--- a/nixos/doc/manual/release-notes/release-notes.xml
+++ b/nixos/doc/manual/release-notes/release-notes.xml
@@ -9,7 +9,7 @@
 <para>This section lists the release notes for each stable version of NixOS
 and current unstable revision.</para>
 
-<xi:include href="rl-unstable.xml" />
+<xi:include href="rl-1603.xml" />
 <xi:include href="rl-1509.xml" />
 <xi:include href="rl-1412.xml" />
 <xi:include href="rl-1404.xml" />
diff --git a/nixos/doc/manual/release-notes/rl-unstable.xml b/nixos/doc/manual/release-notes/rl-1603.xml
index 768b51d84a4..0ede1a9ce8e 100644
--- a/nixos/doc/manual/release-notes/rl-unstable.xml
+++ b/nixos/doc/manual/release-notes/rl-1603.xml
@@ -2,9 +2,9 @@
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
-         xml:id="sec-release-unstable">
+         xml:id="sec-release-16.03">
 
-<title>Unstable</title>
+<title>Release 16.03 (“Emu”, 2016/03/??)</title>
 
 <para>In addition to numerous new and upgraded packages, this release
 has the following highlights:</para>
@@ -12,19 +12,6 @@ has the following highlights:</para>
 <itemizedlist>
 
   <listitem>
-    <para>You can now pin a specific version of NixOS in your <filename>configuration.nix</filename>
-    by setting:
-
-<programlisting>
-nixos.path = ./nixpkgs-unstable-2015-12-06/nixos;
-</programlisting>
-
-    This will make NixOS re-evaluate your configuration with the modules of
-    the specified NixOS version at the given path.  For more details, see
-    <xref linkend="module-misc-nixos" /></para>
-  </listitem>
-
-  <listitem>
     <para>Firefox and similar browsers are now <emphasis>wrapped by default</emphasis>.
     The package and attribute names are plain <literal>firefox</literal>
     or <literal>midori</literal>, etc.  Backward-compatibility attributes were set up,
@@ -41,8 +28,10 @@ nixos.path = ./nixpkgs-unstable-2015-12-06/nixos;
 
   <itemizedlist>
     <listitem><para><literal>services/monitoring/longview.nix</literal></para></listitem>
+    <listitem><para><literal>services/networking/pdnsd.nix</literal></para></listitem>
     <listitem><para><literal>services/web-apps/pump.io.nix</literal></para></listitem>
     <listitem><para><literal>services/security/haka.nix</literal></para></listitem>
+    <listitem><para><literal>i18n/inputMethod/default.nix</literal></para></listitem>
   </itemizedlist>
 </para>
 
@@ -196,6 +185,68 @@ fileSystems."/example" = {
     <literal>services.hardware.opengl.extraPackages{,32}</literal> instead. You can
     also specify VDPAU drivers there.</para>
   </listitem>
+
+  <listitem>
+    <para>
+    <literal>programs.ibus</literal> moved to <literal>i18n.inputMethod.ibus</literal>.
+    The option <literal>programs.ibus.plugins</literal> changed to <literal>i18n.inputMethod.ibus.engines</literal>
+    and the option to enable ibus changed from <literal>programs.ibus.enable</literal> to
+    <literal>i18n.inputMethod.enabled</literal>.
+    <literal>i18n.inputMethod.enabled</literal> should be set to the used input method name,
+    <literal>"ibus"</literal> for ibus.
+    An example of the new style:
+
+<programlisting>
+i18n.inputMethod.enabled = "ibus";
+i18n.inputMethod.ibus.engines = with pkgs.ibus-engines; [ anthy mozc ];
+</programlisting>
+
+That is equivalent to the old version:
+
+<programlisting>
+programs.ibus.enable = true;
+programs.ibus.plugins = with pkgs; [ ibus-anthy mozc ];
+</programlisting>
+
+    </para>
+  </listitem>
+
+  <listitem>
+    <para><literal>services.udev.extraRules</literal> option now writes rules
+    to <filename>99-local.rules</filename> instead of <filename>10-local.rules</filename>.
+    This makes all the user rules apply after others, so their results wouldn't be
+    overriden by anything else.</para>
+  </listitem>
+
+  <listitem>
+    <para>Large parts of the <literal>services.gitlab</literal> module has been
+    been rewritten. There are new configuration options available. The
+    <literal>stateDir</literal> option was renamned to
+    <literal>statePath</literal> and the <literal>satellitesDir</literal> option
+    was removed. Please review the currently available options.</para>
+  </listitem>
+
+  <listitem>
+    <para>
+    The option <option>services.nsd.zones.&lt;name&gt;.data</option> no
+    longer interpret the dollar sign ($) as a shell variable, as such it
+    should not be escaped anymore.  Thus the following zone data:
+    </para>
+    <programlisting>
+\$ORIGIN example.com.
+\$TTL 1800
+@       IN      SOA     ns1.vpn.nbp.name.      admin.example.com. (
+    </programlisting>
+    <para>
+    Should modified to look like the actual file expected by nsd:
+    </para>
+    <programlisting>
+$ORIGIN example.com.
+$TTL 1800
+@       IN      SOA     ns1.vpn.nbp.name.      admin.example.com. (
+    </programlisting>
+  </listitem>
+
 </itemizedlist>
 
 
@@ -214,6 +265,12 @@ fileSystems."/example" = {
     NixOS.</para>
   </listitem>
 
+  <listitem>
+    <para>Input method support was improved. New NixOS modules (fcitx, nabi and uim),
+    fcitx engines (chewing, hangul, m17n, mozc and table-other) and ibus engines (hangul and m17n)
+    have been added.</para>
+  </listitem>
+
 </itemizedlist></para>
 
 </section>
diff --git a/nixos/lib/make-iso9660-image.nix b/nixos/lib/make-iso9660-image.nix
index b2409c6006b..21c9cca316d 100644
--- a/nixos/lib/make-iso9660-image.nix
+++ b/nixos/lib/make-iso9660-image.nix
@@ -22,7 +22,7 @@
 , # Whether this should be an efi-bootable El-Torito CD.
   efiBootable ? false
 
-, # Wheter this should be an hybrid CD (bootable from USB as well as CD).
+, # Whether this should be an hybrid CD (bootable from USB as well as CD).
   usbBootable ? false
 
 , # The path (in the ISO file system) of the boot image.
diff --git a/nixos/modules/config/gtk-exe-env.nix b/nixos/modules/config/gtk-exe-env.nix
deleted file mode 100644
index b565072e3a7..00000000000
--- 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/qt-plugin-env.nix b/nixos/modules/config/qt-plugin-env.nix
deleted file mode 100644
index c5986560416..00000000000
--- 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 68d755232eb..c7ac1b3530e 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/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index 1a04baef193..d0d481f72a4 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 1b70057d135..17b973474c9 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/i18n/inputMethod/default.nix b/nixos/modules/i18n/inputMethod/default.nix
new file mode 100644
index 00000000000..7e6a25bfb08
--- /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 00000000000..8e31743504f
--- /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 00000000000..bb80f43634d
--- /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 00000000000..c6708365eff
--- /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 00000000000..f8a3e560656
--- /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 00000000000..5725938465f
--- /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 506b9292b01..a4bcd7079a4 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 d14768bc107..d14768bc107 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/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
index 15e22fb50d4..957a8ff9ce6 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 12b4f304561..9eba542d8c9 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/tools/auto-upgrade.nix b/nixos/modules/installer/tools/auto-upgrade.nix
index ca51de0fb8c..79ccb5c3d18 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/misc/ids.nix b/nixos/modules/misc/ids.nix
index 064b4cbc4b3..0ab2b8a76fc 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 318b81ca07c..5b560cedc62 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -67,7 +67,9 @@ in {
   };
 
   config = {
-    warnings = let opt = options.services.locate.period; in optional opt.isDefined "The `period` definition in ${showFiles opt.files} has been removed; please replace it with `interval`, using the new systemd.time interval specifier.";
+    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";
diff --git a/nixos/modules/misc/nixos.nix b/nixos/modules/misc/nixos.nix
deleted file mode 100644
index 84365b640a4..00000000000
--- 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 064bdd80b3c..00000000000
--- 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 0011544988d..0105cc3cdf2 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
@@ -43,6 +41,11 @@
   ./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
@@ -53,7 +56,6 @@
   ./misc/lib.nix
   ./misc/locate.nix
   ./misc/meta.nix
-  ./misc/nixos.nix
   ./misc/nixpkgs.nix
   ./misc/passthru.nix
   ./misc/version.nix
@@ -66,7 +68,6 @@
   ./programs/environment.nix
   ./programs/freetds.nix
   ./programs/fish.nix
-  ./programs/ibus.nix
   ./programs/kbdlight.nix
   ./programs/light.nix
   ./programs/man.nix
@@ -76,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
@@ -89,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
@@ -201,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
@@ -211,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
@@ -227,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
@@ -236,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
@@ -250,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
@@ -268,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
@@ -316,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
@@ -331,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
@@ -340,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
@@ -439,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
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 20a1f7f1ed8..66b5765a895 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 759fdb7f8e5..987eb051b98 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 1c3c07a1c21..e4e264ec003 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 398fd104363..e0860a242b7 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 a42753a292b..00000000000
--- 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 169c6a38e75..1ad45f46803 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.'';
       };
 
@@ -226,7 +227,5 @@ in
 
     environment.variables.SSH_ASKPASS = optionalString config.services.xserver.enable askPassword;
 
-    programs.ssh.askPassword = mkDefault "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
-
   };
 }
diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix
deleted file mode 100644
index 4bf2f9a1757..00000000000
--- 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 c3756b4838c..731ebed14c7 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-certificates.crt";
         startAt = cfg.dates;
       };
 
-    services.venus.outputTheme = mkDefault "${pkgs.venus}/themes/classic_fancy";
-
   };
 }
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 6e10b47f03c..85435884b19 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" ])
 
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index 3d25e811e67..c5cd0fb60ee 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -56,7 +56,7 @@ let
 
       plugins = mkOption {
         type = types.listOf (types.enum [
-          "cert.der" "cert.pem" "chain.pem" "external_pem.sh"
+          "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" ];
diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix
index 98d73ed2542..849530238e7 100644
--- a/nixos/modules/security/ca.nix
+++ b/nixos/modules/security/ca.nix
@@ -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.
@@ -64,12 +67,6 @@ in
     # CentOS/Fedora compatibility.
     environment.etc."pki/tls/certs/ca-bundle.crt".source = caCertificates;
 
-    environment.sessionVariables =
-      { SSL_CERT_FILE          = "/etc/ssl/certs/ca-certificates.crt";
-        # FIXME: unneeded - remove eventually.
-        GIT_SSL_CAINFO         = "/etc/ssl/certs/ca-certificates.crt";
-      };
-
   };
 
 }
diff --git a/nixos/modules/security/oath.nix b/nixos/modules/security/oath.nix
new file mode 100644
index 00000000000..20f3e2dd9f8
--- /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 2ee8a803d2f..021c561af75 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 56ff388f8a9..261f9761766 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 cf00d894655..ad8836f4009 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 fb77586f689..6fd39e68b1d 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/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index 56504cd2361..a3403740312 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 369a50bd6a8..8e883ed7775 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -13,13 +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/10-local.hwdb";
+    destination = "/etc/udev/hwdb.d/99-local.hwdb";
   };
 
   nixosRules = ''
@@ -212,8 +212,8 @@ 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.
         '';
       };
 
diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix
index d27456e59e8..e019e6c3f23 100644
--- a/nixos/modules/services/logging/logstash.nix
+++ b/nixos/modules/services/logging/logstash.nix
@@ -85,7 +85,7 @@ in
         type = types.lines;
         default = ''stdin { type => "example" }'';
         description = "Logstash input configuration.";
-        example = literalExample ''
+        example = ''
           # Read from journal
           pipe {
             command => "''${pkgs.systemd}/bin/journalctl -f -o json"
@@ -98,7 +98,7 @@ in
         type = types.lines;
         default = ''noop {}'';
         description = "logstash filter configuration.";
-        example = literalExample ''
+        example = ''
           if [type] == "syslog" {
             # Keep only relevant systemd fields
             # http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
@@ -114,7 +114,7 @@ in
 
       outputConfig = mkOption {
         type = types.lines;
-        default = literalExample ''stdout { debug => true debug_format => "json"}'';
+        default = ''stdout { debug => true debug_format => "json"}'';
         description = "Logstash output configuration.";
         example = ''
           redis { host => "localhost" data_type => "list" key => "logstash" codec => json }
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 333a03315bc..3935c14dc8c 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -254,7 +254,7 @@ in
         ${concatStringsSep "\n" (mapAttrsToList (to: from: ''
           if [ -d '${from}' ]; then
             mkdir '${stateDir}/sieve/${to}'
-            cp ${from}/*.sieve '${stateDir}/sieve/${to}'
+            cp "${from}/"*.sieve '${stateDir}/sieve/${to}'
           else
             cp '${from}' '${stateDir}/sieve/${to}'
           fi
diff --git a/nixos/modules/services/mail/dspam.nix b/nixos/modules/services/mail/dspam.nix
index 2d8aebe2057..46e6f216b21 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,6 +111,7 @@ 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";
diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix
index 1cdae9cb654..af996758f41 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/misc/bepasty.nix b/nixos/modules/services/misc/bepasty.nix
index 12671cb1b6c..5bda73ab64f 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 00000000000..69a33d0b8c1
--- /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 81abaf336dc..84622622db7 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 00000000000..91047ead436
--- /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/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 949357ab20f..cc50bfbea53 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 00000000000..b630fe42113
--- /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/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
index 27c5a38e6b8..0ae0516769c 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 24ae515a6b8..b0e4bf106d3 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -367,6 +367,8 @@ in
           // { 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 3e1f53e79f3..37ea339300d 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 00000000000..9cf46345c22
--- /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 fb62351365e..875771dfa37 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 00000000000..f8133394ffd
--- /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 5a33aa33b26..c1ebe418f72 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/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index 717c2c48168..3c3d83c66ed 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 ed9be73ba65..bd8d9950f77 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-certificates.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 0b49038dd27..5c6f063b149 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/hdaps.nix b/nixos/modules/services/monitoring/hdaps.nix
new file mode 100644
index 00000000000..be26c44e78d
--- /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 00000000000..bff54406a2b
--- /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 576e5c9e87a..a186982ec9c 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 e7e1db19152..e76cdac14ca 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/consul.nix b/nixos/modules/services/networking/consul.nix
index 58dad56014b..2aa101f980d 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 e60520c742b..c5dd1e71c18 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-certificates.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 9340be28205..016b6a12cd6 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 7af11f37a43..8ffce23a4b1 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/ifplugd.nix b/nixos/modules/services/networking/ifplugd.nix
deleted file mode 100644
index 00b94fe2284..00000000000
--- 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 7d70a3d05fa..5f3efcd133a 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 00000000000..3866b216f8e
--- /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 01c05fb4a24..9912ad9ae3f 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/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix
new file mode 100644
index 00000000000..cfa662c7311
--- /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 e85f2681125..333a3378c4c 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 00000000000..f4467b81895
--- /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/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index ba3efc8c0c2..5971a5a250d 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -263,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 {
@@ -304,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
 
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index f5d5e1d2556..67b90516b99 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/tlsdated.nix b/nixos/modules/services/networking/tlsdated.nix
index ff7d0178a81..757cce28760 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 73b10c1d561..89762fe5248 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/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 1558c583289..a8f445a2c73 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -78,10 +78,11 @@ in {
         '';
         default = {};
         example = literalExample ''
-          echelon = {
-            psk = "abcdefgh";
-          };
-          "free.wifi" = {};
+          { echelon = {
+              psk = "abcdefgh";
+            };
+            "free.wifi" = {};
+          }
         '';
       };
 
@@ -127,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 886ea18d980..6237f95b127 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 9411a225beb..59416560655 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -310,7 +310,7 @@ in
               [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i"
             done
             ${optionalString cfg.gutenprint ''
-              ${gutenprint}/bin/cups-genppdupdate
+              ${gutenprint}/bin/cups-genppdupdate -p /etc/cups/ppd
             ''}
           '';
       };
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index 548aee29b26..e4e5c1253b7 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 1d3e18dcab2..afbd81be91f 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
index 4f2bdd29cc4..f48a79b1f7f 100644
--- a/nixos/modules/services/security/haka.nix
+++ b/nixos/modules/services/security/haka.nix
@@ -59,6 +59,7 @@ in
 
       package = mkOption {
         default = pkgs.haka;
+        defaultText = "pkgs.haka";
         type = types.package;
         description = "
           Which Haka derivation to use.
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index c4dc6512a0d..59ef915af6d 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 880cd9f39c4..ed66ea9fc87 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -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/moodle.nix b/nixos/modules/services/web-servers/apache-httpd/moodle.nix
index 84c8281ecd8..87b1fba5aa1 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 5633f30e4a8..94e85f1f428 100644
--- a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
@@ -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 bdd41ed702b..6a60000ce19 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 3e18a6f0e98..e6c25e6215c 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/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 6cb4f3acba8..b112fc2422a 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,19 +52,33 @@ 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;
@@ -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/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 62e483ae706..2dc03b7fe63 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -76,8 +76,6 @@ in
 
     environment.systemPackages =
       [
-        pkgs.qt4 # qtconfig is the only way to set Qt 4 theme
-
         kde5.frameworkintegration
         kde5.kinit
 
@@ -103,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.
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index b93e7db4600..da7be748d8b 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -49,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.
@@ -219,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
@@ -309,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 3949bf01a31..ac7db3d9adc 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -87,6 +87,7 @@ in
 
       background = mkOption {
         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/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix
new file mode 100644
index 00000000000..12cc1e7e646
--- /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/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix
index 8b4e91d25aa..271b1b6cf5d 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 37d3348b8a3..26dfbb1f4e1 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 00000000000..dbbd8a125d6
--- /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/openbox.nix b/nixos/modules/services/x11/window-managers/openbox.nix
index 091b533b28b..07ef77151e9 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 069653d1e45..60b6a97416a 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.";
       };
 
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index 72dd9b94a94..9d61d64f755 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
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index d9048427801..093b7f1ff22 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;
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index d66580b7b9b..2d1b0ffb54c 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/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 95df0ace1ca..c0c2b6a9416 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
@@ -415,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-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index a73070ab332..1b5b22c2005 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 c5ee95f4c9a..a3c83521c35 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -160,6 +160,7 @@ let
       "systemd-timedated.service"
       "systemd-localed.service"
       "systemd-hostnamed.service"
+      "systemd-binfmt.service"
     ]
 
     ++ cfg.additionalUpstreamSystemUnits;
@@ -779,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/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index c233beb63ca..f0f56b17f20 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/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix
index 96418d61ff8..640519758c7 100644
--- a/nixos/modules/virtualisation/azure-agent.nix
+++ b/nixos/modules/virtualisation/azure-agent.nix
@@ -9,10 +9,10 @@ let
   waagent = with pkgs; stdenv.mkDerivation rec {
     name = "waagent-2.0";
     src = pkgs.fetchFromGitHub {
-      owner = "phreedom";
+      owner = "Azure";
       repo = "WALinuxAgent";
-      rev = "1d31fe8cbc7f842993eed9b33a3d3f5410c364e3";
-      sha256 = "1s53pfmy3azp0rmympmnphyq96sr9jy07pbsfza6mdzpalx1ripl";
+      rev = "1b3a8407a95344d9d12a2a377f64140975f1e8e4";
+      sha256 = "10byzvmpgrmr4d5mdn2kq04aapqb3sgr1admk13wjmy5cd6bwd2x";
     };
     buildInputs = [ makeWrapper python pythonPackages.wrapPython ];
     runtimeDeps = [ findutils gnugrep gawk coreutils openssl openssh
@@ -157,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 00000000000..de1b3857923
--- /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 08944e641d7..79d1f7d7cc4 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 00000000000..81d29feea3d
--- /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/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix
index bee26261268..db3dd9949c1 100644
--- a/nixos/modules/virtualisation/ec2-data.nix
+++ b/nixos/modules/virtualisation/ec2-data.nix
@@ -43,18 +43,20 @@ with lib;
 
             mkdir -m 0755 -p /etc/ssh
 
-            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
+            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
+              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/release-combined.nix b/nixos/release-combined.nix
index 06890b458ef..958e587444d 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -48,7 +48,7 @@ in rec {
         (all nixos.ova)
 
         #(all nixos.tests.containers)
-        (all nixos.tests.chromium)
+        (all nixos.tests.chromium.stable)
         (all nixos.tests.firefox)
         (all nixos.tests.firewall)
         nixos.tests.gnome3.x86_64-linux # FIXME: i686-linux
@@ -63,7 +63,7 @@ in rec {
         (all nixos.tests.installer.btrfsSimple)
         (all nixos.tests.installer.btrfsSubvols)
         (all nixos.tests.installer.btrfsSubvolDefault)
-        (all nixos.tests.bootBiosCdrom)
+        (all nixos.tests.boot.biosCdrom)
         (all nixos.tests.ipv6)
         (all nixos.tests.kde4)
         #(all nixos.tests.lightdm)
diff --git a/nixos/release.nix b/nixos/release.nix
index d9f3e46b27c..069cf3727de 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -13,7 +13,25 @@ let
 
   forAllSystems = genAttrs supportedSystems;
 
-  callTest = fn: args: forAllSystems (system: hydraJob (import fn ({ inherit system; } // args)));
+  importTest = fn: args: system: import fn ({
+    inherit system;
+  } // args);
+
+  callTest = fn: args: forAllSystems (system: hydraJob (importTest fn args system));
+
+  callSubTests = fn: args: let
+    discover = attrs: let
+      subTests = filterAttrs (const (hasAttr "test")) attrs;
+    in mapAttrs (const (t: hydraJob t.test)) subTests;
+
+    discoverForSystem = system: mapAttrs (_: test: {
+      ${system} = test;
+    }) (discover (importTest fn args system));
+
+  # If the test is only for a particular system, use only the specified
+  # system instead of generating attributes for all available systems.
+  in if args ? system then discover (import fn args)
+     else foldAttrs mergeAttrs {} (map discoverForSystem supportedSystems);
 
   pkgs = import nixpkgs { system = "x86_64-linux"; };
 
@@ -113,7 +131,7 @@ in rec {
   });
 
   iso_graphical = forAllSystems (system: makeIso {
-    module = ./modules/installer/cd-dvd/installation-cd-graphical.nix;
+    module = ./modules/installer/cd-dvd/installation-cd-graphical-kde.nix;
     type = "graphical";
     inherit system;
   });
@@ -215,8 +233,9 @@ in rec {
   tests.avahi = callTest tests/avahi.nix {};
   tests.bittorrent = callTest tests/bittorrent.nix {};
   tests.blivet = callTest tests/blivet.nix {};
+  tests.boot = callSubTests tests/boot.nix {};
   tests.cadvisor = hydraJob (import tests/cadvisor.nix { system = "x86_64-linux"; });
-  tests.chromium = callTest tests/chromium.nix {};
+  tests.chromium = callSubTests tests/chromium.nix {};
   tests.cjdns = callTest tests/cjdns.nix {};
   tests.containers = callTest tests/containers.nix {};
   tests.docker = hydraJob (import tests/docker.nix { system = "x86_64-linux"; });
@@ -232,18 +251,7 @@ in rec {
   tests.gnome3-gdm = callTest tests/gnome3-gdm.nix {};
   tests.grsecurity = callTest tests/grsecurity.nix {};
   tests.i3wm = callTest tests/i3wm.nix {};
-  tests.installer.grub1 = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).grub1.test);
-  tests.installer.lvm = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).lvm.test);
-  tests.installer.luksroot = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).luksroot.test);
-  tests.installer.separateBoot = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).separateBoot.test);
-  tests.installer.separateBootFat = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).separateBootFat.test);
-  tests.installer.simple = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).simple.test);
-  tests.installer.simpleLabels = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).simpleLabels.test);
-  tests.installer.simpleProvided = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).simpleProvided.test);
-  tests.installer.swraid = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).swraid.test);
-  tests.installer.btrfsSimple = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).btrfsSimple.test);
-  tests.installer.btrfsSubvols = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).btrfsSubvols.test);
-  tests.installer.btrfsSubvolDefault = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).btrfsSubvolDefault.test);
+  tests.installer = callSubTests tests/installer.nix {};
   tests.influxdb = callTest tests/influxdb.nix {};
   tests.ipv6 = callTest tests/ipv6.nix {};
   tests.jenkins = callTest tests/jenkins.nix {};
@@ -262,29 +270,12 @@ in rec {
   tests.mysqlReplication = callTest tests/mysql-replication.nix {};
   tests.nat.firewall = callTest tests/nat.nix { withFirewall = true; };
   tests.nat.standalone = callTest tests/nat.nix { withFirewall = false; };
-  tests.networking.networkd.loopback = callTest tests/networking.nix { networkd = true; test = "loopback"; };
-  tests.networking.networkd.static = callTest tests/networking.nix { networkd = true; test = "static"; };
-  tests.networking.networkd.dhcpSimple = callTest tests/networking.nix { networkd = true; test = "dhcpSimple"; };
-  tests.networking.networkd.dhcpOneIf = callTest tests/networking.nix { networkd = true; test = "dhcpOneIf"; };
-  tests.networking.networkd.bond = callTest tests/networking.nix { networkd = true; test = "bond"; };
-  tests.networking.networkd.bridge = callTest tests/networking.nix { networkd = true; test = "bridge"; };
-  tests.networking.networkd.macvlan = callTest tests/networking.nix { networkd = true; test = "macvlan"; };
-  tests.networking.networkd.sit = callTest tests/networking.nix { networkd = true; test = "sit"; };
-  tests.networking.networkd.vlan = callTest tests/networking.nix { networkd = true; test = "vlan"; };
-  tests.networking.scripted.loopback = callTest tests/networking.nix { networkd = false; test = "loopback"; };
-  tests.networking.scripted.static = callTest tests/networking.nix { networkd = false; test = "static"; };
-  tests.networking.scripted.dhcpSimple = callTest tests/networking.nix { networkd = false; test = "dhcpSimple"; };
-  tests.networking.scripted.dhcpOneIf = callTest tests/networking.nix { networkd = false; test = "dhcpOneIf"; };
-  tests.networking.scripted.bond = callTest tests/networking.nix { networkd = false; test = "bond"; };
-  tests.networking.scripted.bridge = callTest tests/networking.nix { networkd = false; test = "bridge"; };
-  tests.networking.scripted.macvlan = callTest tests/networking.nix { networkd = false; test = "macvlan"; };
-  tests.networking.scripted.sit = callTest tests/networking.nix { networkd = false; test = "sit"; };
-  tests.networking.scripted.vlan = callTest tests/networking.nix { networkd = false; test = "vlan"; };
+  tests.networking.networkd = callSubTests tests/networking.nix { networkd = true; };
+  tests.networking.scripted = callSubTests tests/networking.nix { networkd = false; };
   # TODO: put in networking.nix after the test becomes more complete
   tests.networkingProxy = callTest tests/networking-proxy.nix {};
   tests.nfs3 = callTest tests/nfs.nix { version = 3; };
   tests.nfs4 = callTest tests/nfs.nix { version = 4; };
-  tests.nixosPinVersion = callTest tests/nixos-pin-version.nix {};
   tests.nsd = callTest tests/nsd.nix {};
   tests.openssh = callTest tests/openssh.nix {};
   tests.panamax = hydraJob (import tests/panamax.nix { system = "x86_64-linux"; });
@@ -300,12 +291,8 @@ in rec {
   tests.simple = callTest tests/simple.nix {};
   tests.tomcat = callTest tests/tomcat.nix {};
   tests.udisks2 = callTest tests/udisks2.nix {};
-  tests.virtualbox = hydraJob (import tests/virtualbox.nix { system = "x86_64-linux"; });
+  tests.virtualbox = callSubTests tests/virtualbox.nix { system = "x86_64-linux"; };
   tests.xfce = callTest tests/xfce.nix {};
-  tests.bootBiosCdrom = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootBiosCdrom);
-  tests.bootBiosUsb = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootBiosUsb);
-  tests.bootUefiCdrom = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootUefiCdrom);
-  tests.bootUefiUsb = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootUefiUsb);
 
 
   /* Build a bunch of typical closures so that Hydra can keep track of
diff --git a/nixos/tests/avahi.nix b/nixos/tests/avahi.nix
index a8369a6d1f8..976a770e887 100644
--- a/nixos/tests/avahi.nix
+++ b/nixos/tests/avahi.nix
@@ -5,18 +5,21 @@ import ./make-test.nix ({ pkgs, ... } : {
     maintainers = [ eelco chaoflow ];
   };
 
-  nodes = {
-    one =
-      { config, pkgs, ... }: {
-        services.avahi.enable = true;
-        services.avahi.nssmdns = true;
-      };
-
-    two =
-      { config, pkgs, ... }: {
-        services.avahi.enable = true;
-        services.avahi.nssmdns = true;
+  nodes = let
+    cfg = { config, pkgs, ... }: {
+      services.avahi = {
+        enable = true;
+        nssmdns = true;
+        publish.addresses = true;
+        publish.domain = true;
+        publish.enable = true;
+        publish.userServices = true;
+        publish.workstation = true;
       };
+    };
+  in {
+    one = cfg;
+    two = cfg;
   };
 
   testScript =
diff --git a/nixos/tests/boot.nix b/nixos/tests/boot.nix
index 6a1d330155e..905d1645882 100644
--- a/nixos/tests/boot.nix
+++ b/nixos/tests/boot.nix
@@ -30,17 +30,17 @@ let
         '';
     };
 in {
-    bootBiosCdrom = makeBootTest "bios-cdrom" ''
+    biosCdrom = makeBootTest "bios-cdrom" ''
         cdrom => glob("${iso}/iso/*.iso")
       '';
-    bootBiosUsb = makeBootTest "bios-usb" ''
+    biosUsb = makeBootTest "bios-usb" ''
         usb => glob("${iso}/iso/*.iso")
       '';
-    bootUefiCdrom = makeBootTest "uefi-cdrom" ''
+    uefiCdrom = makeBootTest "uefi-cdrom" ''
         cdrom => glob("${iso}/iso/*.iso"),
         bios => '${pkgs.OVMF}/FV/OVMF.fd'
       '';
-    bootUefiUsb = makeBootTest "uefi-usb" ''
+    uefiUsb = makeBootTest "uefi-usb" ''
         usb => glob("${iso}/iso/*.iso"),
         bios => '${pkgs.OVMF}/FV/OVMF.fd'
       '';
diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix
index 6c61087760d..974af6888b6 100644
--- a/nixos/tests/chromium.nix
+++ b/nixos/tests/chromium.nix
@@ -1,13 +1,10 @@
-import ./make-test.nix (
-{ pkgs
-, channelMap ? {
-    stable = pkgs.chromium;
-    #beta   = pkgs.chromiumBeta;
-    #dev    = pkgs.chromiumDev;
-  }
-, ...
-}: rec {
-  name = "chromium";
+{ system ? builtins.currentSystem }:
+
+with import ../lib/testing.nix { inherit system; };
+with pkgs.lib;
+
+mapAttrs (channel: chromiumPkg: makeTest rec {
+  name = "chromium-${channel}";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ aszlig ];
   };
@@ -16,6 +13,7 @@ import ./make-test.nix (
 
   machine.imports = [ ./common/x11.nix ];
   machine.virtualisation.memorySize = 2047;
+  machine.environment.systemPackages = [ chromiumPkg ];
 
   startupHTML = pkgs.writeText "chromium-startup.html" ''
     <!DOCTYPE html>
@@ -105,74 +103,65 @@ import ./make-test.nix (
       closeWin;
     }
 
-    sub chromiumTest {
-      my ($channel, $pkg, $code) = @_;
-      $machine->waitForX;
-
-      my $url = "file://${startupHTML}";
-      my $args = "--user-data-dir=/tmp/chromium-$channel";
-      $machine->execute(
-        "ulimit -c unlimited; ".
-        "$pkg/bin/chromium $args \"$url\" & disown"
-      );
-      $machine->waitForText(qr/Type to search or enter a URL to navigate/);
-      $machine->waitUntilSucceeds("${xdo "check-startup" ''
-        search --sync --onlyvisible --name "startup done"
-        # close first start help popup
-        key -delay 1000 Escape
+    $machine->waitForX;
+
+    my $url = "file://${startupHTML}";
+    my $args = "--user-data-dir=/tmp/chromium-${channel}";
+    $machine->execute(
+      "ulimit -c unlimited; ".
+      "chromium $args \"$url\" & disown"
+    );
+    $machine->waitForText(qr/Type to search or enter a URL to navigate/);
+    $machine->waitUntilSucceeds("${xdo "check-startup" ''
+      search --sync --onlyvisible --name "startup done"
+      # close first start help popup
+      key -delay 1000 Escape
+      windowfocus --sync
+      windowactivate --sync
+    ''}");
+
+    createAndWaitForNewWin;
+    $machine->screenshot("empty_windows");
+    closeWin;
+
+    $machine->screenshot("startup_done");
+
+    testNewWin "check sandbox", sub {
+      $machine->succeed("${xdo "type-url" ''
+        search --sync --onlyvisible --name "new tab"
         windowfocus --sync
-        windowactivate --sync
+        type --delay 1000 "chrome://sandbox"
       ''}");
 
-      createAndWaitForNewWin;
-      $machine->screenshot($channel."_emptywin");
-      closeWin;
-
-      $machine->screenshot($channel."_startup_done");
-
-      subtest("Chromium $channel", $code);
-
-      $machine->shutdown;
-    }
-
-    for (${let
-      mkArray = name: pkg: "[\"${name}\", \"${pkg}\"]";
-      chanArrays = pkgs.lib.mapAttrsToList mkArray channelMap;
-    in pkgs.lib.concatStringsSep ", " chanArrays}) {
-      my ($channel, $pkg) = @$_;
-      chromiumTest $channel, $pkg, sub {
-        testNewWin "check sandbox", sub {
-          $machine->succeed("${xdo "type-url" ''
-            search --sync --onlyvisible --name "new tab"
-            windowfocus --sync
-            type --delay 1000 "chrome://sandbox"
-          ''}");
+      $machine->succeed("${xdo "submit-url" ''
+        search --sync --onlyvisible --name "new tab"
+        windowfocus --sync
+        key --delay 1000 Return
+      ''}");
 
-          $machine->succeed("${xdo "submit-url" ''
-            search --sync --onlyvisible --name "new tab"
-            windowfocus --sync
-            key --delay 1000 Return
-          ''}");
+      $machine->screenshot("sandbox_info");
 
-          $machine->screenshot($channel."_sandbox");
+      $machine->succeed("${xdo "submit-url" ''
+        search --sync --onlyvisible --name "sandbox status"
+        windowfocus --sync
+      ''}");
+      $machine->succeed("${xdo "submit-url" ''
+        key --delay 1000 Ctrl+a Ctrl+c
+      ''}");
 
-          $machine->succeed("${xdo "submit-url" ''
-            search --sync --onlyvisible --name "sandbox status"
-            windowfocus --sync
-          ''}");
-          $machine->succeed("${xdo "submit-url" ''
-            key --delay 1000 Ctrl+a Ctrl+c
-          ''}");
+      my $clipboard = $machine->succeed("${pkgs.xclip}/bin/xclip -o");
+      die "sandbox not working properly: $clipboard"
+      unless $clipboard =~ /namespace sandbox.*yes/mi
+          && $clipboard =~ /pid namespaces.*yes/mi
+          && $clipboard =~ /network namespaces.*yes/mi
+          && $clipboard =~ /seccomp.*sandbox.*yes/mi
+          && $clipboard =~ /you are adequately sandboxed/mi;
+    };
 
-          my $clipboard = $machine->succeed("${pkgs.xclip}/bin/xclip -o");
-          die "sandbox not working properly: $clipboard"
-          unless $clipboard =~ /namespace sandbox.*yes/mi
-              && $clipboard =~ /pid namespaces.*yes/mi
-              && $clipboard =~ /network namespaces.*yes/mi
-              && $clipboard =~ /seccomp.*sandbox.*yes/mi
-              && $clipboard =~ /you are adequately sandboxed/mi;
-        };
-      };
-    }
+    $machine->shutdown;
   '';
-})
+}) {
+  stable = pkgs.chromium;
+  beta   = pkgs.chromiumBeta;
+  dev    = pkgs.chromiumDev;
+}
diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 84fdb027ed8..9e5a6ad04e1 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -46,7 +46,7 @@ let
                   , grubIdentifier, preBootCommands, extraConfig
                   }:
     let
-      iface = if grubVersion == 1 then "scsi" else "virtio";
+      iface = if grubVersion == 1 then "ide" else "virtio";
       qemuFlags =
         (if system == "x86_64-linux" then "-m 768 " else "-m 512 ") +
         (optionalString (system == "x86_64-linux") "-cpu kvm64 ");
diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix
index 813d7c2bf51..d5a0a9b798f 100644
--- a/nixos/tests/networking.nix
+++ b/nixos/tests/networking.nix
@@ -1,406 +1,411 @@
-import ./make-test.nix ({ pkgs, networkd, test, ... }:
-  let
-    router = { config, pkgs, ... }:
-      with pkgs.lib;
-      let
-        vlanIfs = range 1 (length config.virtualisation.vlans);
-      in {
-        virtualisation.vlans = [ 1 2 3 ];
+{ system ? builtins.currentSystem, networkd }:
+
+with import ../lib/testing.nix { inherit system; };
+with pkgs.lib;
+
+let
+  router = { config, pkgs, ... }:
+    with pkgs.lib;
+    let
+      vlanIfs = range 1 (length config.virtualisation.vlans);
+    in {
+      virtualisation.vlans = [ 1 2 3 ];
+      networking = {
+        useDHCP = false;
+        useNetworkd = networkd;
+        firewall.allowPing = true;
+        interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n:
+          nameValuePair "eth${toString n}" {
+            ipAddress = "192.168.${toString n}.1";
+            prefixLength = 24;
+          })));
+      };
+      services.dhcpd = {
+        enable = true;
+        interfaces = map (n: "eth${toString n}") vlanIfs;
+        extraConfig = ''
+          option subnet-mask 255.255.255.0;
+        '' + flip concatMapStrings vlanIfs (n: ''
+          subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
+            option broadcast-address 192.168.${toString n}.255;
+            option routers 192.168.${toString n}.1;
+            range 192.168.${toString n}.2 192.168.${toString n}.254;
+          }
+        '');
+      };
+    };
+
+  testCases = {
+    loopback = {
+      name = "Loopback";
+      machine.networking.useNetworkd = networkd;
+      testScript = ''
+        startAll;
+        $machine->waitForUnit("network-interfaces.target");
+        $machine->waitForUnit("network.target");
+        $machine->succeed("ip addr show lo | grep -q 'inet 127.0.0.1/8 '");
+        $machine->succeed("ip addr show lo | grep -q 'inet6 ::1/128 '");
+      '';
+    };
+    static = {
+      name = "Static";
+      nodes.router = router;
+      nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ 1 2 ];
         networking = {
-          useDHCP = false;
           useNetworkd = networkd;
           firewall.allowPing = true;
-          interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n:
-            nameValuePair "eth${toString n}" {
-              ipAddress = "192.168.${toString n}.1";
-              prefixLength = 24;
-            })));
-        };
-        services.dhcpd = {
-          enable = true;
-          interfaces = map (n: "eth${toString n}") vlanIfs;
-          extraConfig = ''
-            option subnet-mask 255.255.255.0;
-          '' + flip concatMapStrings vlanIfs (n: ''
-            subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
-              option broadcast-address 192.168.${toString n}.255;
-              option routers 192.168.${toString n}.1;
-              range 192.168.${toString n}.2 192.168.${toString n}.254;
-            }
-          '');
+          useDHCP = false;
+          defaultGateway = "192.168.1.1";
+          interfaces.eth1.ip4 = mkOverride 0 [
+            { address = "192.168.1.2"; prefixLength = 24; }
+            { address = "192.168.1.3"; prefixLength = 32; }
+            { address = "192.168.1.10"; prefixLength = 32; }
+          ];
+          interfaces.eth2.ip4 = mkOverride 0 [
+            { address = "192.168.2.2"; prefixLength = 24; }
+          ];
         };
       };
-    testCases = {
-      loopback = {
-        name = "Loopback";
-        machine.networking.useNetworkd = networkd;
-        testScript = ''
+      testScript = { nodes, ... }:
+        ''
           startAll;
-          $machine->waitForUnit("network-interfaces.target");
-          $machine->waitForUnit("network.target");
-          $machine->succeed("ip addr show lo | grep -q 'inet 127.0.0.1/8 '");
-          $machine->succeed("ip addr show lo | grep -q 'inet6 ::1/128 '");
+
+          $client->waitForUnit("network-interfaces.target");
+          $client->waitForUnit("network.target");
+          $router->waitForUnit("network-interfaces.target");
+          $router->waitForUnit("network.target");
+
+          # Make sure dhcpcd is not started
+          $client->fail("systemctl status dhcpcd.service");
+
+          # Test vlan 1
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.10");
+
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.10");
+
+          # Test vlan 2
+          $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
+          $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
+
+          $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
+          $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
+
+          # Test default gateway
+          $router->waitUntilSucceeds("ping -c 1 192.168.3.1");
+          $client->waitUntilSucceeds("ping -c 1 192.168.3.1");
         '';
-      };
-      static = {
-        name = "Static";
-        nodes.router = router;
-        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ 1 2 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = false;
-            defaultGateway = "192.168.1.1";
-            interfaces.eth1.ip4 = mkOverride 0 [
-              { address = "192.168.1.2"; prefixLength = 24; }
-              { address = "192.168.1.3"; prefixLength = 32; }
-              { address = "192.168.1.10"; prefixLength = 32; }
-            ];
-            interfaces.eth2.ip4 = mkOverride 0 [
-              { address = "192.168.2.2"; prefixLength = 24; }
-            ];
-          };
+    };
+    dhcpSimple = {
+      name = "SimpleDHCP";
+      nodes.router = router;
+      nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ 1 2 ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          useDHCP = true;
+          interfaces.eth1.ip4 = mkOverride 0 [ ];
+          interfaces.eth2.ip4 = mkOverride 0 [ ];
         };
-        testScript = { nodes, ... }:
-          ''
-            startAll;
-
-            $client->waitForUnit("network-interfaces.target");
-            $client->waitForUnit("network.target");
-            $router->waitForUnit("network-interfaces.target");
-            $router->waitForUnit("network.target");
-
-            # Make sure dhcpcd is not started
-            $client->fail("systemctl status dhcpcd.service");
-
-            # Test vlan 1
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.10");
-
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.10");
-
-            # Test vlan 2
-            $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
-            $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
-
-            $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
-            $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
-
-            # Test default gateway
-            $router->waitUntilSucceeds("ping -c 1 192.168.3.1");
-            $client->waitUntilSucceeds("ping -c 1 192.168.3.1");
-          '';
       };
-      dhcpSimple = {
-        name = "SimpleDHCP";
-        nodes.router = router;
-        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ 1 2 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = true;
-            interfaces.eth1.ip4 = mkOverride 0 [ ];
-            interfaces.eth2.ip4 = mkOverride 0 [ ];
-          };
-        };
-        testScript = { nodes, ... }:
-          ''
-            startAll;
+      testScript = { nodes, ... }:
+        ''
+          startAll;
 
-            $client->waitForUnit("network-interfaces.target");
-            $client->waitForUnit("network.target");
-            $router->waitForUnit("network-interfaces.target");
-            $router->waitForUnit("network.target");
+          $client->waitForUnit("network-interfaces.target");
+          $client->waitForUnit("network.target");
+          $router->waitForUnit("network-interfaces.target");
+          $router->waitForUnit("network.target");
 
-            # Wait until we have an ip address on each interface
-            $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
-            $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'");
+          # Wait until we have an ip address on each interface
+          $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
+          $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'");
 
-            # Test vlan 1
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          # Test vlan 1
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
 
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
 
-            # Test vlan 2
-            $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
-            $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
+          # Test vlan 2
+          $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
+          $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
 
-            $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
-            $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
-          '';
-      };
-      dhcpOneIf = {
-        name = "OneInterfaceDHCP";
-        nodes.router = router;
-        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ 1 2 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = false;
-            interfaces.eth1 = {
-              ip4 = mkOverride 0 [ ];
-              useDHCP = true;
-            };
-            interfaces.eth2.ip4 = mkOverride 0 [ ];
+          $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
+          $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
+        '';
+    };
+    dhcpOneIf = {
+      name = "OneInterfaceDHCP";
+      nodes.router = router;
+      nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ 1 2 ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          useDHCP = false;
+          interfaces.eth1 = {
+            ip4 = mkOverride 0 [ ];
+            useDHCP = true;
           };
+          interfaces.eth2.ip4 = mkOverride 0 [ ];
         };
-        testScript = { nodes, ... }:
-          ''
-            startAll;
+      };
+      testScript = { nodes, ... }:
+        ''
+          startAll;
 
-            # Wait for networking to come up
-            $client->waitForUnit("network-interfaces.target");
-            $client->waitForUnit("network.target");
-            $router->waitForUnit("network-interfaces.target");
-            $router->waitForUnit("network.target");
+          # Wait for networking to come up
+          $client->waitForUnit("network-interfaces.target");
+          $client->waitForUnit("network.target");
+          $router->waitForUnit("network-interfaces.target");
+          $router->waitForUnit("network.target");
 
-            # Wait until we have an ip address on each interface
-            $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
+          # Wait until we have an ip address on each interface
+          $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
 
-            # Test vlan 1
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          # Test vlan 1
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
 
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
 
-            # Test vlan 2
-            $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
-            $client->fail("ping -c 1 192.168.2.2");
+          # Test vlan 2
+          $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
+          $client->fail("ping -c 1 192.168.2.2");
 
-            $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
-            $router->fail("ping -c 1 192.168.2.2");
-          '';
-      };
-      bond = let
-        node = address: { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ 1 2 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = false;
-            bonds.bond = {
-              mode = "balance-rr";
-              interfaces = [ "eth1" "eth2" ];
-            };
-            interfaces.eth1.ip4 = mkOverride 0 [ ];
-            interfaces.eth2.ip4 = mkOverride 0 [ ];
-            interfaces.bond.ip4 = mkOverride 0
-              [ { inherit address; prefixLength = 30; } ];
+          $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
+          $router->fail("ping -c 1 192.168.2.2");
+        '';
+    };
+    bond = let
+      node = address: { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ 1 2 ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          useDHCP = false;
+          bonds.bond = {
+            mode = "balance-rr";
+            interfaces = [ "eth1" "eth2" ];
           };
+          interfaces.eth1.ip4 = mkOverride 0 [ ];
+          interfaces.eth2.ip4 = mkOverride 0 [ ];
+          interfaces.bond.ip4 = mkOverride 0
+            [ { inherit address; prefixLength = 30; } ];
         };
-      in {
-        name = "Bond";
-        nodes.client1 = node "192.168.1.1";
-        nodes.client2 = node "192.168.1.2";
-        testScript = { nodes, ... }:
-          ''
-            startAll;
-
-            # Wait for networking to come up
-            $client1->waitForUnit("network-interfaces.target");
-            $client1->waitForUnit("network.target");
-            $client2->waitForUnit("network-interfaces.target");
-            $client2->waitForUnit("network.target");
-
-            # Test bonding
-            $client1->waitUntilSucceeds("ping -c 2 192.168.1.1");
-            $client1->waitUntilSucceeds("ping -c 2 192.168.1.2");
-
-            $client2->waitUntilSucceeds("ping -c 2 192.168.1.1");
-            $client2->waitUntilSucceeds("ping -c 2 192.168.1.2");
-          '';
       };
-      bridge = let
-        node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ vlan ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = false;
-            interfaces.eth1.ip4 = mkOverride 0
-              [ { inherit address; prefixLength = 24; } ];
-          };
+    in {
+      name = "Bond";
+      nodes.client1 = node "192.168.1.1";
+      nodes.client2 = node "192.168.1.2";
+      testScript = { nodes, ... }:
+        ''
+          startAll;
+
+          # Wait for networking to come up
+          $client1->waitForUnit("network-interfaces.target");
+          $client1->waitForUnit("network.target");
+          $client2->waitForUnit("network-interfaces.target");
+          $client2->waitForUnit("network.target");
+
+          # Test bonding
+          $client1->waitUntilSucceeds("ping -c 2 192.168.1.1");
+          $client1->waitUntilSucceeds("ping -c 2 192.168.1.2");
+
+          $client2->waitUntilSucceeds("ping -c 2 192.168.1.1");
+          $client2->waitUntilSucceeds("ping -c 2 192.168.1.2");
+        '';
+    };
+    bridge = let
+      node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ vlan ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          useDHCP = false;
+          interfaces.eth1.ip4 = mkOverride 0
+            [ { inherit address; prefixLength = 24; } ];
         };
-      in {
-        name = "Bridge";
-        nodes.client1 = node { address = "192.168.1.2"; vlan = 1; };
-        nodes.client2 = node { address = "192.168.1.3"; vlan = 2; };
-        nodes.router = { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ 1 2 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = false;
-            bridges.bridge.interfaces = [ "eth1" "eth2" ];
-            interfaces.eth1.ip4 = mkOverride 0 [ ];
-            interfaces.eth2.ip4 = mkOverride 0 [ ];
-            interfaces.bridge.ip4 = mkOverride 0
-              [ { address = "192.168.1.1"; prefixLength = 24; } ];
-          };
+      };
+    in {
+      name = "Bridge";
+      nodes.client1 = node { address = "192.168.1.2"; vlan = 1; };
+      nodes.client2 = node { address = "192.168.1.3"; vlan = 2; };
+      nodes.router = { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ 1 2 ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          useDHCP = false;
+          bridges.bridge.interfaces = [ "eth1" "eth2" ];
+          interfaces.eth1.ip4 = mkOverride 0 [ ];
+          interfaces.eth2.ip4 = mkOverride 0 [ ];
+          interfaces.bridge.ip4 = mkOverride 0
+            [ { address = "192.168.1.1"; prefixLength = 24; } ];
         };
-        testScript = { nodes, ... }:
-          ''
-            startAll;
-
-            # Wait for networking to come up
-            $client1->waitForUnit("network-interfaces.target");
-            $client1->waitForUnit("network.target");
-            $client2->waitForUnit("network-interfaces.target");
-            $client2->waitForUnit("network.target");
-            $router->waitForUnit("network-interfaces.target");
-            $router->waitForUnit("network.target");
-
-            # Test bridging
-            $client1->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $client1->waitUntilSucceeds("ping -c 1 192.168.1.2");
-            $client1->waitUntilSucceeds("ping -c 1 192.168.1.3");
-
-            $client2->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $client2->waitUntilSucceeds("ping -c 1 192.168.1.2");
-            $client2->waitUntilSucceeds("ping -c 1 192.168.1.3");
-
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
-          '';
       };
-      macvlan = {
-        name = "MACVLAN";
-        nodes.router = router;
-        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ 1 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = true;
-            macvlans.macvlan.interface = "eth1";
-            interfaces.eth1.ip4 = mkOverride 0 [ ];
-          };
+      testScript = { nodes, ... }:
+        ''
+          startAll;
+
+          # Wait for networking to come up
+          $client1->waitForUnit("network-interfaces.target");
+          $client1->waitForUnit("network.target");
+          $client2->waitForUnit("network-interfaces.target");
+          $client2->waitForUnit("network.target");
+          $router->waitForUnit("network-interfaces.target");
+          $router->waitForUnit("network.target");
+
+          # Test bridging
+          $client1->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $client1->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $client1->waitUntilSucceeds("ping -c 1 192.168.1.3");
+
+          $client2->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $client2->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $client2->waitUntilSucceeds("ping -c 1 192.168.1.3");
+
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
+        '';
+    };
+    macvlan = {
+      name = "MACVLAN";
+      nodes.router = router;
+      nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ 1 ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          useDHCP = true;
+          macvlans.macvlan.interface = "eth1";
+          interfaces.eth1.ip4 = mkOverride 0 [ ];
         };
-        testScript = { nodes, ... }:
-          ''
-            startAll;
-
-            # Wait for networking to come up
-            $client->waitForUnit("network-interfaces.target");
-            $client->waitForUnit("network.target");
-            $router->waitForUnit("network-interfaces.target");
-            $router->waitForUnit("network.target");
-
-            # Wait until we have an ip address on each interface
-            $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
-            $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'");
-
-            # Print diagnosting information
-            $router->succeed("ip addr >&2");
-            $client->succeed("ip addr >&2");
-
-            # Test macvlan creates routable ips
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
-            $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
-
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
-            $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
-          '';
       };
-      sit = let
-        node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; {
-          virtualisation.vlans = [ 1 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.enable = false;
-            useDHCP = false;
-            sits.sit = {
-              inherit remote;
-              local = address4;
-              dev = "eth1";
-            };
-            interfaces.eth1.ip4 = mkOverride 0
-              [ { address = address4; prefixLength = 24; } ];
-            interfaces.sit.ip6 = mkOverride 0
-              [ { address = address6; prefixLength = 64; } ];
+      testScript = { nodes, ... }:
+        ''
+          startAll;
+
+          # Wait for networking to come up
+          $client->waitForUnit("network-interfaces.target");
+          $client->waitForUnit("network.target");
+          $router->waitForUnit("network-interfaces.target");
+          $router->waitForUnit("network.target");
+
+          # Wait until we have an ip address on each interface
+          $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
+          $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'");
+
+          # Print diagnosting information
+          $router->succeed("ip addr >&2");
+          $client->succeed("ip addr >&2");
+
+          # Test macvlan creates routable ips
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
+
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
+          $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
+        '';
+    };
+    sit = let
+      node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; {
+        virtualisation.vlans = [ 1 ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.enable = false;
+          useDHCP = false;
+          sits.sit = {
+            inherit remote;
+            local = address4;
+            dev = "eth1";
           };
+          interfaces.eth1.ip4 = mkOverride 0
+            [ { address = address4; prefixLength = 24; } ];
+          interfaces.sit.ip6 = mkOverride 0
+            [ { address = address6; prefixLength = 64; } ];
         };
-      in {
-        name = "Sit";
-        nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; };
-        nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; };
-        testScript = { nodes, ... }:
-          ''
-            startAll;
-
-            # Wait for networking to be configured
-            $client1->waitForUnit("network-interfaces.target");
-            $client1->waitForUnit("network.target");
-            $client2->waitForUnit("network-interfaces.target");
-            $client2->waitForUnit("network.target");
-
-            # Print diagnostic information
-            $client1->succeed("ip addr >&2");
-            $client2->succeed("ip addr >&2");
-
-            # Test ipv6
-            $client1->waitUntilSucceeds("ping6 -c 1 fc00::1");
-            $client1->waitUntilSucceeds("ping6 -c 1 fc00::2");
-
-            $client2->waitUntilSucceeds("ping6 -c 1 fc00::1");
-            $client2->waitUntilSucceeds("ping6 -c 1 fc00::2");
-          '';
       };
-      vlan = let
-        node = address: { config, pkgs, ... }: with pkgs.lib; {
-          #virtualisation.vlans = [ 1 ];
-          networking = {
-            useNetworkd = networkd;
-            firewall.allowPing = true;
-            useDHCP = false;
-            vlans.vlan = {
-              id = 1;
-              interface = "eth0";
-            };
-            interfaces.eth0.ip4 = mkOverride 0 [ ];
-            interfaces.eth1.ip4 = mkOverride 0 [ ];
-            interfaces.vlan.ip4 = mkOverride 0
-              [ { inherit address; prefixLength = 24; } ];
+    in {
+      name = "Sit";
+      nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; };
+      nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; };
+      testScript = { nodes, ... }:
+        ''
+          startAll;
+
+          # Wait for networking to be configured
+          $client1->waitForUnit("network-interfaces.target");
+          $client1->waitForUnit("network.target");
+          $client2->waitForUnit("network-interfaces.target");
+          $client2->waitForUnit("network.target");
+
+          # Print diagnostic information
+          $client1->succeed("ip addr >&2");
+          $client2->succeed("ip addr >&2");
+
+          # Test ipv6
+          $client1->waitUntilSucceeds("ping6 -c 1 fc00::1");
+          $client1->waitUntilSucceeds("ping6 -c 1 fc00::2");
+
+          $client2->waitUntilSucceeds("ping6 -c 1 fc00::1");
+          $client2->waitUntilSucceeds("ping6 -c 1 fc00::2");
+        '';
+    };
+    vlan = let
+      node = address: { config, pkgs, ... }: with pkgs.lib; {
+        #virtualisation.vlans = [ 1 ];
+        networking = {
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          useDHCP = false;
+          vlans.vlan = {
+            id = 1;
+            interface = "eth0";
           };
+          interfaces.eth0.ip4 = mkOverride 0 [ ];
+          interfaces.eth1.ip4 = mkOverride 0 [ ];
+          interfaces.vlan.ip4 = mkOverride 0
+            [ { inherit address; prefixLength = 24; } ];
         };
-      in {
-        name = "vlan";
-        nodes.client1 = node "192.168.1.1";
-        nodes.client2 = node "192.168.1.2";
-        testScript = { nodes, ... }:
-          ''
-            startAll;
-
-            # Wait for networking to be configured
-            $client1->waitForUnit("network-interfaces.target");
-            $client1->waitForUnit("network.target");
-            $client2->waitForUnit("network-interfaces.target");
-            $client2->waitForUnit("network.target");
-
-            # Test vlan is setup
-            $client1->succeed("ip addr show dev vlan >&2");
-            $client2->succeed("ip addr show dev vlan >&2");
-          '';
       };
+    in {
+      name = "vlan";
+      nodes.client1 = node "192.168.1.1";
+      nodes.client2 = node "192.168.1.2";
+      testScript = { nodes, ... }:
+        ''
+          startAll;
+
+          # Wait for networking to be configured
+          $client1->waitForUnit("network-interfaces.target");
+          $client1->waitForUnit("network.target");
+          $client2->waitForUnit("network-interfaces.target");
+          $client2->waitForUnit("network.target");
+
+          # Test vlan is setup
+          $client1->succeed("ip addr show dev vlan >&2");
+          $client2->succeed("ip addr show dev vlan >&2");
+        '';
     };
-    case = testCases.${test};
-  in case // {
-    name = "${case.name}-Networking-${if networkd then "Networkd" else "Scripted"}";
-    meta = with pkgs.stdenv.lib.maintainers; {
-      maintainers = [ wkennington ];
-    };
-  })
+  };
+
+in mapAttrs (const (attrs: makeTest (attrs // {
+  name = "${attrs.name}-Networking-${if networkd then "Networkd" else "Scripted"}";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ wkennington ];
+  };
+}))) testCases
diff --git a/nixos/tests/nixos-pin-version.nix b/nixos/tests/nixos-pin-version.nix
deleted file mode 100644
index 91fba2e759d..00000000000
--- a/nixos/tests/nixos-pin-version.nix
+++ /dev/null
@@ -1,57 +0,0 @@
-{ system ? builtins.currentSystem }:
-
-with import ../lib/testing.nix { inherit system; };
-let
-in
-
-pkgs.stdenv.mkDerivation rec {
-  name = "nixos-pin-version";
-  src = ../..;
-  buildInputs = with pkgs; [ nix gnugrep ];
-
-    withoutPath = pkgs.writeText "configuration.nix" ''
-    {
-      nixos.extraModules = [ ({lib, ...}: { system.nixosRevision = lib.mkForce "ABCDEF"; }) ];
-    }
-  '';
-
-  withPath = pkgs.writeText "configuration.nix" ''
-    {
-      nixos.path = ${src}/nixos ;
-      nixos.extraModules = [ ({lib, ...}: { system.nixosRevision = lib.mkForce "ABCDEF"; }) ];
-    }
-  '';
-
-  phases = "buildPhase";
-  buildPhase = ''
-    datadir="${pkgs.nix}/share"
-    export TEST_ROOT=$(pwd)/test-tmp
-    export NIX_STORE_DIR=$TEST_ROOT/store
-    export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
-    export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
-    export NIX_STATE_DIR=$TEST_ROOT/var/nix
-    export NIX_DB_DIR=$TEST_ROOT/db
-    export NIX_CONF_DIR=$TEST_ROOT/etc
-    export NIX_MANIFESTS_DIR=$TEST_ROOT/var/nix/manifests
-    export NIX_BUILD_HOOK=
-    export PAGER=cat
-    cacheDir=$TEST_ROOT/binary-cache
-    nix-store --init
-
-    export NIX_PATH="nixpkgs=$src:nixos=$src/nixos:nixos-config=${withoutPath}" ;
-    if test $(nix-instantiate $src/nixos -A config.system.nixosRevision --eval-only) != '"ABCDEF"' ; then :;
-    else
-      echo "Unexpected re-entry without the nixos.path option defined.";
-      exit 1;
-    fi;
-
-    export NIX_PATH="nixpkgs=$src:nixos=$src/nixos:nixos-config=${withPath}" ;
-    if test $(nix-instantiate $src/nixos -A config.system.nixosRevision --eval-only) = '"ABCDEF"' ; then :;
-    else
-      echo "Expected a re-entry when the nixos.path option is defined.";
-      exit 1;
-    fi;
-
-    touch $out;
-  '';
-}
diff --git a/nixos/tests/printing.nix b/nixos/tests/printing.nix
index 02980cee2fb..10d69b446cd 100644
--- a/nixos/tests/printing.nix
+++ b/nixos/tests/printing.nix
@@ -78,7 +78,7 @@ import ./make-test.nix ({pkgs, ... }: {
               # (showing that the right filters have been applied).  Of
               # course, since there is no actual USB printer attached, the
               # file will stay in the queue forever.
-              $server->waitForFile("/var/spool/cups/d00001-001");
+              $server->waitForFile("/var/spool/cups/d*-001");
               $server->sleep(10);
               $server->succeed("lpq -a") =~ /$fn/ or die;
 
@@ -90,6 +90,9 @@ import ./make-test.nix ({pkgs, ... }: {
               Machine::retry sub {
                 return 1 if $server->succeed("lpq -a") =~ /no entries/;
               };
+              # The queue is empty already, so this should be safe.
+              # Otherwise, pairs of "c*"-"d*-001" files might persist.
+              $server->execute("rm /var/spool/cups/*");
           };
       }
     '';
diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix
index 01fcd15fd8b..da4c0bddc34 100644
--- a/nixos/tests/virtualbox.nix
+++ b/nixos/tests/virtualbox.nix
@@ -1,7 +1,9 @@
-{ debug ? false, ... } @ args:
+{ system ? builtins.currentSystem, debug ? false }:
 
-import ./make-test.nix ({ pkgs, ... }: with pkgs.lib; let
+with import ../lib/testing.nix { inherit system; };
+with pkgs.lib;
 
+let
   testVMConfig = vmName: attrs: { config, pkgs, ... }: let
     guestAdditions = pkgs.linuxPackages.virtualboxGuestAdditions;
 
@@ -314,138 +316,140 @@ import ./make-test.nix ({ pkgs, ... }: with pkgs.lib; let
     test2.vmScript = dhcpScript;
   };
 
-in {
-  name = "virtualbox";
-  meta = with pkgs.stdenv.lib.maintainers; {
-    maintainers = [ aszlig wkennington ];
-  };
+  mkVBoxTest = name: testScript: makeTest {
+    name = "virtualbox-${name}";
+
+    machine = { lib, config, ... }: {
+      imports = let
+        mkVMConf = name: val: val.machine // { key = "${name}-config"; };
+        vmConfigs = mapAttrsToList mkVMConf vboxVMs;
+      in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs;
+      virtualisation.memorySize = 2048;
+      virtualisation.virtualbox.host.enable = true;
+      users.extraUsers.alice.extraGroups = let
+        inherit (config.virtualisation.virtualbox.host) enableHardening;
+      in lib.mkIf enableHardening (lib.singleton "vboxusers");
+    };
 
-  machine = { pkgs, lib, config, ... }: {
-    imports = let
-      mkVMConf = name: val: val.machine // { key = "${name}-config"; };
-      vmConfigs = mapAttrsToList mkVMConf vboxVMs;
-    in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs;
-    virtualisation.memorySize = 2048;
-    virtualisation.virtualbox.host.enable = true;
-    users.extraUsers.alice.extraGroups = let
-      inherit (config.virtualisation.virtualbox.host) enableHardening;
-    in lib.mkIf enableHardening (lib.singleton "vboxusers");
-  };
+    testScript = ''
+      sub ru ($) {
+        my $esc = $_[0] =~ s/'/'\\${"'"}'/gr;
+        return "su - alice -c '$esc'";
+      }
 
-  testScript = ''
-    sub ru ($) {
-      my $esc = $_[0] =~ s/'/'\\${"'"}'/gr;
-      return "su - alice -c '$esc'";
-    }
+      sub vbm {
+        $machine->succeed(ru("VBoxManage ".$_[0]));
+      };
 
-    sub vbm {
-      $machine->succeed(ru("VBoxManage ".$_[0]));
-    };
+      sub removeUUIDs {
+        return join("\n", grep { $_ !~ /^UUID:/ } split(/\n/, $_[0]))."\n";
+      }
 
-    ${concatStrings (mapAttrsToList (_: getAttr "testSubs") vboxVMs)}
+      ${concatStrings (mapAttrsToList (_: getAttr "testSubs") vboxVMs)}
 
-    $machine->waitForX;
+      $machine->waitForX;
 
-    ${mkLog "$HOME/.config/VirtualBox/VBoxSVC.log" "HOST-SVC"}
+      ${mkLog "$HOME/.config/VirtualBox/VBoxSVC.log" "HOST-SVC"}
 
-    createVM_simple;
+      ${testScript}
+    '';
 
-    subtest "simple-gui", sub {
-      $machine->succeed(ru "VirtualBox &");
-      $machine->waitForWindow(qr/Oracle VM VirtualBox Manager/);
-      $machine->sleep(5);
-      $machine->screenshot("gui_manager_started");
-      $machine->sendKeys("ret");
-      $machine->screenshot("gui_manager_sent_startup");
-      waitForStartup_simple (sub {
-        $machine->sendKeys("ret");
-      });
-      $machine->screenshot("gui_started");
-      waitForVMBoot_simple;
-      $machine->screenshot("gui_booted");
-      shutdownVM_simple;
-      $machine->sleep(5);
-      $machine->screenshot("gui_stopped");
-      $machine->sendKeys("ctrl-q");
-      $machine->sleep(5);
-      $machine->screenshot("gui_manager_stopped");
+    meta = with pkgs.stdenv.lib.maintainers; {
+      maintainers = [ aszlig wkennington ];
     };
+  };
 
-    cleanup_simple;
+in mapAttrs mkVBoxTest {
+  simple-gui = ''
+    createVM_simple;
+    $machine->succeed(ru "VirtualBox &");
+    $machine->waitForWindow(qr/Oracle VM VirtualBox Manager/);
+    $machine->sleep(5);
+    $machine->screenshot("gui_manager_started");
+    $machine->sendKeys("ret");
+    $machine->screenshot("gui_manager_sent_startup");
+    waitForStartup_simple (sub {
+      $machine->sendKeys("ret");
+    });
+    $machine->screenshot("gui_started");
+    waitForVMBoot_simple;
+    $machine->screenshot("gui_booted");
+    shutdownVM_simple;
+    $machine->sleep(5);
+    $machine->screenshot("gui_stopped");
+    $machine->sendKeys("ctrl-q");
+    $machine->sleep(5);
+    $machine->screenshot("gui_manager_stopped");
+  '';
 
-    subtest "simple-cli", sub {
-      vbm("startvm simple");
-      waitForStartup_simple;
-      $machine->screenshot("cli_started");
-      waitForVMBoot_simple;
-      $machine->screenshot("cli_booted");
-      shutdownVM_simple;
-    };
+  simple-cli = ''
+    createVM_simple;
+    vbm("startvm simple");
+    waitForStartup_simple;
+    $machine->screenshot("cli_started");
+    waitForVMBoot_simple;
+    $machine->screenshot("cli_booted");
 
-    subtest "privilege-escalation", sub {
+    $machine->nest("Checking for privilege escalation", sub {
       $machine->fail("test -e '/root/VirtualBox VMs'");
       $machine->fail("test -e '/root/.config/VirtualBox'");
       $machine->succeed("test -e '/home/alice/VirtualBox VMs'");
-    };
-
-    destroyVM_simple;
+    });
 
-    sub removeUUIDs {
-      return join("\n", grep { $_ !~ /^UUID:/ } split(/\n/, $_[0]))."\n";
-    }
+    shutdownVM_simple;
+  '';
 
-    subtest "host-usb-permissions", sub {
-      my $userUSB = removeUUIDs vbm("list usbhost");
-      print STDERR $userUSB;
-      my $rootUSB = removeUUIDs $machine->succeed("VBoxManage list usbhost");
-      print STDERR $rootUSB;
+  host-usb-permissions = ''
+    my $userUSB = removeUUIDs vbm("list usbhost");
+    print STDERR $userUSB;
+    my $rootUSB = removeUUIDs $machine->succeed("VBoxManage list usbhost");
+    print STDERR $rootUSB;
 
-      die "USB host devices differ for root and normal user"
-        if $userUSB ne $rootUSB;
-      die "No USB host devices found" if $userUSB =~ /<none>/;
-    };
+    die "USB host devices differ for root and normal user"
+      if $userUSB ne $rootUSB;
+    die "No USB host devices found" if $userUSB =~ /<none>/;
+  '';
 
-    subtest "systemd-detect-virt", sub {
-      createVM_detectvirt;
-      vbm("startvm detectvirt");
-      waitForStartup_detectvirt;
-      waitForVMBoot_detectvirt;
-      shutdownVM_detectvirt;
-      my $result = $machine->succeed("cat '$detectvirt_sharepath/result'");
-      chomp $result;
-      destroyVM_detectvirt;
-      die "systemd-detect-virt returned \"$result\" instead of \"oracle\""
-        if $result ne "oracle";
-    };
+  systemd-detect-virt = ''
+    createVM_detectvirt;
+    vbm("startvm detectvirt");
+    waitForStartup_detectvirt;
+    waitForVMBoot_detectvirt;
+    shutdownVM_detectvirt;
+    my $result = $machine->succeed("cat '$detectvirt_sharepath/result'");
+    chomp $result;
+    destroyVM_detectvirt;
+    die "systemd-detect-virt returned \"$result\" instead of \"oracle\""
+      if $result ne "oracle";
+  '';
 
-    subtest "net-hostonlyif", sub {
-      createVM_test1;
-      createVM_test2;
+  net-hostonlyif = ''
+    createVM_test1;
+    createVM_test2;
 
-      vbm("startvm test1");
-      waitForStartup_test1;
-      waitForVMBoot_test1;
+    vbm("startvm test1");
+    waitForStartup_test1;
+    waitForVMBoot_test1;
 
-      vbm("startvm test2");
-      waitForStartup_test2;
-      waitForVMBoot_test2;
+    vbm("startvm test2");
+    waitForStartup_test2;
+    waitForVMBoot_test2;
 
-      $machine->screenshot("net_booted");
+    $machine->screenshot("net_booted");
 
-      my $test1IP = waitForIP_test1 1;
-      my $test2IP = waitForIP_test2 1;
+    my $test1IP = waitForIP_test1 1;
+    my $test2IP = waitForIP_test2 1;
 
-      $machine->succeed("echo '$test2IP' | netcat -c '$test1IP' 1234");
-      $machine->succeed("echo '$test1IP' | netcat -c '$test2IP' 1234");
+    $machine->succeed("echo '$test2IP' | netcat -c '$test1IP' 1234");
+    $machine->succeed("echo '$test1IP' | netcat -c '$test2IP' 1234");
 
-      $machine->waitUntilSucceeds("netcat -c '$test1IP' 5678 >&2");
-      $machine->waitUntilSucceeds("netcat -c '$test2IP' 5678 >&2");
+    $machine->waitUntilSucceeds("netcat -c '$test1IP' 5678 >&2");
+    $machine->waitUntilSucceeds("netcat -c '$test2IP' 5678 >&2");
 
-      shutdownVM_test1;
-      shutdownVM_test2;
+    shutdownVM_test1;
+    shutdownVM_test2;
 
-      destroyVM_test1;
-      destroyVM_test2;
-    };
+    destroyVM_test1;
+    destroyVM_test2;
   '';
-}) args
+}