about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/administration/container-networking.xml8
-rw-r--r--nixos/doc/manual/configuration/customizing-packages.xml27
-rw-r--r--nixos/doc/manual/development/option-declarations.xml88
-rw-r--r--nixos/doc/manual/development/option-types.xml116
-rw-r--r--nixos/doc/manual/installation/obtaining.xml2
-rw-r--r--nixos/doc/manual/release-notes/rl-1703.xml14
-rwxr-xr-xnixos/maintainers/scripts/ec2/create-amis.sh6
-rw-r--r--nixos/modules/config/debug-info.nix6
-rw-r--r--nixos/modules/config/fonts/fontconfig.nix12
-rw-r--r--nixos/modules/config/shells-environment.nix2
-rw-r--r--nixos/modules/config/system-environment.nix2
-rw-r--r--nixos/modules/config/system-path.nix1
-rw-r--r--nixos/modules/hardware/opengl.nix6
-rw-r--r--nixos/modules/hardware/video/amdgpu-pro.nix2
-rw-r--r--nixos/modules/hardware/video/bumblebee.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix96
-rw-r--r--nixos/modules/installer/tools/nixos-option.sh2
-rw-r--r--nixos/modules/installer/virtualbox-demo.nix2
-rw-r--r--nixos/modules/misc/ids.nix10
-rw-r--r--nixos/modules/module-list.nix5
-rw-r--r--nixos/modules/rename.nix8
-rw-r--r--nixos/modules/security/duosec.nix12
-rw-r--r--nixos/modules/security/grsecurity.nix33
-rw-r--r--nixos/modules/security/grsecurity.xml8
-rw-r--r--nixos/modules/services/backup/crashplan.nix2
-rw-r--r--nixos/modules/services/backup/tarsnap.nix156
-rw-r--r--nixos/modules/services/cluster/fleet.nix2
-rw-r--r--nixos/modules/services/cluster/kubernetes.nix2
-rw-r--r--nixos/modules/services/cluster/panamax.nix2
-rw-r--r--nixos/modules/services/databases/riak-cs.nix202
-rw-r--r--nixos/modules/services/databases/riak.nix2
-rw-r--r--nixos/modules/services/databases/stanchion.nix212
-rw-r--r--nixos/modules/services/editors/emacs.xml6
-rw-r--r--nixos/modules/services/games/ghost-one.nix3
-rw-r--r--nixos/modules/services/hardware/sane.nix111
-rw-r--r--nixos/modules/services/logging/logcheck.nix4
-rw-r--r--nixos/modules/services/misc/errbot.nix4
-rw-r--r--nixos/modules/services/misc/leaps.nix62
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix4
-rw-r--r--nixos/modules/services/misc/parsoid.nix40
-rw-r--r--nixos/modules/services/misc/taskserver/default.nix4
-rw-r--r--nixos/modules/services/network-filesystems/ipfs.nix111
-rw-r--r--nixos/modules/services/network-filesystems/tahoe.nix52
-rw-r--r--nixos/modules/services/network-filesystems/yandex-disk.nix13
-rw-r--r--nixos/modules/services/networking/bitlbee.nix7
-rw-r--r--nixos/modules/services/networking/cjdns.nix56
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix122
-rw-r--r--nixos/modules/services/networking/hostapd.nix5
-rw-r--r--nixos/modules/services/networking/i2pd.nix230
-rw-r--r--nixos/modules/services/networking/nntp-proxy.nix4
-rw-r--r--nixos/modules/services/networking/nsd.nix8
-rw-r--r--nixos/modules/services/networking/quassel.nix11
-rw-r--r--nixos/modules/services/networking/skydns.nix2
-rw-r--r--nixos/modules/services/networking/smokeping.nix2
-rw-r--r--nixos/modules/services/networking/tinc.nix2
-rw-r--r--nixos/modules/services/search/hound.nix2
-rw-r--r--nixos/modules/services/security/clamav.nix95
-rw-r--r--nixos/modules/services/web-servers/fcgiwrap.nix2
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix24
-rw-r--r--nixos/modules/services/x11/desktop-managers/lumina.nix52
-rw-r--r--nixos/modules/services/x11/desktop-managers/lxqt.nix1
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix8
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm-unstable.nix48
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm.nix83
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix1
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix2
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix3
-rw-r--r--nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix7
-rw-r--r--nixos/modules/tasks/network-interfaces.nix19
-rw-r--r--nixos/modules/virtualisation/grow-partition.nix2
-rw-r--r--nixos/modules/virtualisation/libvirtd.nix2
-rw-r--r--nixos/modules/virtualisation/vmware-guest.nix10
-rw-r--r--nixos/release.nix1
-rw-r--r--nixos/tests/chromium.nix2
-rw-r--r--nixos/tests/cjdns.nix2
-rw-r--r--nixos/tests/dnscrypt-proxy.nix2
-rw-r--r--nixos/tests/leaps.nix29
79 files changed, 1754 insertions, 561 deletions
diff --git a/nixos/doc/manual/administration/container-networking.xml b/nixos/doc/manual/administration/container-networking.xml
index 1b1576d3babe..d89d262eff4e 100644
--- a/nixos/doc/manual/administration/container-networking.xml
+++ b/nixos/doc/manual/administration/container-networking.xml
@@ -47,4 +47,12 @@ where <literal>eth0</literal> should be replaced with the desired
 external interface. Note that <literal>ve-+</literal> is a wildcard
 that matches all container interfaces.</para>
 
+<para>If you are using Network Manager, you need to explicitly prevent
+it from managing container interfaces:
+
+<programlisting>
+networking.networkmanager.unmanaged = [ "interface-name:ve-*" ];
+</programlisting>
+</para>
+
 </section>
diff --git a/nixos/doc/manual/configuration/customizing-packages.xml b/nixos/doc/manual/configuration/customizing-packages.xml
index 6ee7a95dc6fa..8aa01fb57a09 100644
--- a/nixos/doc/manual/configuration/customizing-packages.xml
+++ b/nixos/doc/manual/configuration/customizing-packages.xml
@@ -42,29 +42,30 @@ construction, so without them,
 elements.)</para>
 
 <para>Even greater customisation is possible using the function
-<varname>overrideDerivation</varname>.  While the
+<varname>overrideAttrs</varname>.  While the
 <varname>override</varname> mechanism above overrides the arguments of
-a package function, <varname>overrideDerivation</varname> allows
-changing the <emphasis>result</emphasis> of the function.  This
-permits changing any aspect of the package, such as the source code.
+a package function, <varname>overrideAttrs</varname> allows
+changing the <emphasis>attributes</emphasis> passed to <literal>mkDerivation</literal>.
+This permits changing any aspect of the package, such as the source code.
 For instance, if you want to override the source code of Emacs, you
 can say:
 
 <programlisting>
-environment.systemPackages =
-  [ (pkgs.lib.overrideDerivation pkgs.emacs (attrs: {
-      name = "emacs-25.0-pre";
-      src = /path/to/my/emacs/tree;
-    }))
-  ];
+environment.systemPackages = [
+  (pkgs.emacs.overrideAttrs (oldAttrs: {
+    name = "emacs-25.0-pre";
+    src = /path/to/my/emacs/tree;
+  }))
+];
 </programlisting>
 
-Here, <varname>overrideDerivation</varname> takes the Nix derivation
+Here, <varname>overrideAttrs</varname> takes the Nix derivation
 specified by <varname>pkgs.emacs</varname> and produces a new
 derivation in which the original’s <literal>name</literal> and
 <literal>src</literal> attribute have been replaced by the given
-values.  The original attributes are accessible via
-<varname>attrs</varname>.</para>
+values by re-calling <literal>stdenv.mkDerivation</literal>.
+The original attributes are accessible via the function argument,
+which is conventionally named <varname>oldAttrs</varname>.</para>
 
 <para>The overrides shown above are not global.  They do not affect
 the original package; other packages in Nixpkgs continue to depend on
diff --git a/nixos/doc/manual/development/option-declarations.xml b/nixos/doc/manual/development/option-declarations.xml
index 7be5e9d51d46..ce432a7fa6ca 100644
--- a/nixos/doc/manual/development/option-declarations.xml
+++ b/nixos/doc/manual/development/option-declarations.xml
@@ -65,4 +65,92 @@ options = {
 
 </para>
 
+<section xml:id="sec-option-declarations-eot"><title>Extensible Option 
+    Types</title>
+
+  <para>Extensible option types is a feature that allow to extend certain types 
+    declaration through multiple module files.
+    This feature only work with a restricted set of types, namely 
+    <literal>enum</literal> and <literal>submodules</literal> and any composed
+    forms of them.</para>
+
+  <para>Extensible option types can be used for <literal>enum</literal> options 
+    that affects multiple modules, or as an alternative to related 
+    <literal>enable</literal> options.</para>
+
+  <para>As an example, we will take the case of display managers. There is a
+    central display manager module for generic display manager options and a
+    module file per display manager backend (slim, kdm, gdm ...).
+  </para>
+
+  <para>There are two approach to this module structure:
+
+  <itemizedlist>
+    <listitem><para>Managing the display managers independently by adding an
+        enable option to every display manager module backend. (NixOS)</para>
+    </listitem>
+    <listitem><para>Managing the display managers in the central module by
+        adding an option to select which display manager backend to use.</para>
+    </listitem>
+  </itemizedlist>
+  </para>
+
+  <para>Both approachs have problems.</para>
+    
+  <para>Making backends independent can quickly become hard to manage. For
+    display managers, there can be only one enabled at a time, but the type
+    system can not enforce this restriction as there is no relation between
+    each backend <literal>enable</literal> option. As a result, this restriction
+    has to be done explicitely by adding assertions in each display manager
+    backend module.</para>
+
+  <para>On the other hand, managing the display managers backends in the
+    central module will require to change the central module option every time
+    a new backend is added or removed.</para>
+
+  <para>By using extensible option types, it is possible to create a placeholder 
+    option in the central module (<xref linkend='ex-option-declaration-eot-service' 
+      />), and to extend it in each backend module (<xref 
+      linkend='ex-option-declaration-eot-backend-slim' />, <xref 
+      linkend='ex-option-declaration-eot-backend-kdm' />).</para>
+ 
+  <para>As a result, <literal>displayManager.enable</literal> option values can
+  be added without changing the main service module file and the type system
+  automatically enforce that there can only be a single display manager
+  enabled.</para>
+
+<example xml:id='ex-option-declaration-eot-service'><title>Extensible type 
+    placeholder in the service module</title>
+<screen>
+services.xserver.displayManager.enable = mkOption {
+  description = "Display manager to use";
+  type = with types; nullOr (enum [ ]);
+};</screen></example>
+
+<example xml:id='ex-option-declaration-eot-backend-slim'><title>Extending 
+    <literal>services.xserver.displayManager.enable</literal> in the 
+    <literal>slim</literal> module</title>
+<screen>
+services.xserver.displayManager.enable = mkOption {
+  type = with types; nullOr (enum [ "slim" ]);
+};</screen></example>
+
+<example xml:id='ex-option-declaration-eot-backend-kdm'><title>Extending 
+    <literal>services.foo.backend</literal> in the <literal>kdm</literal> 
+    module</title>
+<screen>
+services.xserver.displayManager.enable = mkOption {
+  type = with types; nullOr (enum [ "kdm" ]);
+};</screen></example>
+
+<para>The placeholder declaration is a standard <literal>mkOption</literal> 
+  declaration, but it is important that extensible option declarations only use 
+  the <literal>type</literal> argument.</para>
+
+<para>Extensible option types work with any of the composed variants of 
+  <literal>enum</literal> such as 
+  <literal>with types; nullOr (enum [ "foo" "bar" ])</literal> 
+  or <literal>with types; listOf (enum [ "foo" "bar" ])</literal>.</para>
+
+</section>
 </section>
diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml
index 8871b02cebf1..8e6ac53ad480 100644
--- a/nixos/doc/manual/development/option-types.xml
+++ b/nixos/doc/manual/development/option-types.xml
@@ -62,23 +62,45 @@
     <listitem><para>A string. Multiple definitions are concatenated with a 
         collon <literal>":"</literal>.</para></listitem>
   </varlistentry>
+</variablelist>
+
+ </section>
+
+ <section><title>Value Types</title>
+
+   <para>Value types are type that take a value parameter. The only value type 
+     in the library is <literal>enum</literal>.</para>
+
+<variablelist>
   <varlistentry>
-    <term><varname>types.separatedString</varname> 
+    <term><varname>types.enum</varname> <replaceable>l</replaceable></term>
+    <listitem><para>One element of the list <replaceable>l</replaceable>, e.g. 
+        <literal>types.enum [ "left" "right" ]</literal>. Multiple definitions 
+        cannot be merged.</para></listitem>
+  </varlistentry>
+  <varlistentry>
+    <term><varname>types.separatedString</varname>
       <replaceable>sep</replaceable></term>
-    <listitem><para>A string with a custom separator 
-        <replaceable>sep</replaceable>, e.g. <literal>types.separatedString 
+    <listitem><para>A string with a custom separator
+        <replaceable>sep</replaceable>, e.g. <literal>types.separatedString
           "|"</literal>.</para></listitem>
   </varlistentry>
+  <varlistentry>
+    <term><varname>types.submodule</varname> <replaceable>o</replaceable></term>
+    <listitem><para>A set of sub options <replaceable>o</replaceable>.
+        <replaceable>o</replaceable> can be an attribute set or a function
+        returning an attribute set. Submodules are used in composed types to
+        create modular options. Submodule are detailed in <xref
+          linkend='section-option-types-submodule' />.</para></listitem>
+  </varlistentry>
 </variablelist>
-
  </section>
 
  <section><title>Composed Types</title>
 
-   <para>Composed types allow to create complex types by taking another type(s) 
-     or value(s) as parameter(s).
-     It is possible to compose types multiple times, e.g. <literal>with types; 
-       nullOr (enum [ "left" "right" ])</literal>.</para>
+   <para>Composed types are types that take a type as parameter. <literal>listOf 
+       int</literal> and <literal>either int str</literal> are examples of 
+     composed types.</para>
 
 <variablelist>
   <varlistentry>
@@ -100,12 +122,6 @@
         value.</para></listitem>
   </varlistentry>
   <varlistentry>
-    <term><varname>types.loeOf</varname> <replaceable>t</replaceable></term>
-    <listitem><para>A list or an element of <replaceable>t</replaceable> type. 
-        Multiple definitions are merged according to the 
-        values.</para></listitem>
-  </varlistentry>
-  <varlistentry>
     <term><varname>types.nullOr</varname> <replaceable>t</replaceable></term>
     <listitem><para><literal>null</literal> or type 
         <replaceable>t</replaceable>. Multiple definitions are merged according 
@@ -118,12 +134,6 @@
         once.</para></listitem>
   </varlistentry>
   <varlistentry>
-    <term><varname>types.enum</varname> <replaceable>l</replaceable></term>
-    <listitem><para>One element of the list <replaceable>l</replaceable>, e.g. 
-        <literal>types.enum [ "left" "right" ]</literal>. Multiple definitions 
-        cannot be merged</para></listitem>
-  </varlistentry>
-  <varlistentry>
     <term><varname>types.either</varname> <replaceable>t1</replaceable> 
       <replaceable>t2</replaceable></term>
     <listitem><para>Type <replaceable>t1</replaceable> or type 
@@ -131,14 +141,6 @@
           str</literal>. Multiple definitions cannot be 
         merged.</para></listitem>
   </varlistentry>
-  <varlistentry>
-    <term><varname>types.submodule</varname> <replaceable>o</replaceable></term>
-    <listitem><para>A set of sub options <replaceable>o</replaceable>. 
-        <replaceable>o</replaceable> can be an attribute set or a function 
-        returning an attribute set. Submodules are used in composed types to 
-        create modular options. Submodule are detailed in <xref 
-          linkend='section-option-types-submodule' />.</para></listitem>
-  </varlistentry>
 </variablelist>
 
 </section>
@@ -197,7 +199,6 @@ options.mod = mkOption {
   type = with types; listOf (submodule modOptions);
 };</screen></example>
 
-
 <section><title>Composed with <literal>listOf</literal></title>
 
   <para>When composed with <literal>listOf</literal>, submodule allows multiple 
@@ -323,9 +324,13 @@ code before creating a new type.</para>
 <variablelist>
   <varlistentry>
     <term><varname>name</varname></term>
-    <listitem><para>A string representation of the type function name, name 
-        usually changes accordingly parameters passed to 
-        types.</para></listitem>
+    <listitem><para>A string representation of the type function 
+        name.</para></listitem>
+  </varlistentry>
+  <varlistentry>
+    <term><varname>definition</varname></term>
+    <listitem><para>Description of the type used in documentation. Give 
+        information of the type and any of its arguments.</para></listitem>
   </varlistentry>
   <varlistentry>
     <term><varname>check</varname></term>
@@ -388,6 +393,53 @@ code before creating a new type.</para>
         type parameter, this function should be defined as <literal>m: 
           composedType (elemType.substSubModules m)</literal>.</para></listitem>
   </varlistentry>
+  <varlistentry>
+    <term><varname>typeMerge</varname></term>
+    <listitem><para>A function to merge multiple type declarations. Takes the 
+        type to merge <literal>functor</literal> as parameter. A 
+        <literal>null</literal> return value means that type cannot be 
+        merged.</para>
+      <variablelist>
+        <varlistentry>
+          <term><replaceable>f</replaceable></term>
+          <listitem><para>The type to merge  
+              <literal>functor</literal>.</para></listitem>
+        </varlistentry>
+      </variablelist>
+      <para>Note: There is a generic <literal>defaultTypeMerge</literal> that 
+        work with most of value and composed types.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term><varname>functor</varname></term>
+    <listitem><para>An attribute set representing the type. It is used for type 
+        operations and has the following keys:</para>
+      <variablelist>
+        <varlistentry>
+          <term><varname>type</varname></term>
+          <listitem><para>The type function.</para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>wrapped</varname></term>
+          <listitem><para>Holds the type parameter for composed types.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>payload</varname></term>
+          <listitem><para>Holds the value parameter for value types. 
+              The types that have a <literal>payload</literal> are the
+              <literal>enum</literal>, <literal>separatedString</literal> and
+              <literal>submodule</literal> types.</para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>binOp</varname></term>
+          <listitem><para>A binary operation that can merge the payloads of two 
+              same types. Defined as a function that take two payloads as 
+              parameters and return the payloads merged.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </listitem>
+  </varlistentry>
 </variablelist>
 
 </section>
diff --git a/nixos/doc/manual/installation/obtaining.xml b/nixos/doc/manual/installation/obtaining.xml
index f6e8b218e2b3..20a4838be880 100644
--- a/nixos/doc/manual/installation/obtaining.xml
+++ b/nixos/doc/manual/installation/obtaining.xml
@@ -32,7 +32,7 @@ running NixOS system through several other means:
   <listitem>
     <para>Using AMIs for Amazon’s EC2.  To find one for your region
     and instance type, please refer to the <link
-    xlink:href="https://github.com/NixOS/nixops/blob/master/nix/ec2-amis.nix">list
+    xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/ec2-amis.nix">list
     of most recent AMIs</link>.</para>
   </listitem>
   <listitem>
diff --git a/nixos/doc/manual/release-notes/rl-1703.xml b/nixos/doc/manual/release-notes/rl-1703.xml
index efff8b895a1a..a133630e1464 100644
--- a/nixos/doc/manual/release-notes/rl-1703.xml
+++ b/nixos/doc/manual/release-notes/rl-1703.xml
@@ -68,6 +68,15 @@ following incompatible changes:</para>
     that may be in /etc.
     </para>
   </listitem>
+
+  <listitem>
+    <para>
+      Parsoid service now uses YAML configuration format.
+     <literal>service.parsoid.interwikis</literal> is now called
+     <literal>service.parsoid.wikis</literal> and is a list of either API URLs
+     or attribute sets as specified in parsoid's documentation.
+    </para>
+  </listitem>
 </itemizedlist>
 
 
@@ -75,7 +84,10 @@ following incompatible changes:</para>
 
 <itemizedlist>
   <listitem>
-    <para></para>
+    <para>Module type system have a new extensible option types feature that
+      allow to extend certain types, such as enum, through multiple option
+      declarations of the same option across multiple modules.
+    </para>
   </listitem>
 </itemizedlist>
 
diff --git a/nixos/maintainers/scripts/ec2/create-amis.sh b/nixos/maintainers/scripts/ec2/create-amis.sh
index e26caa191643..8b7db7b30a64 100755
--- a/nixos/maintainers/scripts/ec2/create-amis.sh
+++ b/nixos/maintainers/scripts/ec2/create-amis.sh
@@ -1,4 +1,8 @@
-#! /bin/sh -e
+#!/usr/bin/env nix-shell
+#! nix-shell -i bash -p qemu awscli ec2_ami_tools jq
+
+# To start with do: nix-shell -p awscli --run "aws configure"
+
 
 set -o pipefail
 #set -x
diff --git a/nixos/modules/config/debug-info.nix b/nixos/modules/config/debug-info.nix
index 671a59f52f6d..49991d22a933 100644
--- a/nixos/modules/config/debug-info.nix
+++ b/nixos/modules/config/debug-info.nix
@@ -17,12 +17,10 @@ with lib;
         where tools such as <command>gdb</command> can find them.
         If you need debug symbols for a package that doesn't
         provide them by default, you can enable them as follows:
-        <!-- FIXME: ugly, see #10721 -->
         <programlisting>
         nixpkgs.config.packageOverrides = pkgs: {
-          hello = pkgs.lib.overrideDerivation pkgs.hello (attrs: {
-            outputs = attrs.outputs or ["out"] ++ ["debug"];
-            buildInputs = attrs.buildInputs ++ [&lt;nixpkgs/pkgs/build-support/setup-hooks/separate-debug-info.sh>];
+          hello = pkgs.hello.overrideAttrs (oldAttrs: {
+            separateDebugInfo = true;
           });
         };
         </programlisting>
diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
index 770c3a03f9d8..52ad1e714fb9 100644
--- a/nixos/modules/config/fonts/fontconfig.nix
+++ b/nixos/modules/config/fonts/fontconfig.nix
@@ -301,9 +301,7 @@ in
           };
 
           style = mkOption {
-            type = types.str // {
-              check = flip elem ["none" "slight" "medium" "full"];
-            };
+            type = types.enum ["none" "slight" "medium" "full"];
             default = "full";
             description = ''
               TrueType hinting style, one of <literal>none</literal>,
@@ -329,9 +327,7 @@ in
             default = "rgb";
             type = types.enum ["rgb" "bgr" "vrgb" "vbgr" "none"];
             description = ''
-              Subpixel order, one of <literal>none</literal>,
-              <literal>rgb</literal>, <literal>bgr</literal>,
-              <literal>vrgb</literal>, or <literal>vbgr</literal>.
+              Subpixel order.
             '';
           };
 
@@ -339,9 +335,7 @@ in
             default = "default";
             type = types.enum ["none" "default" "light" "legacy"];
             description = ''
-              FreeType LCD filter, one of <literal>none</literal>,
-              <literal>default</literal>, <literal>light</literal>, or
-              <literal>legacy</literal>.
+              FreeType LCD filter.
             '';
           };
 
diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix
index f458bc39adaa..8147fed39d09 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -41,7 +41,7 @@ in
         strings.  The latter is concatenated, interspersed with colon
         characters.
       '';
-      type = types.attrsOf (types.loeOf types.str);
+      type = with types; attrsOf (either str (listOf str));
       apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
     };
 
diff --git a/nixos/modules/config/system-environment.nix b/nixos/modules/config/system-environment.nix
index 3362400326d2..6011e354ece4 100644
--- a/nixos/modules/config/system-environment.nix
+++ b/nixos/modules/config/system-environment.nix
@@ -23,7 +23,7 @@ in
         strings.  The latter is concatenated, interspersed with colon
         characters.
       '';
-      type = types.attrsOf (types.loeOf types.str);
+      type = with types; attrsOf (either str (listOf str));
       apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
     };
 
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 775d0c39c4fa..3ac5f634c7a6 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -118,6 +118,7 @@ in
         "/share/terminfo"
         "/share/themes"
         "/share/vim-plugins"
+        "/share/vulkan"
       ];
 
     system.path = pkgs.buildEnv {
diff --git a/nixos/modules/hardware/opengl.nix b/nixos/modules/hardware/opengl.nix
index bef500e30c0b..c4fad9a66725 100644
--- a/nixos/modules/hardware/opengl.nix
+++ b/nixos/modules/hardware/opengl.nix
@@ -135,6 +135,12 @@ in
     environment.sessionVariables.LD_LIBRARY_PATH =
       [ "/run/opengl-driver/lib" "/run/opengl-driver-32/lib" ];
 
+    environment.extraInit = ''
+      export XDG_DATA_DIRS=$XDG_DATA_DIRS:/run/opengl-driver/share
+    '' + optionalString cfg.driSupport32Bit ''
+      export XDG_DATA_DIRS=$XDG_DATA_DIRS:/run/opengl-driver-32/share
+    '';
+
     hardware.opengl.package = mkDefault (makePackage pkgs);
     hardware.opengl.package32 = mkDefault (makePackage pkgs_i686);
 
diff --git a/nixos/modules/hardware/video/amdgpu-pro.nix b/nixos/modules/hardware/video/amdgpu-pro.nix
index 3723d7690dc6..979810abf90a 100644
--- a/nixos/modules/hardware/video/amdgpu-pro.nix
+++ b/nixos/modules/hardware/video/amdgpu-pro.nix
@@ -45,10 +45,8 @@ in
       "amd/amdapfxx.blb".source = package + "/etc/amd/amdapfxx.blb";
       "gbm/gbm.conf".source = package + "/etc/gbm/gbm.conf";
       "OpenCL/vendors/amdocl64.icd".source = package + "/etc/OpenCL/vendors/amdocl64.icd";
-      "vulkan/icd.d/amd_icd64.json".source = package + "/etc/vulkan/icd.d/amd_icd64.json";
     } // optionalAttrs opengl.driSupport32Bit {
       "OpenCL/vendors/amdocl32.icd".source = package32 + "/etc/OpenCL/vendors/amdocl32.icd";
-      "vulkan/icd.d/amd_icd32.json".source = package32 + "/etc/vulkan/icd.d/amd_icd32.json";
     };
 
   };
diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix
index 69db518ab21c..76d122ab2124 100644
--- a/nixos/modules/hardware/video/bumblebee.nix
+++ b/nixos/modules/hardware/video/bumblebee.nix
@@ -62,7 +62,7 @@ in
   };
 
   config = mkIf config.hardware.bumblebee.enable {
-    boot.blacklistedKernelModules = [ "nouveau" "nvidia" ];
+    boot.blacklistedKernelModules = [ "nvidia-drm" "nvidia" "nouveau" ];
     boot.kernelModules = [ "bbswitch" ];
     boot.extraModulePackages = [ kernel.bbswitch ] ++ optional useNvidia kernel.nvidia_x11;
 
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
index b5ee57d9e22e..c44dff3bb60d 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
@@ -1,20 +1,41 @@
 # This module defines a NixOS installation CD that contains X11 and
-# KDE 4.
+# KDE 5.
 
 { config, lib, pkgs, ... }:
 
 with lib;
 
 {
-  imports = [ ./installation-cd-base.nix ../../profiles/graphical.nix ];
+  imports = [ ./installation-cd-base.nix ];
 
-  # Provide wicd for easy wireless configuration.
-  #networking.wicd.enable = true;
+  services.xserver = {
+    enable = true;
+
+    # Automatically login as root.
+    displayManager.slim = {
+      enable = true;
+      defaultUser = "root";
+      autoLogin = true;
+    };
+
+    desktopManager.kde5 = {
+      enable = true;
+      enableQt4Support = false;
+    };
+
+    # Enable touchpad support for many laptops.
+    synaptics.enable = true;
+  };
 
   environment.systemPackages =
-    [ # Include gparted for partitioning disks.
+    [ pkgs.glxinfo
+
+      # Include gparted for partitioning disks.
       pkgs.gparted
 
+      # Firefox for reading the manual.
+      pkgs.firefox
+
       # Include some editors.
       pkgs.vim
       pkgs.bvi # binary editor
@@ -32,80 +53,21 @@ with lib;
   # Don't start the X server by default.
   services.xserver.autorun = mkForce false;
 
-  # Auto-login as root.
-  services.xserver.displayManager.kdm.extraConfig =
-    ''
-      [X-*-Core]
-      AllowRootLogin=true
-      AutoLoginEnable=true
-      AutoLoginUser=root
-      AutoLoginPass=""
-    '';
-
-  # Custom kde-workspace adding some icons on the desktop
-
   system.activationScripts.installerDesktop = let
-    openManual = pkgs.writeScript "nixos-manual.sh" ''
-      #!${pkgs.stdenv.shell}
-      cd ${config.system.build.manual.manual}/share/doc/nixos/
-      konqueror ./index.html
-    '';
-
     desktopFile = pkgs.writeText "nixos-manual.desktop" ''
       [Desktop Entry]
       Version=1.0
       Type=Application
       Name=NixOS Manual
-      Exec=${openManual}
-      Icon=konqueror
+      Exec=firefox ${config.system.build.manual.manual}/share/doc/nixos/index.html
+      Icon=text-html
     '';
 
   in ''
     mkdir -p /root/Desktop
     ln -sfT ${desktopFile} /root/Desktop/nixos-manual.desktop
-    ln -sfT ${pkgs.kde4.konsole}/share/applications/kde4/konsole.desktop /root/Desktop/konsole.desktop
+    ln -sfT ${pkgs.kde5.konsole}/share/applications/org.kde.konsole.desktop /root/Desktop/org.kde.konsole.desktop
     ln -sfT ${pkgs.gparted}/share/applications/gparted.desktop /root/Desktop/gparted.desktop
   '';
 
-  services.xserver.desktopManager.kde4.kdeWorkspacePackage = let
-    pkg = pkgs.kde4.kde_workspace;
-
-    plasmaInit = pkgs.writeText "00-defaultLayout.js" ''
-      loadTemplate("org.kde.plasma-desktop.defaultPanel")
-
-      for (var i = 0; i < screenCount; ++i) {
-        var desktop = new Activity
-        desktop.name = i18n("Desktop")
-        desktop.screen = i
-        desktop.wallpaperPlugin = 'image'
-        desktop.wallpaperMode = 'SingleImage'
-
-        var folderview = desktop.addWidget("folderview");
-        folderview.writeConfig("url", "desktop:/");
-
-        //Create more panels for other screens
-        if (i > 0){
-          var panel = new Panel
-          panel.screen = i
-          panel.location = 'bottom'
-          panel.height = screenGeometry(i).height > 1024 ? 35 : 27
-          var tasks = panel.addWidget("tasks")
-          tasks.writeConfig("showOnlyCurrentScreen", true);
-        }
-      }
-    '';
-
-  in
-    pkgs.runCommand pkg.name
-      { inherit (pkg) meta; }
-      ''
-        mkdir -p $out
-        cp -prf ${pkg}/* $out/
-        chmod a+w $out/share/apps/plasma-desktop/init
-        cp -f ${plasmaInit} $out/share/apps/plasma-desktop/init/00-defaultLayout.js
-      '';
-
-  # Disable large stuff that's not very useful on the installation CD.
-  services.xserver.desktopManager.kde4.enablePIM = false;
-
 }
diff --git a/nixos/modules/installer/tools/nixos-option.sh b/nixos/modules/installer/tools/nixos-option.sh
index 17c17d05e288..27eacda48a87 100644
--- a/nixos/modules/installer/tools/nixos-option.sh
+++ b/nixos/modules/installer/tools/nixos-option.sh
@@ -256,7 +256,7 @@ if isOption opt then
   // optionalAttrs (opt ? default) { inherit (opt) default; }
   // optionalAttrs (opt ? example) { inherit (opt) example; }
   // optionalAttrs (opt ? description) { inherit (opt) description; }
-  // optionalAttrs (opt ? type) { typename = opt.type.name; }
+  // optionalAttrs (opt ? type) { typename = opt.type.description; }
   // optionalAttrs (opt ? options) { inherit (opt) options; }
   // {
     # to disambiguate the xml output.
diff --git a/nixos/modules/installer/virtualbox-demo.nix b/nixos/modules/installer/virtualbox-demo.nix
index 49ec08996104..5316cfce906b 100644
--- a/nixos/modules/installer/virtualbox-demo.nix
+++ b/nixos/modules/installer/virtualbox-demo.nix
@@ -18,5 +18,5 @@ with lib;
 
   # Add some more video drivers to give X11 a shot at working in
   # VMware and QEMU.
-  services.xserver.videoDrivers = mkOverride 40 [ "virtualbox" "vmware" "cirrus" "vesa" ];
+  services.xserver.videoDrivers = mkOverride 40 [ "virtualbox" "vmware" "cirrus" "vesa" "modesetting" ];
 }
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 8c0f0c2624b1..b61c1f4799ec 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -84,7 +84,7 @@
       spamd = 56;
       #networkmanager = 57; # unused
       nslcd = 58;
-      #scanner = 59; # unused
+      scanner = 59;
       nginx = 60;
       chrony = 61;
       #systemd-journal = 62; # unused
@@ -277,6 +277,10 @@
       gitlab-runner = 257;
       postgrey = 258;
       hound = 259;
+      leaps = 260;
+      ipfs  = 261;
+      stanchion = 262;
+      riak-cs = 263;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -524,6 +528,10 @@
       gitlab-runner = 257;
       postgrey = 258;
       hound = 259;
+      leaps = 260;
+      ipfs = 261;
+      stanchion = 262;
+      riak-cs = 263;
 
       # 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/module-list.nix b/nixos/modules/module-list.nix
index 08d739704080..d82f1fbc54fd 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -159,6 +159,8 @@
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
   ./services/databases/riak.nix
+  ./services/databases/riak-cs.nix
+  ./services/databases/stanchion.nix
   ./services/databases/virtuoso.nix
   ./services/desktops/accountsservice.nix
   ./services/desktops/geoclue2.nix
@@ -251,6 +253,7 @@
   ./services/misc/gitolite.nix
   ./services/misc/gpsd.nix
   ./services/misc/ihaskell.nix
+  ./services/misc/leaps.nix
   ./services/misc/mantisbt.nix
   ./services/misc/mathics.nix
   ./services/misc/matrix-synapse.nix
@@ -317,6 +320,7 @@
   ./services/monitoring/zabbix-server.nix
   ./services/network-filesystems/cachefilesd.nix
   ./services/network-filesystems/drbd.nix
+  ./services/network-filesystems/ipfs.nix
   ./services/network-filesystems/netatalk.nix
   ./services/network-filesystems/nfsd.nix
   ./services/network-filesystems/openafs-client/default.nix
@@ -537,7 +541,6 @@
   ./services/x11/window-managers/fluxbox.nix
   ./services/x11/window-managers/icewm.nix
   ./services/x11/window-managers/bspwm.nix
-  ./services/x11/window-managers/bspwm-unstable.nix
   ./services/x11/window-managers/metacity.nix
   ./services/x11/window-managers/none.nix
   ./services/x11/window-managers/twm.nix
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 44e07f4618de..a89ce2c743d4 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -30,6 +30,8 @@ with lib;
     (mkRenamedOptionModule [ "services" "gitlab" "stateDir" ] [ "services" "gitlab" "statePath" ])
     (mkRemovedOptionModule [ "services" "gitlab" "satelliteDir" ] "")
 
+    (mkRenamedOptionModule [ "services" "clamav" "updater" "config" ] [ "services" "clamav" "updater" "extraConfig" ])
+
     # Old Grub-related options.
     (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ])
     (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ])
@@ -142,6 +144,12 @@ with lib;
     # murmur
     (mkRenamedOptionModule [ "services" "murmur" "welcome" ] [ "services" "murmur" "welcometext" ])
 
+    # parsoid
+    (mkRemovedOptionModule [ "services" "parsoid" "interwikis" ] [ "services" "parsoid" "wikis" ])
+
+    # tarsnap
+    (mkRemovedOptionModule [ "services" "tarsnap" "cachedir" ] "Use services.tarsnap.archives.<name>.cachedir")
+
     # Options that are obsolete and have no replacement.
     (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "")
     (mkRemovedOptionModule [ "programs" "bash" "enable" ] "")
diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix
index 0e3a54325cad..97e2d39dc076 100644
--- a/nixos/modules/security/duosec.nix
+++ b/nixos/modules/security/duosec.nix
@@ -73,7 +73,7 @@ in
       };
 
       failmode = mkOption {
-        type = types.str;
+        type = types.enum [ "safe" "enum" ];
         default = "safe";
         description = ''
           On service or configuration errors that prevent Duo
@@ -115,7 +115,7 @@ in
       };
 
       prompts = mkOption {
-        type = types.int;
+        type = types.enum [ 1 2 3 ];
         default = 3;
         description = ''
           If a user fails to authenticate with a second factor, Duo
@@ -181,13 +181,7 @@ in
 
   config = mkIf (cfg.ssh.enable || cfg.pam.enable) {
     assertions =
-      [ { assertion = cfg.failmode == "safe" || cfg.failmode == "secure";
-          message   = "Invalid value for failmode (must be safe or secure).";
-        }
-        { assertion = cfg.prompts == 1 || cfg.prompts == 2 || cfg.prompts == 3;
-          message   = "Invalid value for prompts (must be 1, 2, or 3).";
-        }
-        { assertion = !cfg.pam.enable;
+      [ { assertion = !cfg.pam.enable;
           message   = "PAM support is currently not implemented.";
         }
       ];
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index 53c2ace784ef..ea245ecc5b6a 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -6,14 +6,6 @@ let
   cfg = config.security.grsecurity;
   grsecLockPath = "/proc/sys/kernel/grsecurity/grsec_lock";
 
-  # Ascertain whether ZFS is required for booting the system; grsecurity is
-  # currently incompatible with ZFS, rendering the system unbootable.
-  zfsNeededForBoot = filter
-    (fs: (fs.neededForBoot
-          || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ])
-          && fs.fsType == "zfs")
-    config.system.build.fileSystems != [];
-
   # Ascertain whether NixOS container support is required
   containerSupportRequired =
     config.boot.enableContainers && config.containers != {};
@@ -27,7 +19,14 @@ in
 
   options.security.grsecurity = {
 
-    enable = mkEnableOption "grsecurity/PaX";
+    enable = mkOption {
+      type = types.bool;
+      example = true;
+      default = false;
+      description = ''
+        Enable grsecurity/PaX.
+      '';
+    };
 
     lockTunables = mkOption {
       type = types.bool;
@@ -58,20 +57,10 @@ in
 
   config = mkIf cfg.enable {
 
-    # Allow the user to select a different package set, subject to the stated
-    # required kernel config
     boot.kernelPackages = mkDefault pkgs.linuxPackages_grsec_nixos;
 
     boot.kernelParams = optional cfg.disableEfiRuntimeServices "noefi";
 
-    system.requiredKernelConfig = with config.lib.kernelConfig;
-      [ (isEnabled "GRKERNSEC")
-        (isEnabled "PAX")
-        (isYes "GRKERNSEC_SYSCTL")
-        (isYes "GRKERNSEC_SYSCTL_DISTRO")
-        (isNo "GRKERNSEC_NO_RBAC")
-      ];
-
     nixpkgs.config.grsecurity = true;
 
     # Install PaX related utillities into the system profile.
@@ -135,11 +124,5 @@ in
       "kernel.grsecurity.chroot_caps" = mkForce 0;
     };
 
-    assertions = [
-      { assertion = !zfsNeededForBoot;
-        message = "grsecurity is currently incompatible with ZFS";
-      }
-    ];
-
   };
 }
diff --git a/nixos/modules/security/grsecurity.xml b/nixos/modules/security/grsecurity.xml
index 37314bdba8a5..6f9884336b1e 100644
--- a/nixos/modules/security/grsecurity.xml
+++ b/nixos/modules/security/grsecurity.xml
@@ -225,11 +225,9 @@
   </para>
 
   <para>
-    The NixOS module makes several assumptions about the kernel and so may be
-    incompatible with your customised kernel.  Most of these assumptions are
-    encoded as assertions &#x2014; mismatches should ideally result in a build
-    failure.  Currently, the only way to work around incompatibilities is to
-    eschew the NixOS module and do all configuration yourself.
+    The NixOS module makes several assumptions about the kernel and so
+    may be incompatible with your customised kernel. Currently, the only way
+    to work around incompatibilities is to eschew the NixOS module.
   </para>
 
   </sect1>
diff --git a/nixos/modules/services/backup/crashplan.nix b/nixos/modules/services/backup/crashplan.nix
index 38cf8eb72fb8..d0af2e416b63 100644
--- a/nixos/modules/services/backup/crashplan.nix
+++ b/nixos/modules/services/backup/crashplan.nix
@@ -49,7 +49,7 @@ with lib;
         ensureDir ${crashplan.vardir}/backupArchives 700
         ensureDir ${crashplan.vardir}/log 777
         cp -avn ${crashplan}/conf.template/* ${crashplan.vardir}/conf
-        for x in app.asar bin EULA.txt install.vars lang lib libjniwrap64.so libjniwrap.so libjtux64.so libjtux.so libmd564.so libmd5.so share skin upgrade; do
+        for x in app.asar bin install.vars lang lib libc42archive64.so libc52archive.so libjniwrap64.so libjniwrap.so libjtux64.so libjtux.so libleveldb64.so libleveldb.so libmd564.so libmd5.so share skin upgrade; do
           rm -f ${crashplan.vardir}/$x;
           ln -sf ${crashplan}/$x ${crashplan.vardir}/$x;
         done
diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix
index 24892a2a59a1..67112343c335 100644
--- a/nixos/modules/services/backup/tarsnap.nix
+++ b/nixos/modules/services/backup/tarsnap.nix
@@ -1,25 +1,25 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, utils, ... }:
 
 with lib;
 
 let
-  cfg = config.services.tarsnap;
+  gcfg = config.services.tarsnap;
 
   configFile = name: cfg: ''
-    cachedir ${config.services.tarsnap.cachedir}/${name}
-    keyfile  ${cfg.keyfile}
+    keyfile ${cfg.keyfile}
+    ${optionalString (cfg.cachedir != null) "cachedir ${cfg.cachedir}"}
     ${optionalString cfg.nodump "nodump"}
     ${optionalString cfg.printStats "print-stats"}
     ${optionalString cfg.printStats "humanize-numbers"}
     ${optionalString (cfg.checkpointBytes != null) ("checkpoint-bytes "+cfg.checkpointBytes)}
     ${optionalString cfg.aggressiveNetworking "aggressive-networking"}
-    ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)}
-    ${concatStringsSep "\n" (map (v: "include "+v) cfg.includes)}
+    ${concatStringsSep "\n" (map (v: "exclude ${v}") cfg.excludes)}
+    ${concatStringsSep "\n" (map (v: "include ${v}") cfg.includes)}
     ${optionalString cfg.lowmem "lowmem"}
     ${optionalString cfg.verylowmem "verylowmem"}
-    ${optionalString (cfg.maxbw != null) ("maxbw "+toString cfg.maxbw)}
-    ${optionalString (cfg.maxbwRateUp != null) ("maxbw-rate-up "+toString cfg.maxbwRateUp)}
-    ${optionalString (cfg.maxbwRateDown != null) ("maxbw-rate-down "+toString cfg.maxbwRateDown)}
+    ${optionalString (cfg.maxbw != null) "maxbw ${toString cfg.maxbw}"}
+    ${optionalString (cfg.maxbwRateUp != null) "maxbw-rate-up ${toString cfg.maxbwRateUp}"}
+    ${optionalString (cfg.maxbwRateDown != null) "maxbw-rate-down ${toString cfg.maxbwRateDown}"}
   '';
 in
 {
@@ -60,34 +60,13 @@ in
         '';
       };
 
-      cachedir = mkOption {
-        type    = types.nullOr types.path;
-        default = "/var/cache/tarsnap";
-        description = ''
-          The cache allows tarsnap to identify previously stored data
-          blocks, reducing archival time and bandwidth usage.
-
-          Should the cache become desynchronized or corrupted, tarsnap
-          will refuse to run until you manually rebuild the cache with
-          <command>tarsnap --fsck</command>.
-
-          Note that each individual archive (specified below) has its own cache
-          directory specified under <literal>cachedir</literal>; this is because
-          tarsnap locks the cache during backups, meaning multiple services
-          archives cannot be backed up concurrently or overlap with a shared
-          cache.
-
-          Set to <literal>null</literal> to disable caching.
-        '';
-      };
-
       archives = mkOption {
-        type = types.attrsOf (types.submodule (
+        type = types.attrsOf (types.submodule ({ config, ... }:
           {
             options = {
               keyfile = mkOption {
                 type = types.str;
-                default = config.services.tarsnap.keyfile;
+                default = gcfg.keyfile;
                 description = ''
                   Set a specific keyfile for this archive. This defaults to
                   <literal>"/root/tarsnap.key"</literal> if left unspecified.
@@ -107,6 +86,21 @@ in
                 '';
               };
 
+              cachedir = mkOption {
+                type = types.nullOr types.path;
+                default = "/var/cache/tarsnap/${utils.escapeSystemdPath config.keyfile}";
+                description = ''
+                  The cache allows tarsnap to identify previously stored data
+                  blocks, reducing archival time and bandwidth usage.
+
+                  Should the cache become desynchronized or corrupted, tarsnap
+                  will refuse to run until you manually rebuild the cache with
+                  <command>tarsnap --fsck</command>.
+
+                  Set to <literal>null</literal> to disable caching.
+                '';
+              };
+
               nodump = mkOption {
                 type = types.bool;
                 default = true;
@@ -249,7 +243,7 @@ in
               };
 
             gamedata =
-              { directories = [ "/var/lib/minecraft "];
+              { directories = [ "/var/lib/minecraft" ];
                 period      = "*:30";
               };
           }
@@ -262,8 +256,8 @@ in
           archive names are suffixed by a 1 second resolution timestamp.
 
           For each member of the set is created a timer which triggers the
-          instanced <literal>tarsnap@</literal> service unit. You may use
-          <command>systemctl start tarsnap@archive-name</command> to
+          instanced <literal>tarsnap-archive-name</literal> service unit. You may use
+          <command>systemctl start tarsnap-archive-name</command> to
           manually trigger creation of <literal>archive-name</literal> at
           any time.
         '';
@@ -271,63 +265,73 @@ in
     };
   };
 
-  config = mkIf cfg.enable {
+  config = mkIf gcfg.enable {
     assertions =
       (mapAttrsToList (name: cfg:
         { assertion = cfg.directories != [];
           message = "Must specify paths for tarsnap to back up";
-        }) cfg.archives) ++
+        }) gcfg.archives) ++
       (mapAttrsToList (name: cfg:
         { assertion = !(cfg.lowmem && cfg.verylowmem);
           message = "You cannot set both lowmem and verylowmem";
-        }) cfg.archives);
-
-    systemd.services."tarsnap@" = {
-      description = "Tarsnap archive '%i'";
-      requires    = [ "network-online.target" ];
-      after       = [ "network-online.target" ];
-
-      path = [ pkgs.iputils pkgs.tarsnap pkgs.coreutils ];
-
-      # In order for the persistent tarsnap timer to work reliably, we have to
-      # make sure that the tarsnap server is reachable after systemd starts up
-      # the service - therefore we sleep in a loop until we can ping the
-      # endpoint.
-      preStart = "while ! ping -q -c 1 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done";
-      scriptArgs = "%i";
-      script = ''
-        mkdir -p -m 0755 ${dirOf cfg.cachedir}
-        mkdir -p -m 0700 ${cfg.cachedir}
-        chown root:root ${cfg.cachedir}
-        chmod 0700 ${cfg.cachedir}
-        mkdir -p -m 0700 ${cfg.cachedir}/$1
-        DIRS=`cat /etc/tarsnap/$1.dirs`
-        exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS
-      '';
-
-      serviceConfig = {
-        IOSchedulingClass = "idle";
-        NoNewPrivileges = "true";
-        CapabilityBoundingSet = "CAP_DAC_READ_SEARCH";
-        PermissionsStartOnly = "true";
-      };
-    };
+        }) gcfg.archives);
+
+    systemd.services =
+      mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}" {
+        description = "Tarsnap archive '${name}'";
+        requires    = [ "network-online.target" ];
+        after       = [ "network-online.target" ];
+
+        path = [ pkgs.iputils pkgs.tarsnap pkgs.utillinux ];
+
+        # In order for the persistent tarsnap timer to work reliably, we have to
+        # make sure that the tarsnap server is reachable after systemd starts up
+        # the service - therefore we sleep in a loop until we can ping the
+        # endpoint.
+        preStart = ''
+          while ! ping -q -c 1 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done
+        '';
+
+        script =
+          let run = ''tarsnap --configfile "/etc/tarsnap/${name}.conf" -c -f "${name}-$(date +"%Y%m%d%H%M%S")" ${concatStringsSep " " cfg.directories}'';
+          in if (cfg.cachedir != null) then ''
+            mkdir -p ${cfg.cachedir}
+            chmod 0700 ${cfg.cachedir}
+
+            ( flock 9
+              if [ ! -e ${cfg.cachedir}/firstrun ]; then
+                ( flock 10
+                  flock -u 9
+                  tarsnap --configfile "/etc/tarsnap/${name}.conf" --fsck
+                  flock 9
+                ) 10>${cfg.cachedir}/firstrun
+              fi
+            ) 9>${cfg.cachedir}/lockf
+
+             exec flock ${cfg.cachedir}/firstrun ${run}
+          '' else "exec ${run}";
+
+        serviceConfig = {
+          Type = "oneshot";
+          IOSchedulingClass = "idle";
+          NoNewPrivileges = "true";
+          CapabilityBoundingSet = [ "CAP_DAC_READ_SEARCH" ];
+          PermissionsStartOnly = "true";
+        };
+      }) gcfg.archives;
 
     # Note: the timer must be Persistent=true, so that systemd will start it even
     # if e.g. your laptop was asleep while the latest interval occurred.
-    systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap@${name}"
+    systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}"
       { timerConfig.OnCalendar = cfg.period;
         timerConfig.Persistent = "true";
         wantedBy = [ "timers.target" ];
-      }) cfg.archives;
+      }) gcfg.archives;
 
     environment.etc =
-      (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
+      mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
         { text = configFile name cfg;
-        }) cfg.archives) //
-      (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs"
-        { text = concatStringsSep " " cfg.directories;
-        }) cfg.archives);
+        }) gcfg.archives;
 
     environment.systemPackages = [ pkgs.tarsnap ];
   };
diff --git a/nixos/modules/services/cluster/fleet.nix b/nixos/modules/services/cluster/fleet.nix
index 78d4ea93c491..ec03be395948 100644
--- a/nixos/modules/services/cluster/fleet.nix
+++ b/nixos/modules/services/cluster/fleet.nix
@@ -28,7 +28,7 @@ in {
 
     etcdServers = mkOption {
       type = types.listOf types.str;
-      default = [ "http://127.0.0.1:4001" ];
+      default = [ "http://127.0.0.1:2379" ];
       description = ''
         Fleet list of etcd endpoints to use.
       '';
diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix
index 4bdd7f95f774..19303e97a706 100644
--- a/nixos/modules/services/cluster/kubernetes.nix
+++ b/nixos/modules/services/cluster/kubernetes.nix
@@ -23,7 +23,7 @@ in {
 
     etcdServers = mkOption {
       description = "Kubernetes list of etcd servers to watch.";
-      default = [ "127.0.0.1:4001" ];
+      default = [ "127.0.0.1:2379" ];
       type = types.listOf types.str;
     };
 
diff --git a/nixos/modules/services/cluster/panamax.nix b/nixos/modules/services/cluster/panamax.nix
index b47ff744fc27..4475e8d8c24b 100644
--- a/nixos/modules/services/cluster/panamax.nix
+++ b/nixos/modules/services/cluster/panamax.nix
@@ -46,7 +46,7 @@ in {
 
     fleetctlEndpoint = mkOption {
       type = types.str;
-      default = "http://127.0.0.1:4001";
+      default = "http://127.0.0.1:2379";
       description = ''
         Panamax fleetctl endpoint.
       '';
diff --git a/nixos/modules/services/databases/riak-cs.nix b/nixos/modules/services/databases/riak-cs.nix
new file mode 100644
index 000000000000..198efc29222a
--- /dev/null
+++ b/nixos/modules/services/databases/riak-cs.nix
@@ -0,0 +1,202 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.riak-cs;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.riak-cs = {
+
+      enable = mkEnableOption "riak-cs";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.riak-cs;
+        defaultText = "pkgs.riak-cs";
+        example = literalExample "pkgs.riak-cs";
+        description = ''
+          Riak package to use.
+        '';
+      };
+
+      nodeName = mkOption {
+        type = types.str;
+        default = "riak-cs@127.0.0.1";
+        description = ''
+          Name of the Erlang node.
+        '';
+      };
+      
+      anonymousUserCreation = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Anonymous user creation.
+        '';
+      };
+
+      riakHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8087";
+        description = ''
+          Name of riak hosting service.
+        '';
+      };
+
+      listener = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8080";
+        description = ''
+          Name of Riak CS listening service.
+        '';
+      };
+
+      stanchionHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of stanchion hosting service.
+        '';
+      };
+
+      stanchionSsl = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Tell stanchion to use SSL.
+        '';
+      };
+
+      distributedCookie = mkOption {
+        type = types.str;
+        default = "riak";
+        description = ''
+          Cookie for distributed node communication.  All nodes in the
+          same cluster should use the same cookie or they will not be able to
+          communicate.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/db/riak-cs";
+        description = ''
+          Data directory for Riak CS.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/riak-cs";
+        description = ''
+          Log directory for Riak CS.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>riak-cs.conf</filename>.
+        '';
+      };
+
+      extraAdvancedConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>advanced.config</filename>.
+        '';
+      };
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+    environment.etc."riak-cs/riak-cs.conf".text = ''
+      nodename = ${cfg.nodeName}
+      distributed_cookie = ${cfg.distributedCookie}
+
+      platform_log_dir = ${cfg.logDir}
+
+      riak_host = ${cfg.riakHost}
+      listener = ${cfg.listener}
+      stanchion_host = ${cfg.stanchionHost}
+
+      anonymous_user_creation = ${if cfg.anonymousUserCreation then "on" else "off"}
+
+      ${cfg.extraConfig}
+    '';
+
+    environment.etc."riak-cs/advanced.config".text = ''
+      ${cfg.extraAdvancedConfig}
+    '';
+
+    users.extraUsers.riak-cs = {
+      name = "riak-cs";
+      uid = config.ids.uids.riak-cs;
+      group = "riak";
+      description = "Riak CS server user";
+    };
+
+  systemd.services.riak-cs = {
+      description = "Riak CS Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      path = [
+        pkgs.utillinux # for `logger`
+        pkgs.bash
+      ];
+
+      environment.HOME = "${cfg.dataDir}";
+      environment.RIAK_CS_DATA_DIR = "${cfg.dataDir}";
+      environment.RIAK_CS_LOG_DIR = "${cfg.logDir}";
+      environment.RIAK_CS_ETC_DIR = "/etc/riak";
+
+      preStart = ''
+        if ! test -e ${cfg.logDir}; then
+          mkdir -m 0755 -p ${cfg.logDir}
+          chown -R riak-cs ${cfg.logDir}
+        fi
+
+        if ! test -e ${cfg.dataDir}; then
+          mkdir -m 0700 -p ${cfg.dataDir}
+          chown -R riak-cs ${cfg.dataDir}
+        fi
+      '';
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/riak-cs console";
+        ExecStop = "${cfg.package}/bin/riak-cs stop";
+        StandardInput = "tty";
+        User = "riak-cs";
+        Group = "riak-cs";
+        PermissionsStartOnly = true;
+        # Give Riak a decent amount of time to clean up.
+        TimeoutStopSec = 120;
+        LimitNOFILE = 65536;
+      };
+
+      unitConfig.RequiresMountsFor = [
+        "${cfg.dataDir}"
+        "${cfg.logDir}"
+        "/etc/riak"
+      ];
+    };
+  };
+}
diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix
index 4477904f78c6..d592d2e8ffdd 100644
--- a/nixos/modules/services/databases/riak.nix
+++ b/nixos/modules/services/databases/riak.nix
@@ -20,6 +20,8 @@ in
 
       package = mkOption {
         type = types.package;
+        default = pkgs.riak;
+        defaultText = "pkgs.riak";
         example = literalExample "pkgs.riak";
         description = ''
           Riak package to use.
diff --git a/nixos/modules/services/databases/stanchion.nix b/nixos/modules/services/databases/stanchion.nix
new file mode 100644
index 000000000000..f2dbb78b5c4b
--- /dev/null
+++ b/nixos/modules/services/databases/stanchion.nix
@@ -0,0 +1,212 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.stanchion;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.stanchion = {
+
+      enable = mkEnableOption "stanchion";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.stanchion;
+        defaultText = "pkgs.stanchion";
+        example = literalExample "pkgs.stanchion";
+        description = ''
+          Stanchion package to use.
+        '';
+      };
+
+      nodeName = mkOption {
+        type = types.str;
+        default = "stanchion@127.0.0.1";
+        description = ''
+          Name of the Erlang node.
+        '';
+      };
+
+      adminKey = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Name of admin user.
+        '';
+      };
+
+      adminSecret = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Name of admin secret
+        '';
+      };
+
+      riakHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8087";
+        description = ''
+          Name of riak hosting service.
+        '';
+      };
+
+      listener = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of Riak CS listening service.
+        '';
+      };
+
+      stanchionHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of stanchion hosting service.
+        '';
+      };
+
+      stanchionSsl = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Tell stanchion to use SSL.
+        '';
+      };
+
+      distributedCookie = mkOption {
+        type = types.str;
+        default = "riak";
+        description = ''
+          Cookie for distributed node communication.  All nodes in the
+          same cluster should use the same cookie or they will not be able to
+          communicate.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/db/stanchion";
+        description = ''
+          Data directory for Stanchion.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/stanchion";
+        description = ''
+          Log directory for Stanchino.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>stanchion.conf</filename>.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+
+    environment.etc."stanchion/advanced.config".text = ''
+      [{stanchion, []}].
+    '';
+
+    environment.etc."stanchion/stanchion.conf".text = ''
+      listener = ${cfg.listener}
+
+      riak_host = ${cfg.riakHost}
+
+      ${optionalString (cfg.adminKey == "") "#"} admin.key=${optionalString (cfg.adminKey != "") cfg.adminKey}
+      ${optionalString (cfg.adminSecret == "") "#"} admin.secret=${optionalString (cfg.adminSecret != "") cfg.adminSecret}
+
+      platform_bin_dir = ${pkgs.stanchion}/bin
+      platform_data_dir = ${cfg.dataDir}
+      platform_etc_dir = /etc/stanchion
+      platform_lib_dir = ${pkgs.stanchion}/lib
+      platform_log_dir = ${cfg.logDir}
+
+      nodename = ${cfg.nodeName}
+
+      distributed_cookie = ${cfg.distributedCookie}
+
+      stanchion_ssl=${if cfg.stanchionSsl then "on" else "off"}
+
+      ${cfg.extraConfig}
+    '';
+
+    users.extraUsers.stanchion = {
+      name = "stanchion";
+      uid = config.ids.uids.stanchion;
+      group = "stanchion";
+      description = "Stanchion server user";
+    };
+
+    users.extraGroups.stanchion.gid = config.ids.gids.stanchion;
+
+    systemd.services.stanchion = {
+      description = "Stanchion Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      path = [
+        pkgs.utillinux # for `logger`
+        pkgs.bash
+      ];
+
+      environment.HOME = "${cfg.dataDir}";
+      environment.STANCHION_DATA_DIR = "${cfg.dataDir}";
+      environment.STANCHION_LOG_DIR = "${cfg.logDir}";
+      environment.STANCHION_ETC_DIR = "/etc/stanchion";
+
+      preStart = ''
+        if ! test -e ${cfg.logDir}; then
+          mkdir -m 0755 -p ${cfg.logDir}
+          chown -R stanchion:stanchion ${cfg.logDir}
+        fi
+
+        if ! test -e ${cfg.dataDir}; then
+          mkdir -m 0700 -p ${cfg.dataDir}
+          chown -R stanchion:stanchion ${cfg.dataDir}
+        fi
+      '';
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/stanchion console";
+        ExecStop = "${cfg.package}/bin/stanchion stop";
+        StandardInput = "tty";
+        User = "stanchion";
+        Group = "stanchion";
+        PermissionsStartOnly = true;
+        # Give Stanchion a decent amount of time to clean up.
+        TimeoutStopSec = 120;
+        LimitNOFILE = 65536;
+      };
+
+      unitConfig.RequiresMountsFor = [
+        "${cfg.dataDir}"
+        "${cfg.logDir}"
+        "/etc/stanchion"
+      ];
+    };
+  };
+}
diff --git a/nixos/modules/services/editors/emacs.xml b/nixos/modules/services/editors/emacs.xml
index bcaa8b8df3d8..e03f6046de8e 100644
--- a/nixos/modules/services/editors/emacs.xml
+++ b/nixos/modules/services/editors/emacs.xml
@@ -356,14 +356,14 @@ https://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides
         <programlisting><![CDATA[
 { pkgs ? import <nixpkgs> {} }:
 let
-  myEmacs = pkgs.lib.overrideDerivation (pkgs.emacs.override {
+  myEmacs = (pkgs.emacs.override {
     # Use gtk3 instead of the default gtk2
     withGTK3 = true;
     withGTK2 = false;
-  }) (attrs: {
+  }).overrideAttrs (attrs: {
     # I don't want emacs.desktop file because I only use
     # emacsclient.
-    postInstall = attrs.postInstall + ''
+    postInstall = (attrs.postInstall or "") + ''
       rm $out/share/applications/emacs.desktop
     '';
   });
diff --git a/nixos/modules/services/games/ghost-one.nix b/nixos/modules/services/games/ghost-one.nix
index 5762148df2bb..71ff6bb2f3f0 100644
--- a/nixos/modules/services/games/ghost-one.nix
+++ b/nixos/modules/services/games/ghost-one.nix
@@ -21,8 +21,7 @@ in
 
       language = mkOption {
         default = "English";
-        type = types.addCheck types.str
-          (lang: elem lang [ "English" "Spanish" "Russian" "Serbian" "Turkish" ]);
+        type = types.enum [ "English" "Spanish" "Russian" "Serbian" "Turkish" ];
         description = "The language of bot messages: English, Spanish, Russian, Serbian or Turkish.";
       };
 
diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index a34037403123..8ddb9ef9c53b 100644
--- a/nixos/modules/services/hardware/sane.nix
+++ b/nixos/modules/services/hardware/sane.nix
@@ -7,9 +7,35 @@ let
   pkg = if config.hardware.sane.snapshot
     then pkgs.sane-backends-git
     else pkgs.sane-backends;
-  backends = [ pkg ] ++ config.hardware.sane.extraBackends;
+
+  sanedConf = pkgs.writeTextFile {
+    name = "saned.conf";
+    destination = "/etc/sane.d/saned.conf";
+    text = ''
+      localhost
+      ${config.services.saned.extraConfig}
+    '';
+  };
+
+  netConf = pkgs.writeTextFile {
+    name = "net.conf";
+    destination = "/etc/sane.d/net.conf";
+    text = ''
+      ${lib.optionalString config.services.saned.enable "localhost"}
+      ${config.hardware.sane.netConf}
+    '';
+  };
+
+  env = {
+    SANE_CONFIG_DIR = config.hardware.sane.configDir;
+    LD_LIBRARY_PATH = [ "${saneConfig}/lib/sane" ];
+  };
+
+  backends = [ pkg netConf ] ++ optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends;
   saneConfig = pkgs.mkSaneConfig { paths = backends; };
 
+  enabled = config.hardware.sane.enable || config.services.saned.enable;
+
 in
 
 {
@@ -51,27 +77,86 @@ in
 
     hardware.sane.configDir = mkOption {
       type = types.string;
+      internal = true;
       description = "The value of SANE_CONFIG_DIR.";
     };
 
-  };
+    hardware.sane.netConf = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.16";
+      description = ''
+        Network hosts that should be probed for remote scanners.
+      '';
+    };
 
+    services.saned.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable saned network daemon for remote connection to scanners.
 
-  ###### implementation
+        saned would be runned from <literal>scanner</literal> user; to allow
+        access to hardware that doesn't have <literal>scanner</literal> group
+        you should add needed groups to this user.
+      '';
+    };
 
-  config = mkIf config.hardware.sane.enable {
+    services.saned.extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.0/24";
+      description = ''
+        Extra saned configuration lines.
+      '';
+    };
 
-    hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+  };
 
-    environment.systemPackages = backends;
-    environment.sessionVariables = {
-      SANE_CONFIG_DIR = config.hardware.sane.configDir;
-      LD_LIBRARY_PATH = [ "${saneConfig}/lib/sane" ];
-    };
-    services.udev.packages = backends;
 
-    users.extraGroups."scanner".gid = config.ids.gids.scanner;
+  ###### implementation
 
-  };
+  config = mkMerge [
+    (mkIf enabled {
+      hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+
+      environment.systemPackages = backends;
+      environment.sessionVariables = env;
+      services.udev.packages = backends;
+
+      users.extraGroups."scanner".gid = config.ids.gids.scanner;
+    })
+
+    (mkIf config.services.saned.enable {
+      networking.firewall.connectionTrackingModules = [ "sane" ];
+
+      systemd.services."saned@" = {
+        description = "Scanner Service";
+        environment = mapAttrs (name: val: toString val) env;
+        serviceConfig = {
+          User = "scanner";
+          Group = "scanner";
+          ExecStart = "${pkg}/bin/saned";
+        };
+      };
+
+      systemd.sockets.saned = {
+        description = "saned incoming socket";
+        wantedBy = [ "sockets.target" ];
+        listenStreams = [ "0.0.0.0:6566" "[::]:6566" ];
+        socketConfig = {
+          # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets.
+          BindIPv6Only = "ipv6-only";
+          Accept = true;
+          MaxConnections = 1;
+        };
+      };
+
+      users.extraUsers."scanner" = {
+        uid = config.ids.uids.scanner;
+        group = "scanner";
+      };
+    })
+  ];
 
 }
diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix
index a8a214b21550..27ed5374f561 100644
--- a/nixos/modules/services/logging/logcheck.nix
+++ b/nixos/modules/services/logging/logcheck.nix
@@ -55,9 +55,9 @@ let
 
   levelOption = mkOption {
     default = "server";
-    type = types.str;
+    type = types.enum [ "workstation" "server" "paranoid" ];
     description = ''
-      Set the logcheck level. Either "workstation", "server", or "paranoid".
+      Set the logcheck level.
     '';
   };
 
diff --git a/nixos/modules/services/misc/errbot.nix b/nixos/modules/services/misc/errbot.nix
index f573be69925c..427cb7c546d0 100644
--- a/nixos/modules/services/misc/errbot.nix
+++ b/nixos/modules/services/misc/errbot.nix
@@ -8,7 +8,7 @@ let
     name = "errbot-plugins";
     paths = plugins;
   };
-  mkConfigFile = instanceCfg: dataDir: pkgs.writeText "errbot-config.py" ''
+  mkConfigDir = instanceCfg: dataDir: pkgs.writeTextDir "config.py" ''
     import logging
     BACKEND = '${instanceCfg.backend}'
     BOT_DATA_DIR = '${dataDir}'
@@ -93,7 +93,7 @@ in {
       serviceConfig = {
         User = "errbot";
         Restart = "on-failure";
-        ExecStart = "${pkgs.errbot}/bin/errbot -c ${mkConfigFile instanceCfg dataDir}";
+        ExecStart = "${pkgs.errbot}/bin/errbot -c ${mkConfigDir instanceCfg dataDir}/config.py";
         PermissionsStartOnly = true;
       };
     })) cfg.instances;
diff --git a/nixos/modules/services/misc/leaps.nix b/nixos/modules/services/misc/leaps.nix
new file mode 100644
index 000000000000..b92cf27f58dc
--- /dev/null
+++ b/nixos/modules/services/misc/leaps.nix
@@ -0,0 +1,62 @@
+{ config, pkgs, lib, ... } @ args:
+
+with lib;
+
+let
+  cfg = config.services.leaps;
+  stateDir = "/var/lib/leaps/";
+in
+{
+  options = {
+    services.leaps = {
+      enable = mkEnableOption "leaps";
+      port = mkOption {
+        type = types.int;
+        default = 8080;
+        description = "A port where leaps listens for incoming http requests";
+      };
+      address = mkOption {
+        default = "";
+        type = types.str;
+        example = "127.0.0.1";
+        description = "Hostname or IP-address to listen to. By default it will listen on all interfaces.";
+      };
+      path = mkOption {
+        default = "/";
+        type = types.path;
+        description = "Subdirectory used for reverse proxy setups";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users = {
+      users.leaps = {
+        uid             = config.ids.uids.leaps;
+        description     = "Leaps server user";
+        group           = "leaps";
+        home            = stateDir;
+        createHome      = true;
+      };
+
+      groups.leaps = {
+        gid = config.ids.gids.leaps;
+      };
+    };
+
+    systemd.services.leaps = {
+      description   = "leaps service";
+      wantedBy      = [ "multi-user.target" ];
+      after         = [ "network.target" ];
+
+      serviceConfig = {
+        User = "leaps";
+        Group = "leaps";
+        Restart = "on-failure";
+        WorkingDirectory = stateDir;
+        PrivateTmp = true;
+        ExecStart = "${pkgs.leaps.bin}/bin/leaps -path ${toString cfg.path} -address ${cfg.address}:${toString cfg.port}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 333782d15bcb..e2bbd4b01aa1 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -172,8 +172,8 @@ in
             sshKey = "/root/.ssh/id_buildfarm";
             system = "x86_64-linux";
             maxJobs = 2;
-            supportedFeatures = "kvm";
-            mandatoryFeatures = "perf";
+            supportedFeatures = [ "kvm" ];
+            mandatoryFeatures = [ "perf" ];
           }
         ];
         description = ''
diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix
index 0844190a5490..ae3f84333d2d 100644
--- a/nixos/modules/services/misc/parsoid.nix
+++ b/nixos/modules/services/misc/parsoid.nix
@@ -6,20 +6,21 @@ let
 
   cfg = config.services.parsoid;
 
-  conf = ''
-    exports.setup = function( parsoidConfig ) {
-      ${toString (mapAttrsToList (name: str: "parsoidConfig.setInterwiki('${name}', '${str}');") cfg.interwikis)}
-
-      parsoidConfig.serverInterface = "${cfg.interface}";
-      parsoidConfig.serverPort = ${toString cfg.port};
-
-      parsoidConfig.useSelser = true;
-
-      ${cfg.extraConfig}
-    };
-  '';
+  confTree = {
+    worker_heartbeat_timeout = 300000;
+    logging = { level = "info"; };
+    services = [{
+      module = "lib/index.js";
+      entrypoint = "apiServiceWorker";
+      conf = {
+        mwApis = map (x: if isAttrs x then x else { uri = x; }) cfg.wikis;
+        serverInterface = cfg.interface;
+        serverPort = cfg.port;
+      };
+    }];
+  };
 
-  confFile = builtins.toFile "localsettings.js" conf;
+  confFile = pkgs.writeText "config.yml" (builtins.toJSON (recursiveUpdate confTree cfg.extraConfig));
 
 in
 {
@@ -38,9 +39,9 @@ in
         '';
       };
 
-      interwikis = mkOption {
-        type = types.attrsOf types.str;
-        example = { localhost = "http://localhost/api.php"; };
+      wikis = mkOption {
+        type = types.listOf (types.either types.str types.attrs);
+        example = [ "http://localhost/api.php" ];
         description = ''
           Used MediaWiki API endpoints.
         '';
@@ -71,8 +72,8 @@ in
       };
 
       extraConfig = mkOption {
-        type = types.lines;
-        default = "";
+        type = types.attrs;
+        default = {};
         description = ''
           Extra configuration to add to parsoid configuration.
         '';
@@ -91,7 +92,8 @@ in
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       serviceConfig = {
-        ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}";
+        User = "nobody";
+        ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/bin/server.js -c ${confFile} -n ${toString cfg.workers}";
       };
     };
 
diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix
index 233c47684b7d..ca82a733f6fc 100644
--- a/nixos/modules/services/misc/taskserver/default.nix
+++ b/nixos/modules/services/misc/taskserver/default.nix
@@ -292,7 +292,7 @@ in {
       };
 
       allowedClientIDs = mkOption {
-        type = with types; loeOf (either (enum ["all" "none"]) str);
+        type = with types; either str (listOf str);
         default = [];
         example = [ "[Tt]ask [2-9]+" ];
         description = ''
@@ -306,7 +306,7 @@ in {
       };
 
       disallowedClientIDs = mkOption {
-        type = with types; loeOf (either (enum ["all" "none"]) str);
+        type = with types; either str (listOf str);
         default = [];
         example = [ "[Tt]ask [2-9]+" ];
         description = ''
diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix
new file mode 100644
index 000000000000..c26a70737033
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/ipfs.nix
@@ -0,0 +1,111 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  inherit (pkgs) ipfs;
+
+  cfg = config.services.ipfs;
+
+  ipfsFlags = ''${if cfg.autoMigrate then "--migrate" else ""} ${if cfg.enableGC then "--enable-gc" else ""} ${toString cfg.extraFlags}'';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.ipfs = {
+
+      enable = mkEnableOption "Interplanetary File System";
+
+      user = mkOption {
+        type = types.str;
+        default = "ipfs";
+        description = "User under which the IPFS daemon runs";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "ipfs";
+        description = "Group under which the IPFS daemon runs";
+      };
+
+      dataDir = mkOption {
+        type = types.str;
+        default = "/var/lib/ipfs";
+        description = "The data dir for IPFS";
+      };
+
+      autoMigrate = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether IPFS should try to migrate the file system automatically.
+        '';
+      };
+
+      enableGC = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable automatic garbage collection.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        description = "Extra flags passed to the IPFS daemon";
+        default = [];
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.ipfs ];
+
+    users.extraUsers = mkIf (cfg.user == "ipfs") {
+      ipfs = {
+        group = cfg.group;
+        home = cfg.dataDir;
+        createHome = false;
+        uid = config.ids.uids.ipfs;
+        description = "IPFS daemon user";
+      };
+    };
+
+    users.extraGroups = mkIf (cfg.group == "ipfs") {
+      ipfs = {
+        gid = config.ids.gids.ipfs;
+      };
+    };
+
+    systemd.services.ipfs = {
+      description = "IPFS Daemon";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "local-fs.target" ];
+      path  = [ pkgs.ipfs pkgs.su pkgs.bash ];
+
+      preStart =
+        ''
+          install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.dataDir}
+          if [[ ! -d ${cfg.dataDir}/.ipfs ]]; then
+            cd ${cfg.dataDir}
+            ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c "${ipfs}/bin/ipfs init"
+          fi
+        '';
+
+      serviceConfig = {
+        ExecStart = "${ipfs}/bin/ipfs daemon ${ipfsFlags}";
+        User = cfg.user;
+        Group = cfg.group;
+        PermissionsStartOnly = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/network-filesystems/tahoe.nix b/nixos/modules/services/network-filesystems/tahoe.nix
index f1846b963252..f91827c379de 100644
--- a/nixos/modules/services/network-filesystems/tahoe.nix
+++ b/nixos/modules/services/network-filesystems/tahoe.nix
@@ -138,6 +138,45 @@ in
               '';
             };
             helper.enable = mkEnableOption "helper service";
+            sftpd.enable = mkEnableOption "SFTP service";
+            sftpd.port = mkOption {
+              default = null;
+              type = types.nullOr types.int;
+              description = ''
+                The port on which the SFTP server will listen.
+
+                This is the correct setting to tweak if you want Tahoe's SFTP
+                daemon to listen on a different port.
+              '';
+            };
+            sftpd.hostPublicKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the SSH host public key.
+              '';
+            };
+            sftpd.hostPrivateKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the SSH host private key.
+              '';
+            };
+            sftpd.accounts.file = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the accounts file.
+              '';
+            };
+            sftpd.accounts.url = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                URL of the accounts server.
+              '';
+            };
             package = mkOption {
               default = pkgs.tahoelafs;
               defaultText = "pkgs.tahoelafs";
@@ -256,6 +295,19 @@ in
 
                 [helper]
                 enabled = ${if settings.helper.enable then "true" else "false"}
+
+                [sftpd]
+                enabled = ${if settings.sftpd.enable then "true" else "false"}
+                ${optionalString (settings.sftpd.port != null)
+                  "port = ${toString settings.sftpd.port}"}
+                ${optionalString (settings.sftpd.hostPublicKeyFile != null)
+                  "host_pubkey_file = ${settings.sftpd.hostPublicKeyFile}"}
+                ${optionalString (settings.sftpd.hostPrivateKeyFile != null)
+                  "host_privkey_file = ${settings.sftpd.hostPrivateKeyFile}"}
+                ${optionalString (settings.sftpd.accounts.file != null)
+                  "accounts.file = ${settings.sftpd.accounts.file}"}
+                ${optionalString (settings.sftpd.accounts.url != null)
+                  "accounts.url = ${settings.sftpd.accounts.url}"}
               '';
             });
           # Actually require Tahoe, so that we will have it installed.
diff --git a/nixos/modules/services/network-filesystems/yandex-disk.nix b/nixos/modules/services/network-filesystems/yandex-disk.nix
index 982b6ca5ea7b..4de206641331 100644
--- a/nixos/modules/services/network-filesystems/yandex-disk.nix
+++ b/nixos/modules/services/network-filesystems/yandex-disk.nix
@@ -55,6 +55,15 @@ in
         description = "The directory to use for Yandex.Disk storage";
       };
 
+      excludes = mkOption {
+        default = "";
+        type = types.string;
+        example = "data,backup";
+        description = ''
+          Comma-separated list of directories which are excluded from synchronization.
+        '';
+      };
+
     };
 
   };
@@ -86,7 +95,7 @@ in
         chown ${u} ${dir}
 
         if ! test -d "${cfg.directory}" ; then
-          mkdir -p -m 755 ${cfg.directory} ||
+          (mkdir -p -m 755 ${cfg.directory} && chown ${u} ${cfg.directory}) ||
             exit 1
         fi
 
@@ -94,7 +103,7 @@ in
           -c '${pkgs.yandex-disk}/bin/yandex-disk token -p ${cfg.password} ${cfg.username} ${dir}/token'
 
         ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${u} \
-          -c '${pkgs.yandex-disk}/bin/yandex-disk start --no-daemon -a ${dir}/token -d ${cfg.directory}'
+          -c '${pkgs.yandex-disk}/bin/yandex-disk start --no-daemon -a ${dir}/token -d ${cfg.directory} --exclude-dirs=${cfg.excludes}'
       '';
 
     };
diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix
index 5e6847097a94..e72ea20cccee 100644
--- a/nixos/modules/services/networking/bitlbee.nix
+++ b/nixos/modules/services/networking/bitlbee.nix
@@ -7,11 +7,6 @@ let
   cfg = config.services.bitlbee;
   bitlbeeUid = config.ids.uids.bitlbee;
 
-  authModeCheck = v:
-    v == "Open" ||
-    v == "Closed" ||
-    v == "Registered";
-
   bitlbeeConfig = pkgs.writeText "bitlbee.conf"
     ''
     [settings]
@@ -67,7 +62,7 @@ in
 
       authMode = mkOption {
         default = "Open";
-        type = types.addCheck types.str authModeCheck;
+        type = types.enum [ "Open" "Closed" "Registered" ];
         description = ''
           The following authentication modes are available:
             Open -- Accept connections from anyone, use NickServ for user authentication.
diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix
index 5e15e40ea0c1..f50dae2ab7be 100644
--- a/nixos/modules/services/networking/cjdns.nix
+++ b/nixos/modules/services/networking/cjdns.nix
@@ -19,30 +19,21 @@ let
         type = types.str;
         description = "Public key at the opposite end of the tunnel.";
       };
-      hostname = mkOption {
-        default = "";
-        example = "foobar.hype";
-        type = types.str;
-        description = "Optional hostname to add to /etc/hosts; prevents reverse lookup failures.";
-      };
     };
   };
 
-  # Additional /etc/hosts entries for peers with an associated hostname
-  cjdnsExtraHosts = import (pkgs.runCommand "cjdns-hosts" {}
-    # Generate a builder that produces an output usable as a Nix string value
-    ''
-      exec >$out
-      echo \'\'
-      ${concatStringsSep "\n" (mapAttrsToList (k: v:
-          optionalString (v.hostname != "")
-            "echo $(${pkgs.cjdns}/bin/publictoip6 ${x.key}) ${x.host}")
-          (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))}
-      echo \'\'
-    '');
-
-  parseModules = x:
-    x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; };
+  # check for the required attributes, otherwise
+  # permit attributes not undefined here
+  checkPeers = x:
+    x // {
+      connectTo = mapAttrs
+        (name: value:
+          if !hasAttr "publicKey" value then abort "cjdns peer ${name} missing a publicKey" else
+          if !hasAttr "password"  value then abort "cjdns peer ${name} missing a password"  else
+          value
+        )
+      x.connectTo;
+    };
 
   # would be nice to  merge 'cfg' with a //,
   # but the json nesting is wacky.
@@ -53,8 +44,8 @@ let
     };
     authorizedPasswords = map (p: { password = p; }) cfg.authorizedPasswords;
     interfaces = {
-      ETHInterface = if (cfg.ETHInterface.bind != "") then [ (parseModules cfg.ETHInterface) ] else [ ];
-      UDPInterface = if (cfg.UDPInterface.bind != "") then [ (parseModules cfg.UDPInterface) ] else [ ];
+      ETHInterface = if (cfg.ETHInterface.bind != "") then [ (checkPeers cfg.ETHInterface) ] else [ ];
+      UDPInterface = if (cfg.UDPInterface.bind != "") then [ (checkPeers cfg.UDPInterface) ] else [ ];
     };
 
     privateKey = "@CJDNS_PRIVATE_KEY@";
@@ -134,12 +125,12 @@ in
           '';
          };
         connectTo = mkOption {
-          type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
+          type = types.attrsOf (types.attrsOf types.str);
           default = { };
           example = {
             "192.168.1.1:27313" = {
-              hostname = "homer.hype";
-              password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+              user      = "foobar";
+              password  = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
               publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
             };
           };
@@ -179,12 +170,12 @@ in
         };
 
         connectTo = mkOption {
-          type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
+          type = types.attrsOf (types.attrsOf types.str);
           default = { };
           example = {
             "01:02:03:04:05:06" = {
-              hostname = "homer.hype";
-              password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+              user      = "foobar";
+              password  = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
               publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
             };
           };
@@ -245,14 +236,15 @@ in
       serviceConfig = {
         Type = "forking";
         Restart = "on-failure";
-
+        CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW";
+        AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW";
+        ProtectSystem = "full";
+        MemoryDenyWriteExecute = true;
         ProtectHome = true;
         PrivateTmp = true;
       };
     };
 
-    networking.extraHosts = cjdnsExtraHosts;
-
     assertions = [
       { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null );
         message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined.";
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index 5a24db8ccba0..82bf178f4cb7 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -5,15 +5,25 @@ let
   apparmorEnabled = config.security.apparmor.enable;
   dnscrypt-proxy = pkgs.dnscrypt-proxy;
   cfg = config.services.dnscrypt-proxy;
+  stateDirectory = "/var/lib/dnscrypt-proxy";
 
   localAddress = "${cfg.localAddress}:${toString cfg.localPort}";
 
-  daemonArgs =
-    [ "--local-address=${localAddress}"
-      (optionalString cfg.tcpOnly "--tcp-only")
-      (optionalString cfg.ephemeralKeys "-E")
-    ]
-    ++ resolverArgs;
+  # The minisign public key used to sign the upstream resolver list.
+  # This is somewhat more flexible than preloading the key as an
+  # embedded string.
+  upstreamResolverListPubKey = pkgs.fetchurl {
+    url = https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/minisign.pub;
+    sha256 = "18lnp8qr6ghfc2sd46nn1rhcpr324fqlvgsp4zaigw396cd7vnnh";
+  };
+
+  # Internal flag indicating whether the upstream resolver list is used
+  useUpstreamResolverList = cfg.resolverList == null && cfg.customResolver == null;
+
+  resolverList =
+    if (cfg.resolverList != null)
+      then cfg.resolverList
+      else "${stateDirectory}/dnscrypt-resolvers.csv";
 
   resolverArgs = if (cfg.customResolver != null)
     then
@@ -22,9 +32,16 @@ let
         "--provider-key=${cfg.customResolver.key}"
       ]
     else
-      [ "--resolvers-list=${cfg.resolverList}"
-        "--resolver-name=${toString cfg.resolverName}"
+      [ "--resolvers-list=${resolverList}"
+        "--resolver-name=${cfg.resolverName}"
       ];
+
+  # The final command line arguments passed to the daemon
+  daemonArgs =
+    [ "--local-address=${localAddress}" ]
+    ++ optional cfg.tcpOnly "--tcp-only"
+    ++ optional cfg.ephemeralKeys "-E"
+    ++ resolverArgs;
 in
 
 {
@@ -66,24 +83,20 @@ in
         default = "dnscrypt.eu-nl";
         type = types.nullOr types.str;
         description = ''
-          The name of the upstream DNSCrypt resolver to use, taken from the
-          list named in the <literal>resolverList</literal> option.
-          The default resolver is located in Holland, supports DNS security
-          extensions, and claims to not keep logs.
+          The name of the upstream DNSCrypt resolver to use, taken from
+          <filename>${resolverList}</filename>.  The default resolver is
+          located in Holland, supports DNS security extensions, and
+          <emphasis>claims</emphasis> to not keep logs.
         '';
       };
 
       resolverList = mkOption {
+        default = null;
+        type = types.nullOr types.path;
         description = ''
-          The list of upstream DNSCrypt resolvers. By default, we use the most
-          recent list published by upstream.
+          List of DNSCrypt resolvers.  The default is to use the list of
+          public resolvers provided by upstream.
         '';
-        example = literalExample "${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv";
-        default = pkgs.fetchurl {
-          url = https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv;
-          sha256 = "1i9wzw4zl052h5nyp28bwl8d66cgj0awvjhw5wgwz0warkjl1g8g";
-        };
-        defaultText = "pkgs.fetchurl { url = ...; sha256 = ...; }";
       };
 
       customResolver = mkOption {
@@ -150,7 +163,7 @@ in
       }
     ];
 
-    security.apparmor.profiles = mkIf apparmorEnabled (singleton (pkgs.writeText "apparmor-dnscrypt-proxy" ''
+    security.apparmor.profiles = optional apparmorEnabled (pkgs.writeText "apparmor-dnscrypt-proxy" ''
       ${dnscrypt-proxy}/bin/dnscrypt-proxy {
         /dev/null rw,
         /dev/urandom r,
@@ -177,9 +190,9 @@ in
         ${getLib pkgs.lz4}/lib/liblz4.so.* mr,
         ${getLib pkgs.attr}/lib/libattr.so.* mr,
 
-        ${cfg.resolverList} r,
+        ${resolverList} r,
       }
-    ''));
+    '');
 
     users.users.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon user";
@@ -188,11 +201,61 @@ in
     };
     users.groups.dnscrypt-proxy = {};
 
+    systemd.services.init-dnscrypt-proxy-statedir = optionalAttrs useUpstreamResolverList {
+      description = "Initialize dnscrypt-proxy state directory";
+      script = ''
+        mkdir -pv ${stateDirectory}
+        chown -c dnscrypt-proxy:dnscrypt-proxy ${stateDirectory}
+        cp --preserve=timestamps -uv \
+          ${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv \
+          ${stateDirectory}
+      '';
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+      };
+    };
+
+    systemd.services.update-dnscrypt-resolvers = optionalAttrs useUpstreamResolverList {
+      description = "Update list of DNSCrypt resolvers";
+
+      requires = [ "init-dnscrypt-proxy-statedir.service" ];
+      after = [ "init-dnscrypt-proxy-statedir.service" ];
+
+      path = with pkgs; [ curl minisign ];
+      script = ''
+        cd ${stateDirectory}
+        curl -fSsL -o dnscrypt-resolvers.csv.tmp \
+          https://download.dnscrypt.org/dnscrypt-proxy/dnscrypt-resolvers.csv
+        curl -fSsL -o dnscrypt-resolvers.csv.minisig.tmp \
+          https://download.dnscrypt.org/dnscrypt-proxy/dnscrypt-resolvers.csv.minisig
+        mv dnscrypt-resolvers.csv.minisig{.tmp,}
+        minisign -q -V -p ${upstreamResolverListPubKey} \
+          -m dnscrypt-resolvers.csv.tmp -x dnscrypt-resolvers.csv.minisig
+        mv dnscrypt-resolvers.csv{.tmp,}
+      '';
+
+      serviceConfig = {
+        PrivateTmp = true;
+        PrivateDevices = true;
+        ProtectHome = true;
+        ProtectSystem = true;
+      };
+    };
+
+    systemd.timers.update-dnscrypt-resolvers = optionalAttrs useUpstreamResolverList {
+      timerConfig = {
+        OnBootSec = "5min";
+        OnUnitActiveSec = "6h";
+      };
+      wantedBy = [ "timers.target" ];
+    };
+
     systemd.sockets.dnscrypt-proxy = {
       description = "dnscrypt-proxy listening socket";
       socketConfig = {
-        ListenStream = "${localAddress}";
-        ListenDatagram = "${localAddress}";
+        ListenStream = localAddress;
+        ListenDatagram = localAddress;
       };
       wantedBy = [ "sockets.target" ];
     };
@@ -200,8 +263,13 @@ in
     systemd.services.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon";
 
-      after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service";
-      requires = [ "dnscrypt-proxy.socket "] ++ optional apparmorEnabled "apparmor.service";
+      after = [ "network.target" ]
+        ++ optional apparmorEnabled "apparmor.service"
+        ++ optional useUpstreamResolverList "init-dnscrypt-proxy-statedir.service";
+
+      requires = [ "dnscrypt-proxy.socket "]
+        ++ optional apparmorEnabled "apparmor.service"
+        ++ optional useUpstreamResolverList "init-dnscrypt-proxy-statedir.service";
 
       serviceConfig = {
         Type = "simple";
diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix
index 51f95af48029..fd4545e88e2d 100644
--- a/nixos/modules/services/networking/hostapd.nix
+++ b/nixos/modules/services/networking/hostapd.nix
@@ -86,7 +86,7 @@ in
 
       hwMode = mkOption {
         default = "g";
-        type = types.string;
+        type = types.enum [ "a" "b" "g" ];
         description = ''
           Operation mode.
           (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g).
@@ -152,9 +152,6 @@ in
   config = mkIf cfg.enable {
 
     assertions = [
-      { assertion = (cfg.hwMode == "a" || cfg.hwMode == "b" || cfg.hwMode == "g");
-        message = "hwMode must be a/b/g";
-      }
       { assertion = (cfg.channel >= 1 && cfg.channel <= 13);
         message = "channel must be between 1 and 13";
       }];
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index 926857a0ff4e..578376764eba 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -10,7 +10,7 @@ let
 
   extip = "EXTIP=\$(${pkgs.curl.bin}/bin/curl -sf \"http://jsonip.com\" | ${pkgs.gawk}/bin/awk -F'\"' '{print $4}')";
 
-  toYesNo = b: if b then "yes" else "no";
+  toYesNo = b: if b then "true" else "false";
 
   mkEndpointOpt = name: addr: port: {
     enable = mkEnableOption name;
@@ -31,6 +31,17 @@ let
     };
   };
 
+  mkKeyedEndpointOpt = name: addr: port: keyFile:
+  (mkEndpointOpt name addr port) // {
+    keys = mkOption {
+      type = types.str;
+      default = "";
+      description = ''
+        File to persist ${lib.toUpper name} keys.
+      '';
+    };
+  };
+
   commonTunOpts = let
     i2cpOpts = {
       length = mkOption {
@@ -63,19 +74,49 @@ let
     };
   } // mkEndpointOpt name "127.0.0.1" 0;
 
-  i2pdConf = pkgs.writeText "i2pd.conf" ''
-      ipv6 = ${toYesNo cfg.enableIPv6}
-      notransit = ${toYesNo cfg.notransit}
-      floodfill = ${toYesNo cfg.floodfill}
-      ${if isNull cfg.port then "" else "port = ${toString cfg.port}"}
-      ${flip concatMapStrings
-        (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
-        (proto: let portStr = toString proto.port; in ''
-      [${proto.name}]
-      address = ${proto.address}
-      port = ${toString proto.port}
-      enabled = ${toYesNo proto.enable}
-      '')
+  i2pdConf = pkgs.writeText "i2pd.conf"
+  ''
+  ipv4 = ${toYesNo cfg.enableIPv4}
+  ipv6 = ${toYesNo cfg.enableIPv6}
+  notransit = ${toYesNo cfg.notransit}
+  floodfill = ${toYesNo cfg.floodfill}
+  netid = ${toString cfg.netid}
+  ${if isNull cfg.bandwidth then "" else "bandwidth = ${toString cfg.bandwidth}" }
+  ${if isNull cfg.port then "" else "port = ${toString cfg.port}"}
+
+  [limits]
+  transittunnels = ${toString cfg.limits.transittunnels}
+
+  [upnp]
+  enabled = ${toYesNo cfg.upnp.enable}
+  name = ${cfg.upnp.name}
+
+  [precomputation]
+  elgamal = ${toYesNo cfg.precomputation.elgamal}
+
+  [reseed]
+  verify = ${toYesNo cfg.reseed.verify}
+  file = ${cfg.reseed.file}
+  urls = ${builtins.concatStringsSep "," cfg.reseed.urls}
+
+  [addressbook]
+  defaulturl = ${cfg.addressbook.defaulturl}
+  subscriptions = ${builtins.concatStringsSep "," cfg.addressbook.subscriptions}
+  ${flip concatMapStrings
+      (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
+      (proto: let portStr = toString proto.port; in
+        ''
+          [${proto.name}]
+          enabled = ${toYesNo proto.enable}
+          address = ${proto.address}
+          port = ${toString proto.port}
+          ${if proto ? keys then "keys = ${proto.keys}" else ""}
+          ${if proto ? auth then "auth = ${toYesNo proto.auth}" else ""}
+          ${if proto ? user then "user = ${proto.user}" else ""}
+          ${if proto ? pass then "pass = ${proto.pass}" else ""}
+          ${if proto ? outproxy then "outproxy = ${proto.outproxy}" else ""}
+          ${if proto ? outproxyPort then "outproxyport = ${toString proto.outproxyPort}" else ""}
+        '')
       }
   '';
 
@@ -114,7 +155,7 @@ let
   i2pdSh = pkgs.writeScriptBin "i2pd" ''
     #!/bin/sh
     ${if isNull cfg.extIp then extip else ""}
-    ${pkgs.i2pd}/bin/i2pd --log=1 \
+    ${pkgs.i2pd}/bin/i2pd \
       --host=${if isNull cfg.extIp then "$EXTIP" else cfg.extIp} \
       --conf=${i2pdConf} \
       --tunconf=${i2pdTunnelConf}
@@ -135,6 +176,8 @@ in
         default = false;
         description = ''
           Enables I2Pd as a running service upon activation.
+          Please read http://i2pd.readthedocs.io/en/latest/ for further
+          configuration help.
         '';
       };
 
@@ -162,6 +205,22 @@ in
         '';
       };
 
+      netid = mkOption {
+        type = types.int;
+        default = 2;
+        description = ''
+          I2P overlay netid.
+        '';
+      };
+
+      bandwidth = mkOption {
+        type = with types; nullOr int;
+        default = null;
+        description = ''
+           Set a router bandwidth limit integer in kbps or letters: L (32), O (256), P (2048), X (>9000)
+        '';
+      };
+
       port = mkOption {
         type = with types; nullOr int;
         default = null;
@@ -170,6 +229,14 @@ in
         '';
       };
 
+      enableIPv4 = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enables IPv4 connectivity. Enabled by default.
+        '';
+      };
+
       enableIPv6 = mkOption {
         type = types.bool;
         default = false;
@@ -178,16 +245,141 @@ in
         '';
       };
 
-      proto.http = mkEndpointOpt "http" "127.0.0.1" 7070;
+      upnp = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Enables UPnP.
+          '';
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "I2Pd";
+          description = ''
+            Name i2pd appears in UPnP forwardings list.
+          '';
+        };
+      };
+
+      precomputation.elgamal = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Use ElGamal precomputated tables.
+        '';
+      };
+
+      reseed = {
+        verify = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Request SU3 signature verification
+          '';
+        };
+
+        file = mkOption {
+          type = types.str;
+          default = "";
+          description = ''
+            Full path to SU3 file to reseed from
+          '';
+        };
+
+        urls = mkOption {
+          type = with types; listOf str;
+          default = [
+            "https://reseed.i2p-project.de/"
+            "https://i2p.mooo.com/netDb/"
+            "https://netdb.i2p2.no/"
+            "https://us.reseed.i2p2.no:444/"
+            "https://uk.reseed.i2p2.no:444/"
+            "https://i2p.manas.ca:8443/"
+          ];
+          description = ''
+            Reseed URLs
+          '';
+        };
+      };
+
+      addressbook = {
+       defaulturl = mkOption {
+          type = types.str;
+          default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
+          description = ''
+            AddressBook subscription URL for initial setup
+          '';
+        };
+       subscriptions = mkOption {
+          type = with types; listOf str;
+          default = [
+            "http://inr.i2p/export/alive-hosts.txt"
+            "http://i2p-projekt.i2p/hosts.txt"
+            "http://stats.i2p/cgi-bin/newhosts.txt"
+          ];
+          description = ''
+            AddressBook subscription URLs
+          '';
+        };
+      };
+
+      limits.transittunnels = mkOption {
+        type = types.int;
+        default = 2500;
+        description = ''
+          Maximum number of active transit sessions
+        '';
+      };
+
+      proto.http = (mkEndpointOpt "http" "127.0.0.1" 7070) // {
+        auth = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Enable authentication for webconsole.
+          '';
+        };
+        user = mkOption {
+          type = types.str;
+          default = "i2pd";
+          description = ''
+            Username for webconsole access
+          '';
+        };
+        pass = mkOption {
+          type = types.str;
+          default = "i2pd";
+          description = ''
+            Password for webconsole access.
+          '';
+        };
+      };
+
+      proto.httpProxy = mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4446 "";
+      proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "")
+      // {
+        outproxy = mkOption {
+          type = types.str;
+          default = "127.0.0.1";
+          description = "Upstream outproxy bind address.";
+        };
+        outproxyPort = mkOption {
+          type = types.int;
+          default = 4444;
+          description = "Upstream outproxy bind port.";
+        };
+      };
+
       proto.sam = mkEndpointOpt "sam" "127.0.0.1" 7656;
       proto.bob = mkEndpointOpt "bob" "127.0.0.1" 2827;
+      proto.i2cp = mkEndpointOpt "i2cp" "127.0.0.1" 7654;
       proto.i2pControl = mkEndpointOpt "i2pcontrol" "127.0.0.1" 7650;
-      proto.httpProxy = mkEndpointOpt "httpproxy" "127.0.0.1" 4446;
-      proto.socksProxy = mkEndpointOpt "socksproxy" "127.0.0.1" 4447;
 
       outTunnels = mkOption {
         default = {};
-        type = with types; loaOf (submodule ( 
+        type = with types; loaOf (submodule (
           { name, config, ... }: {
             options = commonTunOpts name;
             config = {
diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix
index dca8ccac7627..7eebecb23b00 100644
--- a/nixos/modules/services/networking/nntp-proxy.nix
+++ b/nixos/modules/services/networking/nntp-proxy.nix
@@ -148,11 +148,11 @@ in
       };
 
       verbosity = mkOption {
-        type = types.str;
+        type = types.enum [ "error" "warning" "notice" "info" "debug" ];
         default = "info";
         example = "error";
         description = ''
-          Verbosity level (error, warning, notice, info, debug)
+          Verbosity level
         '';
       };
 
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index 6af1dd736431..481e267f6c38 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -118,8 +118,8 @@ let
   '';
 
   yesOrNo = b: if b then "yes" else "no";
-  maybeString = prefix: x: if x == null then "" else ''${prefix} "${s}"'';
-  maybeToString = prefix: x: if x == null then "" else ''${prefix} ${toString s}'';
+  maybeString = prefix: x: if x == null then "" else ''${prefix} "${x}"'';
+  maybeToString = prefix: x: if x == null then "" else ''${prefix} ${toString x}'';
   forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
 
 
@@ -345,12 +345,10 @@ let
       };
 
       rrlWhitelist = mkOption {
-        type = types.listOf types.str;
+        type = with types; listOf (enum [ "nxdomain" "error" "referral" "any" "rrsig" "wildcard" "nodata" "dnskey" "positive" "all" ]);
         default = [];
         description = ''
           Whitelists the given rrl-types.
-          The RRL classification types are:  nxdomain,  error, referral, any,
-          rrsig, wildcard, nodata, dnskey, positive, all
         '';
       };
 
diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix
index 99269c49e8f1..3f0906fdb80d 100644
--- a/nixos/modules/services/networking/quassel.nix
+++ b/nixos/modules/services/networking/quassel.nix
@@ -3,8 +3,8 @@
 with lib;
 
 let
-  quassel = pkgs.kde4.quasselDaemon;
   cfg = config.services.quassel;
+  quassel = cfg.package;
   user = if cfg.user != null then cfg.user else "quassel";
 in
 
@@ -23,6 +23,15 @@ in
         '';
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.kde4.quasselDaemon;
+        description = ''
+          The package of the quassel daemon.
+        '';
+        example = pkgs.quasselDaemon;
+      };
+
       interfaces = mkOption {
         default = [ "127.0.0.1" ];
         description = ''
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
index ba913482e3cb..6ad18bb22403 100644
--- a/nixos/modules/services/networking/skydns.nix
+++ b/nixos/modules/services/networking/skydns.nix
@@ -11,7 +11,7 @@ in {
 
     etcd = {
       machines = mkOption {
-        default = [ "http://localhost:4001" ];
+        default = [ "http://127.0.0.1:2379" ];
         type = types.listOf types.str;
         description = "Skydns list of etcd endpoints to connect to.";
       };
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index 6084dbdbf78f..005655f111a1 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -221,7 +221,7 @@ in
         type = types.string;
         default = ''
           + FPing
-          binary = ${pkgs.fping}/bin/fping
+          binary = ${config.security.wrapperDir}/fping
         '';
         description = "Probe configuration";
       };
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index b26d30597b1f..f8e68fda7fc2 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -68,7 +68,7 @@ in
 
             interfaceType = mkOption {
               default = "tun";
-              type = types.addCheck types.str (n: n == "tun" || n == "tap");
+              type = types.enum [ "tun" "tap" ];
               description = ''
                 The type of virtual interface used for the network connection
               '';
diff --git a/nixos/modules/services/search/hound.nix b/nixos/modules/services/search/hound.nix
index 708f57a5eb7c..1226cba682ec 100644
--- a/nixos/modules/services/search/hound.nix
+++ b/nixos/modules/services/search/hound.nix
@@ -116,7 +116,7 @@ in {
                     " -conf ${pkgs.writeText "hound.json" cfg.config}";
 
       };
-      path = [ pkgs.git ];
+      path = [ pkgs.git pkgs.mercurial pkgs.openssh ];
     };
   };
 
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index e4e5c1253b77..b045e140546d 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -3,26 +3,37 @@ with lib;
 let
   clamavUser = "clamav";
   stateDir = "/var/lib/clamav";
-  runDir = "/var/run/clamav";
-  logDir = "/var/log/clamav";
+  runDir = "/run/clamav";
   clamavGroup = clamavUser;
   cfg = config.services.clamav;
+  pkg = pkgs.clamav;
+
   clamdConfigFile = pkgs.writeText "clamd.conf" ''
     DatabaseDirectory ${stateDir}
     LocalSocket ${runDir}/clamd.ctl
-    LogFile ${logDir}/clamav.log
     PidFile ${runDir}/clamd.pid
+    TemporaryDirectory /tmp
     User clamav
+    Foreground yes
 
     ${cfg.daemon.extraConfig}
   '';
-  pkg = pkgs.clamav.override { freshclamConf = cfg.updater.config; };
+
+  freshclamConfigFile = pkgs.writeText "freshclam.conf" ''
+    DatabaseDirectory ${stateDir}
+    Foreground yes
+    Checks ${toString cfg.updater.frequency}
+
+    ${cfg.updater.extraConfig}
+
+    DatabaseMirror database.clamav.net
+  '';
 in
 {
   options = {
     services.clamav = {
       daemon = {
-        enable = mkEnableOption "clamd daemon";
+        enable = mkEnableOption "ClamAV clamd daemon";
 
         extraConfig = mkOption {
           type = types.lines;
@@ -34,16 +45,27 @@ in
         };
       };
       updater = {
-        enable = mkEnableOption "freshclam updater";
+        enable = mkEnableOption "ClamAV freshclam updater";
 
         frequency = mkOption {
+          type = types.int;
           default = 12;
           description = ''
             Number of database checks per day.
           '';
         };
 
-        config = mkOption {
+        interval = mkOption {
+          type = types.str;
+          default = "hourly";
+          description = ''
+            How often freshclam is invoked. See systemd.time(7) for more
+            information about the format.
+          '';
+        };
+
+        extraConfig = mkOption {
+          type = types.lines;
           default = "";
           description = ''
             Extra configuration for freshclam. Contents will be added verbatim to the
@@ -68,50 +90,53 @@ in
       gid = config.ids.gids.clamav;
     };
 
-    services.clamav.updater.config = mkIf cfg.updater.enable ''
-      DatabaseDirectory ${stateDir}
-      Foreground yes
-      Checks ${toString cfg.updater.frequency}
-      DatabaseMirror database.clamav.net
-    '';
+    environment.etc."clamav/freshclam.conf".source = freshclamConfigFile;
+    environment.etc."clamav/clamd.conf".source = clamdConfigFile;
 
-    systemd.services.clamd = mkIf cfg.daemon.enable {
+    systemd.services.clamav-daemon = mkIf cfg.daemon.enable {
       description = "ClamAV daemon (clamd)";
-      path = [ pkg ];
-      after = [ "network.target" "freshclam.service" ];
-      requires = [ "freshclam.service" ];
+      after = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
+      requires = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
       wantedBy = [ "multi-user.target" ];
+      restartTriggers = [ clamdConfigFile ];
+
       preStart = ''
-        mkdir -m 0755 -p ${logDir}
         mkdir -m 0755 -p ${runDir}
-        chown ${clamavUser}:${clamavGroup} ${logDir}
         chown ${clamavUser}:${clamavGroup} ${runDir}
       '';
+
       serviceConfig = {
-        ExecStart = "${pkg}/bin/clamd --config-file=${clamdConfigFile}";
-        Type = "forking";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-        Restart = "on-failure";
-        RestartSec = "10s";
-        StartLimitInterval = "1min";
+        ExecStart = "${pkg}/bin/clamd";
+        ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
+        PrivateTmp = "yes";
+        PrivateDevices = "yes";
+        PrivateNetwork = "yes";
       };
     };
 
-    systemd.services.freshclam = mkIf cfg.updater.enable {
-      description = "ClamAV updater (freshclam)";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      path = [ pkg ];
+    systemd.timers.clamav-freshclam = mkIf cfg.updater.enable {
+      description = "Timer for ClamAV virus database updater (freshclam)";
+      wantedBy = [ "timers.target" ];
+      timerConfig = {
+        OnCalendar = cfg.updater.interval;
+        Unit = "clamav-freshclam.service";
+      };
+    };
+
+    systemd.services.clamav-freshclam = mkIf cfg.updater.enable {
+      description = "ClamAV virus database updater (freshclam)";
+      restartTriggers = [ freshclamConfigFile ];
+
       preStart = ''
         mkdir -m 0755 -p ${stateDir}
         chown ${clamavUser}:${clamavGroup} ${stateDir}
       '';
+
       serviceConfig = {
-        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";
-        StartLimitInterval = "1min";
+        Type = "oneshot";
+        ExecStart = "${pkg}/bin/freshclam";
+        PrivateTmp = "yes";
+        PrivateDevices = "yes";
       };
     };
   };
diff --git a/nixos/modules/services/web-servers/fcgiwrap.nix b/nixos/modules/services/web-servers/fcgiwrap.nix
index 2c5e433003c8..a64a187255a4 100644
--- a/nixos/modules/services/web-servers/fcgiwrap.nix
+++ b/nixos/modules/services/web-servers/fcgiwrap.nix
@@ -21,7 +21,7 @@ in {
       };
 
       socketType = mkOption {
-        type = types.addCheck types.str (t: t == "unix" || t == "tcp" || t == "tcp6");
+        type = types.enum [ "unix" "tcp" "tcp6" ];
         default = "unix";
         description = "Socket type: 'unix', 'tcp' or 'tcp6'.";
       };
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 166e5a6b2cea..698d37133d74 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -138,7 +138,7 @@ let
             server_name ${serverName} ${concatStringsSep " " vhost.serverAliases};
             ${acmeLocation}
             location / {
-              return 301 https://$host${optionalString (port != 443) ":${port}"}$request_uri;
+              return 301 https://$host${optionalString (port != 443) ":${toString port}"}$request_uri;
             }
           }
         ''}
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 31412ae70142..144e4aada277 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -19,7 +19,8 @@ in
   # E.g., if KDE is enabled, it supersedes xterm.
   imports = [
     ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix ./kde5.nix
-    ./lxqt.nix ./enlightenment.nix ./gnome3.nix ./kodi.nix
+    ./lumina.nix ./lxqt.nix ./enlightenment.nix ./gnome3.nix
+    ./kodi.nix
   ];
 
   options = {
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index bc010d1ce1cf..9b51b92faa4d 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -22,6 +22,15 @@ in
         description = "Enable the Plasma 5 (KDE 5) desktop environment.";
       };
 
+      enableQt4Support = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable support for Qt 4-based applications. Particularly, install the
+          Qt 4 version of the Breeze theme and a default backend for Phonon.
+        '';
+      };
+
     };
 
   };
@@ -105,7 +114,7 @@ in
         kde5.sonnet
         kde5.threadweaver
 
-        kde5.breeze
+        kde5.breeze-qt5
         kde5.kactivitymanagerd
         kde5.kde-cli-tools
         kde5.kdecoration
@@ -141,13 +150,12 @@ in
         kde5.konsole
         kde5.print-manager
 
-        # Oxygen icons moved to KDE Frameworks 5.16 and later.
-        (kde5.oxygen-icons or kde5.oxygen-icons5)
+        # Install Breeze icons if available
+        (kde5.breeze-icons or kde5.oxygen-icons5 or kde5.oxygen-icons)
         pkgs.hicolor_icon_theme
 
-        kde5.kde-gtk-config
+        kde5.kde-gtk-config kde5.breeze-gtk
 
-        pkgs.phonon-backend-gstreamer
         pkgs.qt5.phonon-backend-gstreamer
       ]
 
@@ -155,15 +163,14 @@ in
       # If it is not available, Orion is very similar to Breeze.
       ++ lib.optional (!(lib.hasAttr "breeze-gtk" kde5)) pkgs.orion
 
-      # Install Breeze icons if available
-      ++ lib.optional (lib.hasAttr "breeze-icons" kde5) kde5.breeze-icons
-
       # Install activity manager if available
       ++ lib.optional (lib.hasAttr "kactivitymanagerd" kde5) kde5.kactivitymanagerd
 
       # frameworkintegration was split with plasma-integration in Plasma 5.6
       ++ lib.optional (lib.hasAttr "plasma-integration" kde5) kde5.plasma-integration
 
+      ++ lib.optionals cfg.enableQt4Support [ kde5.breeze-qt4 pkgs.phonon-backend-gstreamer ]
+
       # Optional hardware support features
       ++ lib.optional config.hardware.bluetooth.enable kde5.bluedevil
       ++ lib.optional config.networking.networkmanager.enable kde5.plasma-nm
@@ -217,7 +224,6 @@ in
         kde5.ecm # for the setup-hook
         kde5.plasma-workspace
         kde5.breeze-icons
-        (kde5.oxygen-icons or kde5.oxygen-icons5)
       ];
     };
 
diff --git a/nixos/modules/services/x11/desktop-managers/lumina.nix b/nixos/modules/services/x11/desktop-managers/lumina.nix
new file mode 100644
index 000000000000..f0b31a2acb01
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/lumina.nix
@@ -0,0 +1,52 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.lumina;
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.lumina.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Enable the Lumina desktop manager";
+    };
+
+  };
+
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    services.xserver.desktopManager.session = singleton {
+      name = "lumina";
+      start = ''
+        exec ${pkgs.lumina}/bin/start-lumina-desktop
+      '';
+    };
+
+    environment.systemPackages = [
+      pkgs.fluxbox
+      pkgs.kde5.kwindowsystem
+      pkgs.kde5.oxygen-icons5
+      pkgs.lumina
+      pkgs.numlockx
+      pkgs.qt5.qtsvg
+      pkgs.xscreensaver
+    ];
+
+    # Link some extra directories in /run/current-system/software/share
+    environment.pathsToLink = [
+      "/share/desktop-directories"
+      "/share/icons"
+      "/share/lumina"
+      "/share"
+    ];
+
+  };
+}
diff --git a/nixos/modules/services/x11/desktop-managers/lxqt.nix b/nixos/modules/services/x11/desktop-managers/lxqt.nix
index d13b7352c95e..c385e74dbb2f 100644
--- a/nixos/modules/services/x11/desktop-managers/lxqt.nix
+++ b/nixos/modules/services/x11/desktop-managers/lxqt.nix
@@ -25,6 +25,7 @@ in
 
     services.xserver.desktopManager.session = singleton {
       name = "lxqt";
+      bgSupport = true;
       start = ''
         exec ${pkgs.lxqt.lxqt-common}/bin/startlxqt
       '';
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 36daf55a36a5..dda8d0f7629e 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -27,7 +27,6 @@ let
     ${cfg.stopScript}
   '';
 
-
   cfgFile = pkgs.writeText "sddm.conf" ''
     [General]
     HaltCommand=${pkgs.systemd}/bin/systemctl poweroff
@@ -47,7 +46,7 @@ let
     HideShells=/run/current-system/sw/bin/nologin
 
     [X11]
-    MinimumVT=${toString xcfg.tty}
+    MinimumVT=${toString (if xcfg.tty != null then xcfg.tty else 7)}
     ServerPath=${xserverWrapper}
     XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr
     SessionCommand=${dmcfg.session.script}
@@ -254,5 +253,10 @@ in
 
     users.extraGroups.sddm.gid = config.ids.gids.sddm;
 
+    services.dbus.packages = [ sddm.unwrapped ];
+
+    # To enable user switching, allow sddm to allocate TTYs/displays dynamically.
+    services.xserver.tty = null;
+    services.xserver.display = null;
   };
 }
diff --git a/nixos/modules/services/x11/window-managers/bspwm-unstable.nix b/nixos/modules/services/x11/window-managers/bspwm-unstable.nix
deleted file mode 100644
index 3282e0d0851f..000000000000
--- a/nixos/modules/services/x11/window-managers/bspwm-unstable.nix
+++ /dev/null
@@ -1,48 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.services.xserver.windowManager.bspwm-unstable;
-in
-
-{
-  options = {
-    services.xserver.windowManager.bspwm-unstable = {
-        enable = mkEnableOption "bspwm-unstable";
-        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-unstable}/bin/bspwm-session";
-            defaultText = "(pkgs.bspwm-unstable)/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-unstable";
-      start = if cfg.startThroughSession
-        then cfg.sessionScript
-        else ''
-            export _JAVA_AWT_WM_NONREPARENTING=1
-            SXHKD_SHELL=/bin/sh ${pkgs.sxhkd-unstable}/bin/sxhkd -f 100 &
-            ${pkgs.bspwm-unstable}/bin/bspwm
-        '';
-    };
-    environment.systemPackages = [ pkgs.bspwm-unstable ];
-  };
-}
diff --git a/nixos/modules/services/x11/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix
index 03a1b7a72e88..6783ac3479e6 100644
--- a/nixos/modules/services/x11/window-managers/bspwm.nix
+++ b/nixos/modules/services/x11/window-managers/bspwm.nix
@@ -9,40 +9,69 @@ in
 {
   options = {
     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.
+      enable = mkEnableOption "bspwm";
+
+      package = mkOption {
+        type        = types.package;
+        default     = pkgs.bspwm;
+        defaultText = "pkgs.bspwm";
+        example     = "pkgs.bspwm-unstable";
+        description = ''
+          bspwm package to use.
+        '';
+      };
+      configFile = mkOption {
+        type        = with types; nullOr path;
+        example     = "${pkgs.bspwm}/share/doc/bspwm/examples/bspwmrc";
+        default     = null;
+        description = ''
+          Path to the bspwm configuration file.
+          If null, $HOME/.config/bspwm/bspwmrc will be used.
+        '';
+      };
 
-                Does nothing unless `bspwm.startThroughSession` is enabled
-            ";
+      sxhkd = {
+        package = mkOption {
+          type        = types.package;
+          default     = pkgs.sxhkd;
+          defaultText = "pkgs.sxhkd";
+          example     = "pkgs.sxhkd-unstable";
+          description = ''
+            sxhkd package to use.
+          '';
         };
+        configFile = mkOption {
+          type        = with types; nullOr path;
+          example     = "${pkgs.bspwm}/share/doc/bspwm/examples/sxhkdrc";
+          default     = null;
+          description = ''
+            Path to the sxhkd configuration file.
+            If null, $HOME/.config/sxhkd/sxhkdrc will be used.
+          '';
+        };
+      };
     };
   };
 
   config = mkIf cfg.enable {
     services.xserver.windowManager.session = singleton {
-      name = "bspwm";
-      start = if cfg.startThroughSession
-        then cfg.sessionScript
-        else ''
-            export _JAVA_AWT_WM_NONREPARENTING=1
-            SXHKD_SHELL=/bin/sh ${pkgs.sxhkd}/bin/sxhkd -f 100 &
-            ${pkgs.bspwm}/bin/bspwm
-        '';
+      name  = "bspwm";
+      start = ''
+        export _JAVA_AWT_WM_NONREPARENTING=1
+        SXHKD_SHELL=/bin/sh ${cfg.sxhkd.package}/bin/sxhkd ${optionalString (cfg.sxhkd.configFile != null) "-c \"${cfg.sxhkd.configFile}\""} &
+        ${cfg.package}/bin/bspwm ${optionalString (cfg.configFile != null) "-c \"${cfg.configFile}\""}
+        waitPID=$!
+      '';
     };
-    environment.systemPackages = [ pkgs.bspwm ];
+    environment.systemPackages = [ cfg.package ];
   };
+
+  imports = [
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm-unstable" "enable" ]
+     "Use services.xserver.windowManager.bspwm.enable and set services.xserver.windowManager.bspwm.package to pkgs.bspwm-unstable to use the unstable version of bspwm.")
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm" "startThroughSession" ]
+     "bspwm package does not provide bspwm-session anymore.")
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm" "sessionScript" ]
+     "bspwm package does not provide bspwm-session anymore.")
+  ];
 }
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index dabe2c26a72f..f005decfa33c 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -10,7 +10,6 @@ in
   imports = [
     ./afterstep.nix
     ./bspwm.nix
-    ./bspwm-unstable.nix
     ./compiz.nix
     ./dwm.nix
     ./exwm.nix
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
index a8c7d4b3ee5e..59ecaf8d5a6d 100644
--- a/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -122,7 +122,7 @@ in
 
       mkdir -p /root/.ssh
       ${concatStrings (map (key: ''
-        echo -n ${escapeShellArg key} >> /root/.ssh/authorized_keys
+        echo ${escapeShellArg key} >> /root/.ssh/authorized_keys
       '') cfg.authorizedKeys)}
 
       dropbear -s -j -k -E -m -p ${toString cfg.port}
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 588e54a9d3a0..294fc1988e9f 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -324,8 +324,7 @@ in
 
       fsIdentifier = mkOption {
         default = "uuid";
-        type = types.addCheck types.str
-          (type: type == "uuid" || type == "label" || type == "provided");
+        type = types.enum [ "uuid" "label" "provided" ];
         description = ''
           Determines how GRUB will identify devices when generating the
           configuration file. A value of uuid / label signifies that grub
diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
index b7400e333e21..eb8ea6130972 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
+++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
@@ -33,7 +33,7 @@ in
 
     boot.loader.raspberryPi.version = mkOption {
       default = 2;
-      type = types.int;
+      type = types.enum [ 1 2 ];
       description = ''
       '';
     };
@@ -44,10 +44,5 @@ in
     system.build.installBootLoader = builder;
     system.boot.loader.id = "raspberrypi";
     system.boot.loader.kernelFile = platform.kernelTarget;
-    assertions = [
-      { assertion = (cfg.version == 1 || cfg.version == 2);
-        message = "loader.raspberryPi.version should be 1 or 2";
-      }
-    ];
   };
 }
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index aae4dc5fdadf..aaa78daeb3a3 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -245,7 +245,7 @@ let
 
       virtualType = mkOption {
         default = null;
-        type = types.nullOr (types.addCheck types.str (v: v == "tun" || v == "tap"));
+        type = with types; nullOr (enum [ "tun" "tap" ]);
         description = ''
           The explicit type of interface to create. Accepts tun or tap strings.
           Also accepts null to implicitly detect the type of device.
@@ -782,13 +782,12 @@ in
           };
 
           type = mkOption {
-            type = types.string;
+            type = types.enum [ "managed" "ibss" "monitor" "mesh" "wds" ];
             default = "managed";
             example = "ibss";
             description = ''
-              The type of the WLAN interface. The type has to be either <literal>managed</literal>,
-              <literal>ibss</literal>, <literal>monitor</literal>, <literal>mesh</literal> or <literal>wds</literal>.
-              Also, the type has to be supported by the underlying hardware of the device.
+              The type of the WLAN interface.
+              The type has to be supported by the underlying hardware of the device.
             '';
           };
 
@@ -799,17 +798,11 @@ in
           };
 
           flags = mkOption {
-            type = types.nullOr types.string;
+            type = with types; nullOr (enum [ "none" "fcsfail" "control" "otherbss" "cook" "active" ]);
             default = null;
             example = "control";
             description = ''
-              Flags for interface of type <literal>monitor</literal>. The valid flags are:
-              none:     no special flags
-              fcsfail:  show frames with FCS errors
-              control:  show control frames
-              otherbss: show frames from other BSSes
-              cook:     use cooked mode
-              active:   use active mode (ACK incoming unicast packets)
+              Flags for interface of type <literal>monitor</literal>.
             '';
           };
 
diff --git a/nixos/modules/virtualisation/grow-partition.nix b/nixos/modules/virtualisation/grow-partition.nix
index abc2e766959e..5039118d78ee 100644
--- a/nixos/modules/virtualisation/grow-partition.nix
+++ b/nixos/modules/virtualisation/grow-partition.nix
@@ -24,7 +24,7 @@ with lib;
       copy_bin_and_libs ${pkgs.gnused}/bin/sed
       copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
       copy_bin_and_libs ${pkgs.utillinux}/sbin/lsblk
-      cp -v ${pkgs.cloud-utils}/bin/growpart $out/bin/growpart
+      cp -v ${pkgs.cloud-utils}/bin/.growpart-wrapped $out/bin/growpart
       ln -s sed $out/bin/gnused
     '';
 
diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix
index ea503a9526f8..5f669dee7545 100644
--- a/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixos/modules/virtualisation/libvirtd.nix
@@ -123,7 +123,7 @@ in {
         # config file. But this path can unfortunately be garbage collected
         # while still being used by the virtual machine. So update the
         # emulator path on each startup to something valid (re-scan $PATH).
-        for file in /etc/libvirt/qemu/*.xml /etc/libvirt/lxc/*.xml; do
+        for file in /var/lib/libvirt/qemu/*.xml /var/lib/libvirt/lxc/*.xml; do
             test -f "$file" || continue
             # get (old) emulator path from config file
             emulator=$(grep "^[[:space:]]*<emulator>" "$file" | sed 's,^[[:space:]]*<emulator>\(.*\)</emulator>.*,\1,')
diff --git a/nixos/modules/virtualisation/vmware-guest.nix b/nixos/modules/virtualisation/vmware-guest.nix
index b9a4f3b11dc1..ac5f87817fe9 100644
--- a/nixos/modules/virtualisation/vmware-guest.nix
+++ b/nixos/modules/virtualisation/vmware-guest.nix
@@ -5,6 +5,7 @@ with lib;
 let
   cfg = config.services.vmwareGuest;
   open-vm-tools = pkgs.open-vm-tools;
+  xf86inputvmmouse = pkgs.xorg.xf86inputvmmouse;
 in
 {
   options = {
@@ -29,18 +30,17 @@ in
 
     services.xserver = {
       videoDrivers = mkOverride 50 [ "vmware" ];
+      modules = [ xf86inputvmmouse ];
 
       config = ''
-          Section "InputDevice"
+          Section "InputClass"
             Identifier "VMMouse"
+            MatchDevicePath "/dev/input/event*"
+            MatchProduct "ImPS/2 Generic Wheel Mouse"
             Driver "vmmouse"
           EndSection
         '';
 
-      serverLayoutSection = ''
-          InputDevice "VMMouse"
-        '';
-
       displayManager.sessionCommands = ''
           ${open-vm-tools}/bin/vmware-user-suid-wrapper
         '';
diff --git a/nixos/release.nix b/nixos/release.nix
index fbd3efd16ff0..639ee45b38d6 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -275,6 +275,7 @@ in rec {
   tests.networkingProxy = callTest tests/networking-proxy.nix {};
   tests.nfs3 = callTest tests/nfs.nix { version = 3; };
   tests.nfs4 = callTest tests/nfs.nix { version = 4; };
+  tests.leaps = callTest tests/leaps.nix { };
   tests.nsd = callTest tests/nsd.nix {};
   tests.openssh = callTest tests/openssh.nix {};
   #tests.panamax = hydraJob (import tests/panamax.nix { system = "x86_64-linux"; });
diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix
index 9a6414f81c39..55b1fb5a7222 100644
--- a/nixos/tests/chromium.nix
+++ b/nixos/tests/chromium.nix
@@ -118,7 +118,7 @@ mapAttrs (channel: chromiumPkg: makeTest rec {
       "ulimit -c unlimited; ".
       "chromium $args \"$url\" & disown"
     );
-    $machine->waitForText(qr/Type to search or enter a URL to navigate/);
+    $machine->waitForText(qr/startup done/);
     $machine->waitUntilSucceeds("${xdo "check-startup" ''
       search --sync --onlyvisible --name "startup done"
       # close first start help popup
diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix
index f61c82b916ad..f32ec52dfc26 100644
--- a/nixos/tests/cjdns.nix
+++ b/nixos/tests/cjdns.nix
@@ -54,7 +54,7 @@ import ./make-test.nix ({ pkgs, ...} : {
           services.cjdns =
             { UDPInterface =
                 { bind = "0.0.0.0:1024";
-                  connectTo."192.168.0.1:1024}" =
+                  connectTo."192.168.0.1:1024" =
                     { password = carolPassword;
                       publicKey = carolPubKey;
                     };
diff --git a/nixos/tests/dnscrypt-proxy.nix b/nixos/tests/dnscrypt-proxy.nix
index b686e9582a7d..26409949ec62 100644
--- a/nixos/tests/dnscrypt-proxy.nix
+++ b/nixos/tests/dnscrypt-proxy.nix
@@ -22,8 +22,6 @@ import ./make-test.nix ({ pkgs, ... }: {
   };
 
   testScript = ''
-    $client->start;
-    $client->waitForUnit("sockets.target");
     $client->waitForUnit("dnsmasq");
 
     # The daemon is socket activated; sending a single ping should activate it.
diff --git a/nixos/tests/leaps.nix b/nixos/tests/leaps.nix
new file mode 100644
index 000000000000..3c390e1a1691
--- /dev/null
+++ b/nixos/tests/leaps.nix
@@ -0,0 +1,29 @@
+import ./make-test.nix ({ pkgs,  ... }:
+
+{
+  name = "leaps";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ qknight ];
+  };
+
+  nodes =
+    { 
+      client = { };
+
+      server =
+        { services.leaps = {
+            enable = true;
+            port = 6666;
+            path = "/leaps/";
+          };
+          networking.firewall.enable = false;
+        };
+    };
+
+  testScript =
+    ''
+      startAll;
+      $server->waitForOpenPort(6666);
+      $client->succeed("curl http://server:6666/leaps/ | grep -i 'leaps'"); 
+    '';
+})