summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/configuration/configuration.xml10
-rw-r--r--nixos/doc/manual/default.nix17
-rw-r--r--nixos/doc/manual/development/meta-attributes.xml62
-rw-r--r--nixos/doc/manual/development/writing-modules.xml1
-rw-r--r--nixos/doc/manual/release-notes/release-notes.xml1
-rw-r--r--nixos/doc/manual/release-notes/rl-1603.xml35
-rw-r--r--nixos/doc/manual/release-notes/rl-1609.xml24
-rw-r--r--nixos/doc/manual/release-notes/rl-1703.xml46
-rw-r--r--nixos/lib/utils.nix9
-rw-r--r--nixos/modules/config/fonts/fonts.nix2
-rw-r--r--nixos/modules/config/gnu.nix1
-rw-r--r--nixos/modules/config/pulseaudio.nix2
-rw-r--r--nixos/modules/config/swap.nix8
-rw-r--r--nixos/modules/config/system-path.nix2
-rw-r--r--nixos/modules/config/update-users-groups.pl4
-rw-r--r--nixos/modules/i18n/input-method/default.nix5
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh12
-rw-r--r--nixos/modules/misc/meta.nix8
-rw-r--r--nixos/modules/misc/nixpkgs.nix5
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/programs/zsh/zsh.nix5
-rw-r--r--nixos/modules/rename.nix66
-rw-r--r--nixos/modules/security/acme.nix7
-rw-r--r--nixos/modules/security/audit.nix16
-rw-r--r--nixos/modules/security/grsecurity.nix7
-rw-r--r--nixos/modules/security/grsecurity.xml (renamed from nixos/doc/manual/configuration/grsecurity.xml)0
-rw-r--r--nixos/modules/security/hidepid.nix19
-rw-r--r--nixos/modules/security/setuid-wrappers.nix35
-rw-r--r--nixos/modules/services/databases/postgresql.nix6
-rw-r--r--nixos/modules/services/databases/redis.nix5
-rw-r--r--nixos/modules/services/desktops/accountsservice.nix8
-rw-r--r--nixos/modules/services/editors/emacs.nix2
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix2
-rw-r--r--nixos/modules/services/misc/gitit.nix2
-rw-r--r--nixos/modules/services/misc/gitlab.nix41
-rw-r--r--nixos/modules/services/misc/gitlab.xml17
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix2
-rw-r--r--nixos/modules/services/misc/nixos-manual.nix2
-rw-r--r--nixos/modules/services/misc/taskserver/default.nix3
-rw-r--r--nixos/modules/services/networking/cjdns.nix2
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix48
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.xml76
-rw-r--r--nixos/modules/services/networking/ferm.nix63
-rw-r--r--nixos/modules/services/networking/mjpg-streamer.nix8
-rw-r--r--nixos/modules/services/networking/quagga.nix187
-rw-r--r--nixos/modules/services/networking/teamspeak3.nix75
-rw-r--r--nixos/modules/services/networking/unbound.nix10
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix99
-rw-r--r--nixos/modules/services/networking/zerotierone.nix16
-rw-r--r--nixos/modules/services/printing/cupsd.nix6
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix2
-rw-r--r--nixos/modules/services/web-servers/nginx/location-options.nix21
-rw-r--r--nixos/modules/services/x11/desktop-managers/enlightenment.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix3
-rw-r--r--nixos/modules/system/activation/activation-script.nix12
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix17
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl15
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh26
-rw-r--r--nixos/modules/system/boot/stage-1.nix32
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh36
-rw-r--r--nixos/modules/system/boot/stage-2.nix3
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix2
-rw-r--r--nixos/modules/tasks/cpu-freq.nix2
-rw-r--r--nixos/modules/tasks/encrypted-devices.nix2
-rw-r--r--nixos/modules/tasks/filesystems.nix111
-rw-r--r--nixos/modules/tasks/filesystems/zfs.nix8
-rw-r--r--nixos/modules/virtualisation/amazon-grow-partition.nix24
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix4
-rw-r--r--nixos/modules/virtualisation/brightbox-image.nix2
-rw-r--r--nixos/modules/virtualisation/containers.nix29
-rw-r--r--nixos/modules/virtualisation/grow-partition.nix43
-rw-r--r--nixos/modules/virtualisation/qemu-opts4
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix11
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix28
-rw-r--r--nixos/release.nix2
-rw-r--r--nixos/tests/boot-stage1.nix1
-rw-r--r--nixos/tests/ferm.nix72
-rw-r--r--nixos/tests/postgis.nix30
-rw-r--r--nixos/tests/quagga.nix97
-rw-r--r--nixos/tests/virtualbox.nix11
80 files changed, 1316 insertions, 427 deletions
diff --git a/nixos/doc/manual/configuration/configuration.xml b/nixos/doc/manual/configuration/configuration.xml
index 26f8ebad7344..448e2a932e91 100644
--- a/nixos/doc/manual/configuration/configuration.xml
+++ b/nixos/doc/manual/configuration/configuration.xml
@@ -23,16 +23,10 @@ effect after you run <command>nixos-rebuild</command>.</para>
 <xi:include href="x-windows.xml" />
 <xi:include href="networking.xml" />
 <xi:include href="linux-kernel.xml" />
-<xi:include href="grsecurity.xml" />
 
-<!-- FIXME: auto-include NixOS module docs -->
-<xi:include href="postgresql.xml" />
-<xi:include href="gitlab.xml" />
-<xi:include href="taskserver.xml" />
-<xi:include href="acme.xml" />
-<xi:include href="input-methods.xml" />
-<xi:include href="emacs.xml" />
+<xi:include href="modules.xml" xpointer="xpointer(//section[@id='modules']/*)" />
 
 <!-- Apache; libvirtd virtualisation -->
 
 </part>
+
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix
index 2592766ee496..13668dfd8ebc 100644
--- a/nixos/doc/manual/default.nix
+++ b/nixos/doc/manual/default.nix
@@ -1,4 +1,4 @@
-{ pkgs, options, version, revision, extraSources ? [] }:
+{ pkgs, options, config, version, revision, extraSources ? [] }:
 
 with pkgs;
 
@@ -51,16 +51,19 @@ let
 
   sources = lib.sourceFilesBySuffices ./. [".xml"];
 
+  modulesDoc = builtins.toFile "modules.xml" ''
+    <section xmlns:xi="http://www.w3.org/2001/XInclude" id="modules">
+    ${(lib.concatMapStrings (path: ''
+      <xi:include href="${path}" />
+    '') (lib.catAttrs "value" config.meta.doc))}
+    </section>
+  '';
+
   copySources =
     ''
       cp -prd $sources/* . # */
       chmod -R u+w .
-      cp ${../../modules/services/databases/postgresql.xml} configuration/postgresql.xml
-      cp ${../../modules/services/misc/gitlab.xml} configuration/gitlab.xml
-      cp ${../../modules/services/misc/taskserver/doc.xml} configuration/taskserver.xml
-      cp ${../../modules/security/acme.xml} configuration/acme.xml
-      cp ${../../modules/i18n/input-method/default.xml} configuration/input-methods.xml
-      cp ${../../modules/services/editors/emacs.xml} configuration/emacs.xml
+      ln -s ${modulesDoc} configuration/modules.xml
       ln -s ${optionsDocBook} options-db.xml
       echo "${version}" > version
     '';
diff --git a/nixos/doc/manual/development/meta-attributes.xml b/nixos/doc/manual/development/meta-attributes.xml
new file mode 100644
index 000000000000..de0870314dcb
--- /dev/null
+++ b/nixos/doc/manual/development/meta-attributes.xml
@@ -0,0 +1,62 @@
+<section xmlns="http://docbook.org/ns/docbook"
+        xmlns:xlink="http://www.w3.org/1999/xlink"
+        xmlns:xi="http://www.w3.org/2001/XInclude"
+        version="5.0"
+        xml:id="sec-meta-attributes">
+
+<title>Meta Attributes</title>
+
+<para>Like Nix packages, NixOS modules can declare meta-attributes to provide
+  extra information. Module meta attributes are defined in the
+  <filename
+    xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/meta.nix">meta.nix</filename>
+  special module.</para>
+
+<para><literal>meta</literal> is a top level attribute like
+  <literal>options</literal> and <literal>config</literal>. Available
+  meta-attributes are <literal>maintainers</literal> and
+  <literal>doc</literal>.</para>
+
+<para>Each of the meta-attributes must be defined at most once per module
+  file.</para>
+
+<programlisting>
+{ config, lib, pkgs, ... }:
+{
+  options = {
+    ...
+  };
+
+  config = {
+    ...
+  };
+
+  meta = {
+    maintainers = with lib.maintainers; [ ericsagnes ]; <co
+      xml:id='modules-meta-1' />
+    doc = ./default.xml; <co xml:id='modules-meta-2' />
+  };
+}
+</programlisting>
+
+<calloutlist>
+ <callout arearefs='modules-meta-1'>
+  <para>
+    <varname>maintainers</varname> contains a list of the module maintainers.
+  </para>
+ </callout>
+
+ <callout arearefs='modules-meta-2'>
+  <para>
+    <varname>doc</varname> points to a valid DocBook file containing the module
+    documentation. Its contents is automatically added to <xref
+      linkend="ch-configuration"/>.
+    Changes to a module documentation have to be checked to not break
+    building the NixOS manual:
+  </para>
+  <programlisting>$ nix-build nixos/release.nix -A manual</programlisting>
+ </callout>
+
+</calloutlist>
+
+</section>
diff --git a/nixos/doc/manual/development/writing-modules.xml b/nixos/doc/manual/development/writing-modules.xml
index 971e586f20bd..a68b122ce022 100644
--- a/nixos/doc/manual/development/writing-modules.xml
+++ b/nixos/doc/manual/development/writing-modules.xml
@@ -177,5 +177,6 @@ in {
 
 <xi:include href="option-declarations.xml" />
 <xi:include href="option-def.xml" />
+<xi:include href="meta-attributes.xml" />
 
 </chapter>
diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml
index 31a7ae04a4f5..20d3f74f94b4 100644
--- a/nixos/doc/manual/release-notes/release-notes.xml
+++ b/nixos/doc/manual/release-notes/release-notes.xml
@@ -9,6 +9,7 @@
 <para>This section lists the release notes for each stable version of NixOS
 and current unstable revision.</para>
 
+<xi:include href="rl-1703.xml" />
 <xi:include href="rl-1609.xml" />
 <xi:include href="rl-1603.xml" />
 <xi:include href="rl-1509.xml" />
diff --git a/nixos/doc/manual/release-notes/rl-1603.xml b/nixos/doc/manual/release-notes/rl-1603.xml
index c51316bd2808..f460e00e836e 100644
--- a/nixos/doc/manual/release-notes/rl-1603.xml
+++ b/nixos/doc/manual/release-notes/rl-1603.xml
@@ -385,6 +385,41 @@ services.syncthing = {
       the github issue</link>.
     </para>
   </listitem>
+
+  <listitem>
+    <para>
+      The <literal>services.xserver.startGnuPGAgent</literal> option has been removed.
+      GnuPG 2.1.x changed the way the gpg-agent works, and that new approach no
+      longer requires (or even supports) the "start everything as a child of the
+      agent" scheme we've implemented in NixOS for older versions.
+      To configure the gpg-agent for your X session, add the following code to
+      <filename>~/.bashrc</filename> or some file that’s sourced when your shell is started:
+    <programlisting>
+GPG_TTY=$(tty)
+export GPG_TTY
+    </programlisting>
+      If you want to use gpg-agent for SSH, too, add the following to your session
+      initialization (e.g. <literal>displayManager.sessionCommands</literal>)
+    <programlisting>
+gpg-connect-agent /bye
+unset SSH_AGENT_PID
+export SSH_AUTH_SOCK="''${HOME}/.gnupg/S.gpg-agent.ssh"
+    </programlisting>
+      and make sure that
+    <programlisting>
+enable-ssh-support
+    </programlisting>
+      is included in your <filename>~/.gnupg/gpg-agent.conf</filename>.
+      You will need to use <command>ssh-add</command> to re-add your ssh keys.
+      If gpg’s automatic transformation of the private keys to the new format fails,
+      you will need to re-import your private keyring as well:
+    <programlisting>
+gpg --import ~/.gnupg/secring.gpg
+    </programlisting>
+    The <command>gpg-agent(1)</command> man page has more details about this subject,
+    i.e. in the "EXAMPLES" section.
+    </para>
+  </listitem>
 </itemizedlist>
 
 
diff --git a/nixos/doc/manual/release-notes/rl-1609.xml b/nixos/doc/manual/release-notes/rl-1609.xml
index 1245411be179..70759ee25f86 100644
--- a/nixos/doc/manual/release-notes/rl-1609.xml
+++ b/nixos/doc/manual/release-notes/rl-1609.xml
@@ -35,6 +35,17 @@ following incompatible changes:</para>
 <itemizedlist>
 
   <listitem>
+    <para>A large number of packages have been converted to use the multiple outputs feature
+      of Nix to greatly reduce the amount of required disk space. This may require changes
+      to any custom packages to make them build again; see the relevant chapter in the
+      Nixpkgs manual for more information. (Additional caveat to packagers: some packaging conventions
+      related to multiple-output packages
+      <link xlink:href="https://github.com/NixOS/nixpkgs/pull/14766">were changed</link>
+      late (August 2016) in the release cycle and differ from the initial introduction of multiple outputs.)
+    </para>
+  </listitem>
+
+  <listitem>
     <para>Shell aliases for systemd sub-commands
     <link xlink:href="https://github.com/NixOS/nixpkgs/pull/15598">were dropped</link>:
     <command>start</command>, <command>stop</command>,
@@ -47,6 +58,14 @@ following incompatible changes:</para>
   </listitem>
 
   <listitem>
+    <para>/var/setuid-wrappers/
+      <link xlink:href="https://github.com/NixOS/nixpkgs/pull/18124">is now a symlink so
+      it can be atomically updated</link>
+      and it's not mounted as tmpfs anymore since setuid binaries are located on /run/ as tmpfs.
+    </para>
+  </listitem>
+
+  <listitem>
     <para>Gitlab's maintainence script gitlab-runner was removed and split up into the more clearer
       gitlab-run and gitlab-rake scripts because gitlab-runner is a component of Gitlab CI.</para>
   </listitem>
@@ -66,6 +85,11 @@ following incompatible changes:</para>
     <literal>environment.variables</literal>.</para>
   </listitem>
 
+  <listitem>
+    <para>The <literal>audit</literal> service is no longer enabled by default.
+    Use <literal>security.audit.enable = true;</literal> to explicitly enable it.</para>
+  </listitem>
+
 </itemizedlist>
 
 
diff --git a/nixos/doc/manual/release-notes/rl-1703.xml b/nixos/doc/manual/release-notes/rl-1703.xml
new file mode 100644
index 000000000000..c0fa4388a2ad
--- /dev/null
+++ b/nixos/doc/manual/release-notes/rl-1703.xml
@@ -0,0 +1,46 @@
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-release-17.03">
+
+<title>Release 17.03 (“XXX”, 2017/03/??)</title>
+
+<para>In addition to numerous new and upgraded packages, this release
+has the following highlights: </para>
+
+<itemizedlist>
+  <listitem>
+    <para></para>
+  </listitem>
+</itemizedlist>
+
+<para>The following new services were added since the last release:</para>
+
+<itemizedlist>
+  <listitem>
+    <para></para>
+  </listitem>
+</itemizedlist>
+
+
+<para>When upgrading from a previous release, please be aware of the
+following incompatible changes:</para>
+
+<itemizedlist>
+  <listitem>
+    <para></para>
+  </listitem>
+</itemizedlist>
+
+
+<para>Other notable improvements:</para>
+
+<itemizedlist>
+  <listitem>
+    <para></para>
+  </listitem>
+</itemizedlist>
+
+
+</section>
diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix
index 40d0854d968d..1ef915d40612 100644
--- a/nixos/lib/utils.nix
+++ b/nixos/lib/utils.nix
@@ -2,6 +2,15 @@ pkgs: with pkgs.lib;
 
 rec {
 
+  # Check whenever fileSystem is needed for boot
+  fsNeededForBoot = fs: fs.neededForBoot
+                     || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ];
+
+  # Check whenever `b` depends on `a` as a fileSystem
+  # FIXME: it's incorrect to simply use hasPrefix here: "/dev/a" is not a parent of "/dev/ab"
+  fsBefore = a: b: ((any (x: elem x [ "bind" "move" ]) b.options) && (a.mountPoint == b.device))
+                || (hasPrefix a.mountPoint b.mountPoint);
+
   # Escape a path according to the systemd rules, e.g. /dev/xyzzy
   # becomes dev-xyzzy.  FIXME: slow.
   escapeSystemdPath = s:
diff --git a/nixos/modules/config/fonts/fonts.nix b/nixos/modules/config/fonts/fonts.nix
index ea0a67038572..f913b8c33e56 100644
--- a/nixos/modules/config/fonts/fonts.nix
+++ b/nixos/modules/config/fonts/fonts.nix
@@ -22,7 +22,7 @@ with lib;
   config = {
 
     fonts.fonts =
-      [ pkgs.xorg.fontbhttf
+      [
         pkgs.xorg.fontbhlucidatypewriter100dpi
         pkgs.xorg.fontbhlucidatypewriter75dpi
         pkgs.dejavu_fonts
diff --git a/nixos/modules/config/gnu.nix b/nixos/modules/config/gnu.nix
index ad0e35c8a63f..f8c35b440d12 100644
--- a/nixos/modules/config/gnu.nix
+++ b/nixos/modules/config/gnu.nix
@@ -37,6 +37,7 @@ with lib;
     services.openssh.enable = false;
     services.lshd.enable = true;
     programs.ssh.startAgent = false;
+    services.xserver.startGnuPGAgent = true;
 
     # TODO: GNU dico.
     # TODO: GNU Inetutils' inetd.
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index 71ac3f9a72c4..06ce52004202 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -34,7 +34,7 @@ let
         ${addModuleIf cfg.zeroconf.publish.enable "module-zeroconf-publish"}
         ${addModuleIf cfg.zeroconf.discovery.enable "module-zeroconf-discover"}
         ${addModuleIf cfg.tcp.enable (concatStringsSep " "
-           ([ "load-module module-native-protocol-tcp" ] ++ allAnon ++ ipAnon))}
+           ([ "module-native-protocol-tcp" ] ++ allAnon ++ ipAnon))}
         ${cfg.extraConfig}
       '';
     };
diff --git a/nixos/modules/config/swap.nix b/nixos/modules/config/swap.nix
index 62b6e011713e..e57ed2565a10 100644
--- a/nixos/modules/config/swap.nix
+++ b/nixos/modules/config/swap.nix
@@ -54,6 +54,10 @@ let
           WARNING: Don't try to hibernate when you have at least one swap partition with
           this option enabled! We have no way to set the partition into which hibernation image
           is saved, so if your image ends up on an encrypted one you would lose it!
+
+          WARNING #2: Do not use /dev/disk/by-uuid/… or /dev/disk/by-label/… as your swap device
+          when using randomEncryption as the UUIDs and labels will get erased on every boot when
+          the partition is encrypted. Best to use /dev/disk/by-partuuid/…
         '';
       };
 
@@ -72,7 +76,7 @@ let
     config = rec {
       device = mkIf options.label.isDefined
         "/dev/disk/by-label/${config.label}";
-      deviceName = escapeSystemdPath config.device;
+      deviceName = lib.replaceChars ["\\"] [""] (escapeSystemdPath config.device);
       realDevice = if config.randomEncryption then "/dev/mapper/${deviceName}" else config.device;
     };
 
@@ -121,6 +125,8 @@ in
 
         createSwapDevice = sw:
           assert sw.device != "";
+          assert !(sw.randomEncryption && lib.hasPrefix "/dev/disk/by-uuid"  sw.device);
+          assert !(sw.randomEncryption && lib.hasPrefix "/dev/disk/by-label" sw.device);
           let realDevice' = escapeSystemdPath sw.realDevice;
           in nameValuePair "mkswap-${sw.deviceName}"
           { description = "Initialisation of swap device ${sw.device}";
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 9708b5d9fe33..169c86a2eae7 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -76,7 +76,7 @@ in
       extraOutputsToInstall = mkOption {
         type = types.listOf types.str;
         default = [ ];
-        example = [ "doc" "info" "docdev" ];
+        example = [ "doc" "info" "devdoc" ];
         description = "List of additional package outputs to be symlinked into <filename>/run/current-system/sw</filename>.";
       };
 
diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl
index 967f427374b1..cbbe216e5a17 100644
--- a/nixos/modules/config/update-users-groups.pl
+++ b/nixos/modules/config/update-users-groups.pl
@@ -52,8 +52,8 @@ foreach my $g (@{$spec->{groups}}) {
     $gidsUsed{$g->{gid}} = 1 if defined $g->{gid};
 }
 
-foreach my $u (@{$spec->{groups}}) {
-    $uidsUsed{$u->{u}} = 1 if defined $u->{uid};
+foreach my $u (@{$spec->{users}}) {
+    $uidsUsed{$u->{uid}} = 1 if defined $u->{uid};
 }
 
 # Read the current /etc/group.
diff --git a/nixos/modules/i18n/input-method/default.nix b/nixos/modules/i18n/input-method/default.nix
index 5d57a7f99666..f3e568f1dde3 100644
--- a/nixos/modules/i18n/input-method/default.nix
+++ b/nixos/modules/i18n/input-method/default.nix
@@ -62,4 +62,9 @@ in
     environment.systemPackages = [ cfg.package gtk2_cache gtk3_cache ];
   };
 
+  meta = {
+    maintainers = with lib.maintainers; [ ericsagnes ];
+    doc = ./default.xml;
+  };
+
 }
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index 3b3a7bd27fe8..0a452b86018a 100644
--- a/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -92,14 +92,13 @@ fi
 mkdir -m 0755 -p $mountPoint/dev $mountPoint/proc $mountPoint/sys $mountPoint/etc $mountPoint/run $mountPoint/home
 mkdir -m 01777 -p $mountPoint/tmp
 mkdir -m 0755 -p $mountPoint/tmp/root
-mkdir -m 0755 -p $mountPoint/var/setuid-wrappers
+mkdir -m 0755 -p $mountPoint/var
 mkdir -m 0700 -p $mountPoint/root
 mount --rbind /dev $mountPoint/dev
 mount --rbind /proc $mountPoint/proc
 mount --rbind /sys $mountPoint/sys
 mount --rbind / $mountPoint/tmp/root
 mount -t tmpfs -o "mode=0755" none $mountPoint/run
-mount -t tmpfs -o "mode=0755" none $mountPoint/var/setuid-wrappers
 rm -rf $mountPoint/var/run
 ln -s /run $mountPoint/var/run
 for f in /etc/resolv.conf /etc/hosts; do rm -f $mountPoint/$f; [ -f "$f" ] && cp -Lf $f $mountPoint/etc/; done
@@ -136,7 +135,6 @@ fi
 mkdir -m 0755 -p \
     $mountPoint/nix/var/nix/gcroots \
     $mountPoint/nix/var/nix/temproots \
-    $mountPoint/nix/var/nix/manifests \
     $mountPoint/nix/var/nix/userpool \
     $mountPoint/nix/var/nix/profiles \
     $mountPoint/nix/var/nix/db \
@@ -201,14 +199,6 @@ p=@nix@/libexec/nix/substituters
 export NIX_SUBSTITUTERS=$p/copy-from-other-stores.pl:$p/download-from-binary-cache.pl
 
 
-# Make manifests available in the chroot.
-rm -f $mountPoint/nix/var/nix/manifests/*
-for i in /nix/var/nix/manifests/*.nixmanifest; do
-    chroot $mountPoint @nix@/bin/nix-store -r "$(readlink -f "$i")" > /dev/null
-    cp -pd "$i" $mountPoint/nix/var/nix/manifests/
-done
-
-
 if [ -z "$closure" ]; then
     # Get the absolute path to the NixOS/Nixpkgs sources.
     nixpkgs="$(readlink -f $(nix-instantiate --find-file nixpkgs))"
diff --git a/nixos/modules/misc/meta.nix b/nixos/modules/misc/meta.nix
index 22622706f2c8..6a5738e47ff3 100644
--- a/nixos/modules/misc/meta.nix
+++ b/nixos/modules/misc/meta.nix
@@ -39,7 +39,7 @@ in
         default = [];
         example = [ lib.maintainers.all ];
         description = ''
-	  List of maintainers of each module.  This option should be defined at
+          List of maintainers of each module.  This option should be defined at
           most once per module.
         '';
       };
@@ -49,7 +49,7 @@ in
         internal = true;
         example = "./meta.xml";
         description = ''
-	  Documentation prologe for the set of options of each module.  This
+          Documentation prologe for the set of options of each module.  This
           option should be defined at most once per module.
         '';
       };
@@ -57,7 +57,5 @@ in
     };
   };
 
-  config = {
-    meta.maintainers = singleton lib.maintainers.pierron;
-  };
+  meta.maintainers = singleton lib.maintainers.pierron;
 }
diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix
index 5eb38c510b48..7d50b8025bdd 100644
--- a/nixos/modules/misc/nixpkgs.nix
+++ b/nixos/modules/misc/nixpkgs.nix
@@ -21,6 +21,11 @@ let
       packageOverrides = pkgs:
         optCall lhs.packageOverrides pkgs //
         optCall (attrByPath ["packageOverrides"] ({}) rhs) pkgs;
+    } //
+    optionalAttrs (lhs ? perlPackageOverrides) {
+      perlPackageOverrides = pkgs:
+        optCall lhs.perlPackageOverrides pkgs //
+        optCall (attrByPath ["perlPackageOverrides"] ({}) rhs) pkgs;
     };
 
   configType = mkOptionType {
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index eb89ff83e2ce..27fbe55cd429 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -335,6 +335,7 @@
   ./services/networking/docker-registry-server.nix
   ./services/networking/ejabberd.nix
   ./services/networking/fan.nix
+  ./services/networking/ferm.nix
   ./services/networking/firefox/sync-server.nix
   ./services/networking/firewall.nix
   ./services/networking/flashpolicyd.nix
@@ -387,6 +388,7 @@
   ./services/networking/prayer.nix
   ./services/networking/privoxy.nix
   ./services/networking/prosody.nix
+  ./services/networking/quagga.nix
   ./services/networking/quassel.nix
   ./services/networking/racoon.nix
   ./services/networking/radicale.nix
diff --git a/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix
index 1b8b7a79593e..91cd84416921 100644
--- a/nixos/modules/programs/zsh/zsh.nix
+++ b/nixos/modules/programs/zsh/zsh.nix
@@ -25,7 +25,10 @@ in
       enable = mkOption {
         default = false;
         description = ''
-          Whether to configure zsh as an interactive shell.
+          Whether to configure zsh as an interactive shell. To enable zsh for
+          a particular user, use the <option>users.users.&lt;name?&gt;.shell</option>
+          option for that user. To enable zsh system-wide use the
+          <option>users.defaultUserShell</option> option.
         '';
         type = types.bool;
       };
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 3caac6c4ee60..412cccc20d58 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -29,7 +29,7 @@ with lib;
     (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ])
 
     (mkRenamedOptionModule [ "services" "gitlab" "stateDir" ] [ "services" "gitlab" "statePath" ])
-    (mkRemovedOptionModule [ "services" "gitlab" "satelliteDir" ])
+    (mkRemovedOptionModule [ "services" "gitlab" "satelliteDir" ] "")
 
     # Old Grub-related options.
     (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ])
@@ -112,27 +112,27 @@ with lib;
     (mkRenamedOptionModule [ "services" "iodined" "domain" ] [ "services" "iodine" "server" "domain" ])
     (mkRenamedOptionModule [ "services" "iodined" "ip" ] [ "services" "iodine" "server" "ip" ])
     (mkRenamedOptionModule [ "services" "iodined" "extraConfig" ] [ "services" "iodine" "server" "extraConfig" ])
-    (mkRemovedOptionModule [ "services" "iodined" "client" ])
+    (mkRemovedOptionModule [ "services" "iodined" "client" ] "")
 
     # Grsecurity
-    (mkRemovedOptionModule [ "security" "grsecurity" "kernelPatch" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "mode" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "priority" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "system" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationConfig" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "hardwareVirtualisation" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationSoftware" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "sysctl" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootChmod" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootCaps" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyUSB" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProc" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProcWithGroup" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "unrestrictProcGid" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableRBAC" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableSimultConnect" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "verboseVersion" ])
-    (mkRemovedOptionModule [ "security" "grsecurity" "config" "kernelExtraConfig" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "kernelPatch" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "mode" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "priority" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "system" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationConfig" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "hardwareVirtualisation" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationSoftware" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "sysctl" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootChmod" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootCaps" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyUSB" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProc" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProcWithGroup" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "unrestrictProcGid" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableRBAC" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableSimultConnect" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "verboseVersion" ] "")
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "kernelExtraConfig" ] "")
 
     # Unity3D
     (mkRenamedOptionModule [ "programs" "unity3d" "enable" ] [ "security" "chromiumSuidSandbox" "enable" ])
@@ -141,18 +141,18 @@ with lib;
     (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "rendering" ] [ "fonts" "fontconfig" "ultimate" "preset" ])
 
     # Options that are obsolete and have no replacement.
-    (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ])
-    (mkRemovedOptionModule [ "programs" "bash" "enable" ])
-    (mkRemovedOptionModule [ "services" "samba" "defaultShare" ])
-    (mkRemovedOptionModule [ "services" "syslog-ng" "serviceName" ])
-    (mkRemovedOptionModule [ "services" "syslog-ng" "listenToJournal" ])
-    (mkRemovedOptionModule [ "ec2" "metadata" ])
-    (mkRemovedOptionModule [ "services" "openvpn" "enable" ])
-    (mkRemovedOptionModule [ "services" "printing" "cupsFilesConf" ])
-    (mkRemovedOptionModule [ "services" "printing" "cupsdConf" ])
-    (mkRemovedOptionModule [ "services" "xserver" "startGnuPGAgent" ])
-    (mkRemovedOptionModule [ "services" "phpfpm" "phpIni" ])
-    (mkRemovedOptionModule [ "services" "dovecot2" "package" ])
-
+    (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "")
+    (mkRemovedOptionModule [ "programs" "bash" "enable" ] "")
+    (mkRemovedOptionModule [ "services" "samba" "defaultShare" ] "")
+    (mkRemovedOptionModule [ "services" "syslog-ng" "serviceName" ] "")
+    (mkRemovedOptionModule [ "services" "syslog-ng" "listenToJournal" ] "")
+    (mkRemovedOptionModule [ "ec2" "metadata" ] "")
+    (mkRemovedOptionModule [ "services" "openvpn" "enable" ] "")
+    (mkRemovedOptionModule [ "services" "printing" "cupsFilesConf" ] "")
+    (mkRemovedOptionModule [ "services" "printing" "cupsdConf" ] "")
+    (mkRemovedOptionModule [ "services" "xserver" "startGnuPGAgent" ]
+      "See the 16.03 release notes for more information.")
+    (mkRemovedOptionModule [ "services" "phpfpm" "phpIni" ] "")
+    (mkRemovedOptionModule [ "services" "dovecot2" "package" ] "")
   ];
 }
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index f646602221a4..3dac558b9537 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -290,9 +290,10 @@ in
       systemd.targets."acme-certificates" = {};
     })
 
-    { meta.maintainers = with lib.maintainers; [ abbradar fpletz globin ];
-      meta.doc = ./acme.xml;
-    }
   ];
 
+  meta = {
+    maintainers = with lib.maintainers; [ abbradar fpletz globin ];
+    doc = ./acme.xml;
+  };
 }
diff --git a/nixos/modules/security/audit.nix b/nixos/modules/security/audit.nix
index f223f52ec487..ebfe594d0c71 100644
--- a/nixos/modules/security/audit.nix
+++ b/nixos/modules/security/audit.nix
@@ -4,6 +4,7 @@ with lib;
 
 let
   cfg = config.security.audit;
+  enabled = cfg.enable == "lock" || cfg.enable;
 
   failureModes = {
     silent = 0;
@@ -11,6 +12,13 @@ let
     panic  = 2;
   };
 
+  disableScript = pkgs.writeScript "audit-disable" ''
+    #!${pkgs.stdenv.shell} -eu
+    # Explicitly disable everything, as otherwise journald might start it.
+    auditctl -D
+    auditctl -e 0 -a task,never
+  '';
+
   # TODO: it seems like people like their rules to be somewhat secret, yet they will not be if
   # put in the store like this. At the same time, it doesn't feel like a huge deal and working
   # around that is a pain so I'm leaving it like this for now.
@@ -47,7 +55,7 @@ in {
     security.audit = {
       enable = mkOption {
         type        = types.enum [ false true "lock" ];
-        default     = true; # The kernel seems to enable it by default with no rules anyway
+        default     = false;
         description = ''
           Whether to enable the Linux audit system. The special `lock' value can be used to
           enable auditing and prevent disabling it until a restart. Be careful about locking
@@ -91,7 +99,7 @@ in {
     };
   };
 
-  config = mkIf (cfg.enable == "lock" || cfg.enable) {
+  config = {
     systemd.services.audit = {
       description = "Kernel Auditing";
       wantedBy = [ "basic.target" ];
@@ -103,8 +111,8 @@ in {
       serviceConfig = {
         Type = "oneshot";
         RemainAfterExit = true;
-        ExecStart = "@${startScript} audit-start";
-        ExecStop  = "@${stopScript}  audit-stop";
+        ExecStart = "@${if enabled then startScript else disableScript} audit-start";
+        ExecStop  = "@${stopScript} audit-stop";
       };
     };
   };
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index 9a2f62a14889..ea1064c2d425 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -12,7 +12,7 @@ let
     (fs: (fs.neededForBoot
           || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ])
           && fs.fsType == "zfs")
-    (attrValues config.fileSystems) != [];
+    config.system.build.fileSystems != [];
 
   # Ascertain whether NixOS container support is required
   containerSupportRequired =
@@ -20,6 +20,11 @@ let
 in
 
 {
+  meta = {
+    maintainers = with maintainers; [ joachifm ];
+    doc = ./grsecurity.xml;
+  };
+
   options.security.grsecurity = {
 
     enable = mkEnableOption "grsecurity/PaX";
diff --git a/nixos/doc/manual/configuration/grsecurity.xml b/nixos/modules/security/grsecurity.xml
index 28415e89bfab..28415e89bfab 100644
--- a/nixos/doc/manual/configuration/grsecurity.xml
+++ b/nixos/modules/security/grsecurity.xml
diff --git a/nixos/modules/security/hidepid.nix b/nixos/modules/security/hidepid.nix
index 8271578c55d6..8f2df380cfe8 100644
--- a/nixos/modules/security/hidepid.nix
+++ b/nixos/modules/security/hidepid.nix
@@ -20,23 +20,6 @@ with lib;
   config = mkIf config.security.hideProcessInformation {
     users.groups.proc.gid = config.ids.gids.proc;
 
-    systemd.services.hidepid = {
-      wantedBy = [ "local-fs.target" ];
-      after = [ "systemd-remount-fs.service" ];
-      before = [ "local-fs-pre.target" "local-fs.target" "shutdown.target" ];
-      wants = [ "local-fs-pre.target" ];
-
-      serviceConfig = {
-        Type = "oneshot";
-        RemainAfterExit = true;
-        ExecStart = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=2,gid=${toString config.ids.gids.proc} /proc'';
-        ExecStop = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=0,gid=0 /proc'';
-      };
-
-      unitConfig = {
-        DefaultDependencies = false;
-        Conflicts = "shutdown.target";
-      };
-    };
+    boot.specialFileSystems."/proc".options = [ "hidepid=2" "gid=${toString config.ids.gids.proc}" ];
   };
 }
diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix
index 99dd514feea3..dcccd8342866 100644
--- a/nixos/modules/security/setuid-wrappers.nix
+++ b/nixos/modules/security/setuid-wrappers.nix
@@ -12,7 +12,7 @@ let
     installPhase = ''
       mkdir -p $out/bin
       cp ${./setuid-wrapper.c} setuid-wrapper.c
-      gcc -Wall -O2 -DWRAPPER_DIR=\"${wrapperDir}\" \
+      gcc -Wall -O2 -DWRAPPER_DIR=\"/run/setuid-wrapper-dirs\" \
           setuid-wrapper.c -o $out/bin/setuid-wrapper
     '';
   };
@@ -102,11 +102,11 @@ in
                 source=/nix/var/nix/profiles/default/bin/${program}
             fi
 
-            cp ${setuidWrapper}/bin/setuid-wrapper ${wrapperDir}/${program}
-            echo -n "$source" > ${wrapperDir}/${program}.real
-            chmod 0000 ${wrapperDir}/${program} # to prevent races
-            chown ${owner}.${group} ${wrapperDir}/${program}
-            chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" ${wrapperDir}/${program}
+            cp ${setuidWrapper}/bin/setuid-wrapper $wrapperDir/${program}
+            echo -n "$source" > $wrapperDir/${program}.real
+            chmod 0000 $wrapperDir/${program} # to prevent races
+            chown ${owner}.${group} $wrapperDir/${program}
+            chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" $wrapperDir/${program}
           '';
 
       in stringAfter [ "users" ]
@@ -115,9 +115,30 @@ in
           # programs to be wrapped.
           SETUID_PATH=${config.system.path}/bin:${config.system.path}/sbin
 
-          rm -f ${wrapperDir}/* # */
+          mkdir -p /run/setuid-wrapper-dirs
+          wrapperDir=$(mktemp --directory --tmpdir=/run/setuid-wrapper-dirs setuid-wrappers.XXXXXXXXXX)
+          chmod a+rx $wrapperDir
 
           ${concatMapStrings makeSetuidWrapper setuidPrograms}
+
+          if [ -L ${wrapperDir} ]; then
+            # Atomically replace the symlink
+            # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/
+            old=$(readlink ${wrapperDir})
+            ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp
+            mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir}
+            rm --force --recursive $old
+          elif [ -d ${wrapperDir} ]; then
+            # Compatibility with old state, just remove the folder and symlink
+            rm -f ${wrapperDir}/*
+            # if it happens to be a tmpfs
+            umount ${wrapperDir} || true
+            rm -d ${wrapperDir}
+            ln -d --symbolic $wrapperDir ${wrapperDir}
+          else
+            # For initial setup
+            ln --symbolic $wrapperDir ${wrapperDir}
+          fi
         '';
 
   };
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index 80ee32f4ee33..24ef4637ec98 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -11,12 +11,14 @@ let
     if cfg.extraPlugins == [] then pg
     else pkgs.buildEnv {
       name = "postgresql-and-plugins-${(builtins.parseDrvName pg.name).version}";
-      paths = [ pg ] ++ cfg.extraPlugins;
+      paths = [ pg pg.lib ] ++ cfg.extraPlugins;
+      buildInputs = [ pkgs.makeWrapper ];
       postBuild =
         ''
           mkdir -p $out/bin
           rm $out/bin/{pg_config,postgres,pg_ctl}
           cp --target-directory=$out/bin ${pg}/bin/{postgres,pg_config,pg_ctl}
+          wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
         '';
     };
 
@@ -253,4 +255,6 @@ in
 
   };
 
+  meta.doc = ./postgresql.xml;
+
 }
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index 480e1184ffa3..a039ad138f6f 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -234,9 +234,8 @@ in
         serviceConfig.Type = "oneshot";
 
         script = ''
-          if ! test -e ${cfg.dbpath}; then
-              install -d -m0700 -o ${cfg.user} ${cfg.dbpath}
-          fi
+          install -d -m0700 -o ${cfg.user} ${cfg.dbpath}
+          chown -R ${cfg.user} ${cfg.dbpath}
         '';
       };
 
diff --git a/nixos/modules/services/desktops/accountsservice.nix b/nixos/modules/services/desktops/accountsservice.nix
index c28c27295761..2a7450669ea0 100644
--- a/nixos/modules/services/desktops/accountsservice.nix
+++ b/nixos/modules/services/desktops/accountsservice.nix
@@ -35,6 +35,14 @@ with lib;
     services.dbus.packages = [ pkgs.accountsservice ];
 
     systemd.packages = [ pkgs.accountsservice ];
+
+    systemd.services.accounts-daemon= {
+
+      wantedBy = [ "graphical.target" ];
+
+    } // (mkIf (!config.users.mutableUsers) {
+      environment.NIXOS_USERS_PURE = "true";
+    });
   };
 
 }
diff --git a/nixos/modules/services/editors/emacs.nix b/nixos/modules/services/editors/emacs.nix
index 43b4219c51dd..6795ec52fe4d 100644
--- a/nixos/modules/services/editors/emacs.nix
+++ b/nixos/modules/services/editors/emacs.nix
@@ -83,4 +83,6 @@ in {
       EDITOR = mkOverride 900 "${editorScript}/bin/emacseditor";
     } else {};
   };
+
+  meta.doc = ./emacs.xml;
 }
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index e773cdedaea2..fb94560e10aa 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -109,12 +109,14 @@ in {
       after = [ "network.target" ];
       preStart = ''
         mkdir -p /var/spool/smtpd
+        chmod 711 /var/spool/smtpd
 
         mkdir -p /var/spool/smtpd/offline
         chown root.smtpq /var/spool/smtpd/offline
         chmod 770 /var/spool/smtpd/offline
 
         mkdir -p /var/spool/smtpd/purge
+        chown smtpq.root /var/spool/smtpd/purge
         chmod 700 /var/spool/smtpd/purge
       '';
       serviceConfig.ExecStart = "${opensmtpd}/sbin/smtpd -d -f ${conf} ${args}";
diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix
index befd8c628f16..44880ebeda14 100644
--- a/nixos/modules/services/misc/gitit.nix
+++ b/nixos/modules/services/misc/gitit.nix
@@ -663,7 +663,7 @@ in
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       path = with pkgs; [ curl ]
-             ++ optional cfg.pdfExport texLiveFull
+             ++ optional cfg.pdfExport texlive.combined.scheme-basic
 	     ++ optional (cfg.repositoryType == "darcs") darcs
 	     ++ optional (cfg.repositoryType == "mercurial") mercurial
 	     ++ optional (cfg.repositoryType == "git") git;
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 39283d2d9437..b3f09999adba 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -43,7 +43,9 @@ let
 
   secretsYml = ''
     production:
-      db_key_base: ${cfg.secrets.db_key_base}
+      secret_key_base: ${cfg.secrets.secret}
+      otp_key_base: ${cfg.secrets.otp}
+      db_key_base: ${cfg.secrets.db}
   '';
 
   gitlabConfig = {
@@ -121,7 +123,7 @@ let
       makeWrapper ${cfg.packages.gitlab.env}/bin/bundle $out/bin/gitlab-bundle \
           ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \
           --set GITLAB_CONFIG_PATH '${cfg.statePath}/config' \
-          --set PATH '${stdenv.lib.makeBinPath [ pkgs.nodejs pkgs.gzip config.services.postgresql.package ]}:$PATH' \
+          --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip config.services.postgresql.package ]}:$PATH' \
           --set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \
           --run 'cd ${cfg.packages.gitlab}/share/gitlab'
       makeWrapper $out/bin/gitlab-bundle $out/bin/gitlab-rake \
@@ -318,11 +320,10 @@ in {
         };
       };
 
-      secrets.db_key_base = mkOption {
+      secrets.secret = mkOption {
         type = types.str;
-        example = "";
         description = ''
-          The db_key_base secrets is used to encrypt variables in the DB. If
+          The secret is used to encrypt variables in the DB. If
           you change or lose this key you will be unable to access variables
           stored in database.
 
@@ -331,6 +332,30 @@ in {
         '';
       };
 
+      secrets.db = mkOption {
+        type = types.str;
+        description = ''
+          The secret is used to encrypt variables in the DB. If
+          you change or lose this key you will be unable to access variables
+          stored in database.
+
+          Make sure the secret is at least 30 characters and all random,
+          no regular words or you'll be exposed to dictionary attacks.
+        '';
+      };
+
+      secrets.otp = mkOption {
+        type = types.str;
+        description = ''
+          The secret is used to encrypt secrets for OTP tokens. If
+          you change or lose this key, users which have 2FA enabled for login
+          won't be able to login anymore.
+
+          Make sure the secret is at least 30 characters and all random,
+          no regular words or you'll be exposed to dictionary attacks.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.attrs;
         default = {};
@@ -458,8 +483,7 @@ in {
         rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks
         mkdir -p ${cfg.statePath}/config ${cfg.statePath}/shell
 
-        # TODO: What exactly is gitlab-shell doing with the secret?
-        tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 20 > ${cfg.statePath}/config/gitlab_shell_secret
+        tr -dc A-Za-z0-9 < /dev/urandom | head -c 32 > ${cfg.statePath}/config/gitlab_shell_secret
 
         # The uploads directory is hardcoded somewhere deep in rails. It is
         # symlinked in the gitlab package to /run/gitlab/uploads to make it
@@ -532,4 +556,7 @@ in {
     };
 
   };
+
+  meta.doc = ./gitlab.xml;
+
 }
diff --git a/nixos/modules/services/misc/gitlab.xml b/nixos/modules/services/misc/gitlab.xml
index 83f715a50b43..f9636f8e1278 100644
--- a/nixos/modules/services/misc/gitlab.xml
+++ b/nixos/modules/services/misc/gitlab.xml
@@ -62,7 +62,11 @@ services.gitlab = {
     address = "localhost";
     port = 25;
   };
-  secrets.db_key_base = "ei3eeP1ohsh0uu3ad4YeeMeeheengah3AiZee2ohl4Ooj5mie4Ohl0vishoghaes";
+  secrets = {
+    db = "uPgq1gtwwHiatiuE0YHqbGa5lEIXH7fMsvuTNgdzJi8P0Dg12gibTzBQbq5LT7PNzcc3BP9P1snHVnduqtGF43PgrQtU7XL93ts6gqe9CBNhjtaqUwutQUDkygP5NrV6";
+    secret = "devzJ0Tz0POiDBlrpWmcsjjrLaltyiAdS8TtgT9YNBOoUcDsfppiY3IXZjMVtKgXrFImIennFGOpPN8IkP8ATXpRgDD5rxVnKuTTwYQaci2NtaV1XxOQGjdIE50VGsR3";
+    otp = "e1GATJVuS2sUh7jxiPzZPre4qtzGGaS22FR50Xs1TerRVdgI3CBVUi5XYtQ38W4xFeS4mDqi5cQjExE838iViSzCdcG19XSL6qNsfokQP9JugwiftmhmCadtsnHErBMI";
+  };
   extraConfig = {
     gitlab = {
       email_from = "gitlab-no-reply@example.com";
@@ -75,11 +79,12 @@ services.gitlab = {
 </programlisting>
 </para>
 
-<para>If you're setting up a new Gitlab instance, generate a new
-<literal>db_key_base</literal> secret to encrypt sensible data in the
-database. If you're restoring an existing Gitlab instance, you must
-specify the <literal>db_key_base</literal> secret from
-<literal>config/secrets.yml</literal> in your Gitlab state folder.</para>
+<para>If you're setting up a new Gitlab instance, generate new secrets. You
+for instance use <literal>tr -dc A-Za-z0-9 &lt; /dev/urandom | head -c 128</literal>
+to generate a new secret. Gitlab encrypts sensitive data stored in the database.
+If you're restoring an existing Gitlab instance, you must specify the secrets
+secret from <literal>config/secrets.yml</literal> located in your Gitlab state
+folder.</para>
 
 <para>Refer to <xref linkend="ch-options" /> for all available configuration
 options for the <literal>services.gitlab</literal> module.</para>
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index fe5132d4973e..333782d15bcb 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -311,7 +311,7 @@ in
       nixPath = mkOption {
         type = types.listOf types.str;
         default =
-          [ "/nix/var/nix/profiles/per-user/root/channels/nixos"
+          [ "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs"
             "nixos-config=/etc/nixos/configuration.nix"
             "/nix/var/nix/profiles/per-user/root/channels"
           ];
diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix
index a60d5f7983bc..306ee346523d 100644
--- a/nixos/modules/services/misc/nixos-manual.nix
+++ b/nixos/modules/services/misc/nixos-manual.nix
@@ -17,7 +17,7 @@ let
     Caveat: even if the package is reached by a different means,
     the path above will be shown and not e.g. `${config.services.foo.package}`. */
   manual = import ../../../doc/manual {
-    inherit pkgs;
+    inherit pkgs config;
     version = config.system.nixosRelease;
     revision = "release-${config.system.nixosRelease}";
     options =
diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix
index c846ffd04551..6d458feec345 100644
--- a/nixos/modules/services/misc/taskserver/default.nix
+++ b/nixos/modules/services/misc/taskserver/default.nix
@@ -534,6 +534,7 @@ in {
     (mkIf (cfg.enable && cfg.listenHost != "localhost") {
       networking.firewall.allowedTCPPorts = [ cfg.listenPort ];
     })
-    { meta.doc = ./taskserver.xml; }
   ];
+
+  meta.doc = ./doc.xml;
 }
diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix
index f4063a3406f1..0495b32c6fa8 100644
--- a/nixos/modules/services/networking/cjdns.nix
+++ b/nixos/modules/services/networking/cjdns.nix
@@ -253,7 +253,7 @@ in
     networking.extraHosts = "${cjdnsHosts}";
 
     assertions = [
-      { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile == "" );
+      { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != "" );
         message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined.";
       }
       { assertion = config.networking.enableIPv6;
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index cf36ccf05725..2714e8d75993 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -28,31 +28,15 @@ let
 in
 
 {
+  meta = {
+    maintainers = with maintainers; [ joachifm ];
+    doc = ./dnscrypt-proxy.xml;
+  };
+
   options = {
     services.dnscrypt-proxy = {
-      enable = mkEnableOption "dnscrypt-proxy" // { description = ''
-        Whether to enable the DNSCrypt client proxy. The proxy relays
-        DNS queries to a DNSCrypt enabled upstream resolver. The traffic
-        between the client and the upstream resolver is encrypted and
-        authenticated, mitigating the risk of MITM attacks and third-party
-        snooping (assuming the upstream is trustworthy).
-
-        Enabling this option does not alter the system nameserver; to relay
-        local queries, prepend <literal>127.0.0.1</literal> to
-        <option>networking.nameservers</option>.
-
-        The recommended configuration is to run DNSCrypt proxy as a forwarder
-        for a caching DNS client, as in
-        <programlisting>
-        {
-          services.dnscrypt-proxy.enable = true;
-          services.dnscrypt-proxy.localPort = 43;
-          services.dnsmasq.enable = true;
-          services.dnsmasq.servers = [ "127.0.0.1#43" ];
-          services.dnsmasq.resolveLocalQueries = true; # this is the default
-        }
-        </programlisting>
-      ''; };
+      enable = mkEnableOption "DNSCrypt client proxy";
+
       localAddress = mkOption {
         default = "127.0.0.1";
         type = types.str;
@@ -62,6 +46,7 @@ in
           of other machines (typically on the local network).
         '';
       };
+
       localPort = mkOption {
         default = 53;
         type = types.int;
@@ -72,6 +57,7 @@ in
           to a different value; otherwise leave the default.
         '';
       };
+
       resolverName = mkOption {
         default = "dnscrypt.eu-nl";
         type = types.nullOr types.str;
@@ -82,6 +68,7 @@ in
           extensions, and claims to not keep logs.
         '';
       };
+
       resolverList = mkOption {
         description = ''
           The list of upstream DNSCrypt resolvers. By default, we use the most
@@ -94,6 +81,7 @@ in
         };
         defaultText = "pkgs.fetchurl { url = ...; sha256 = ...; }";
       };
+
       customResolver = mkOption {
         default = null;
         description = ''
@@ -103,26 +91,30 @@ in
         type = types.nullOr (types.submodule ({ ... }: { options = {
           address = mkOption {
             type = types.str;
-            description = "Resolver IP address";
+            description = "IP address";
             example = "208.67.220.220";
           };
+
           port = mkOption {
             type = types.int;
-            description = "Resolver port";
+            description = "Port";
             default = 443;
           };
+
           name = mkOption {
             type = types.str;
-            description = "Provider fully qualified domain name";
+            description = "Fully qualified domain name";
             example = "2.dnscrypt-cert.opendns.com";
           };
+
           key = mkOption {
             type = types.str;
-            description = "Provider public key";
+            description = "Public key";
             example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79";
           };
         }; }));
       };
+
       tcpOnly = mkOption {
         default = false;
         type = types.bool;
@@ -131,6 +123,7 @@ in
           TCP instead of UDP (on port 443). Use only if the UDP port is blocked.
         '';
       };
+
       ephemeralKeys = mkOption {
         default = false;
         type = types.bool;
@@ -212,7 +205,6 @@ in
         ExecStart = "${dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}";
 
         User = "dnscrypt-proxy";
-        Group = "dnscrypt-proxy";
 
         PrivateTmp = true;
         PrivateDevices = true;
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.xml b/nixos/modules/services/networking/dnscrypt-proxy.xml
new file mode 100644
index 000000000000..e212a8d3e2c3
--- /dev/null
+++ b/nixos/modules/services/networking/dnscrypt-proxy.xml
@@ -0,0 +1,76 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-dnscrypt-proxy">
+
+  <title>DNSCrypt client proxy</title>
+
+  <para>
+    The DNSCrypt client proxy relays DNS queries to a DNSCrypt enabled
+    upstream resolver. The traffic between the client and the upstream
+    resolver is encrypted and authenticated, mitigating the risk of MITM
+    attacks, DNS poisoning attacks, and third-party snooping (assuming the
+    upstream is trustworthy).
+  </para>
+
+  <sect1><title>Basic configuration</title>
+
+  <para>
+    To enable the client proxy, set
+    <programlisting>
+      services.dnscrypt-proxy.enable = true;
+    </programlisting>
+  </para>
+
+  <para>
+    Enabling the client proxy does not alter the system nameserver; to
+    relay local queries, prepend <literal>127.0.0.1</literal> to
+    <option>networking.nameservers</option>.
+  </para>
+
+  </sect1>
+
+  <sect1><title>As a forwarder for a caching DNS client</title>
+
+  <para>
+    By default, DNSCrypt proxy acts as a transparent proxy for the
+    system stub resolver. Because the client does not cache lookups, this
+    setup can significantly slow down e.g., web browsing. The recommended
+    configuration is to run DNSCrypt proxy as a forwarder for a caching DNS
+    client. To achieve this, change the default proxy listening port to
+    a non-standard value and point the caching client to it:
+    <programlisting>
+      services.dnscrypt-proxy.localPort = 43;
+    </programlisting>
+  </para>
+
+  <sect2><title>dnsmasq</title>
+  <para>
+    <programlisting>
+      {
+      services.dnsmasq.enable = true;
+      services.dnsmasq.servers = [ "127.0.0.1#43" ];
+      }
+    </programlisting>
+  </para>
+  </sect2>
+
+  <sect2><title>unbound</title>
+  <para>
+    <programlisting>
+      {
+      networking.nameservers = [ "127.0.0.1" ];
+      services.unbound.enable = true;
+      services.unbound.forwardAddresses = [ "127.0.0.1@43" ];
+      services.unbound.extraConfig = ''
+        do-not-query-localhost: no
+      '';
+      }
+    </programlisting>
+  </para>
+  </sect2>
+
+  </sect1>
+
+</chapter>
diff --git a/nixos/modules/services/networking/ferm.nix b/nixos/modules/services/networking/ferm.nix
new file mode 100644
index 000000000000..6271e82541f4
--- /dev/null
+++ b/nixos/modules/services/networking/ferm.nix
@@ -0,0 +1,63 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.ferm;
+
+  configFile = pkgs.stdenv.mkDerivation {
+    name = "ferm.conf";
+    text = cfg.config;
+    preferLocalBuild = true;
+    buildCommand = ''
+      echo -n "$text" > $out
+      ${cfg.package}/bin/ferm --noexec $out
+    '';
+  };
+in {
+  options = {
+    services.ferm = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        type = types.bool;
+        description = ''
+          Whether to enable Ferm Firewall.
+          *Warning*: Enabling this service WILL disable the existing NixOS
+          firewall! Default firewall rules provided by packages are not
+          considered at the moment.
+        '';
+      };
+      config = mkOption {
+        description = "Verbatim ferm.conf configuration.";
+        default = "";
+        defaultText = "empty firewall, allows any traffic";
+        type = types.lines;
+      };
+      package = mkOption {
+        description = "The ferm package.";
+        type = types.package;
+        default = pkgs.ferm;
+        defaultText = "pkgs.ferm";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.firewall.enable = false;
+    systemd.services.ferm = {
+      description = "Ferm Firewall";
+      after = [ "ipset.target" ];
+      before = [ "network-pre.target" ];
+      wants = [ "network-pre.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type="oneshot";
+        RemainAfterExit = "yes";
+        ExecStart = "${cfg.package}/bin/ferm ${configFile}";
+        ExecReload = "${cfg.package}/bin/ferm ${configFile}";
+        ExecStop = "${cfg.package}/bin/ferm -F ${configFile}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/mjpg-streamer.nix b/nixos/modules/services/networking/mjpg-streamer.nix
index 9986f549aecf..1286b0c7ef6c 100644
--- a/nixos/modules/services/networking/mjpg-streamer.nix
+++ b/nixos/modules/services/networking/mjpg-streamer.nix
@@ -59,8 +59,12 @@ in {
       description = "mjpg-streamer webcam streamer";
       wantedBy = [ "multi-user.target" ];
 
-      serviceConfig.User = cfg.user;
-      serviceConfig.Group = cfg.group;
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart = "on-failure";
+        RestartSec = 1;
+      };
 
       script = ''
         IPLUGIN="${cfg.inputPlugin}"
diff --git a/nixos/modules/services/networking/quagga.nix b/nixos/modules/services/networking/quagga.nix
new file mode 100644
index 000000000000..ac83da920638
--- /dev/null
+++ b/nixos/modules/services/networking/quagga.nix
@@ -0,0 +1,187 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.quagga;
+
+  services = [ "babel" "bgp" "isis" "ospf6" "ospf" "pim" "rip" "ripng" ];
+  allServices = services ++ [ "zebra" ];
+
+  isEnabled = service: cfg.${service}.enable;
+
+  daemonName = service: if service == "zebra" then service else "${service}d";
+
+  configFile = service:
+    let
+      scfg = cfg.${service};
+    in
+      if scfg.configFile != null then scfg.configFile
+      else pkgs.writeText "${daemonName service}.conf"
+        ''
+          ! Quagga ${daemonName service} configuration
+          !
+          hostname ${config.networking.hostName}
+          log syslog
+          service password-encryption
+          !
+          ${scfg.config}
+          !
+          end
+        '';
+
+  serviceOptions = service:
+    {
+      enable = mkEnableOption "the Quagga ${toUpper service} routing protocol";
+
+      configFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/etc/quagga/${daemonName service}.conf";
+        description = ''
+          Configuration file to use for Quagga ${daemonName service}.
+          By default the NixOS generated files are used.
+        '';
+      };
+
+      config = mkOption {
+        type = types.lines;
+        default = "";
+        example =
+          let
+            examples = {
+              rip = ''
+                router rip
+                  network 10.0.0.0/8
+              '';
+
+              ospf = ''
+                router ospf
+                  network 10.0.0.0/8 area 0
+              '';
+
+              bgp = ''
+                router bgp 65001
+                  neighbor 10.0.0.1 remote-as 65001
+              '';
+            };
+          in
+            examples.${service} or "";
+        description = ''
+          ${daemonName service} configuration statements.
+        '';
+      };
+
+      vtyListenAddress = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = ''
+          Address to bind to for the VTY interface.
+        '';
+      };
+
+      vtyListenPort = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          TCP Port to bind to for the VTY interface.
+        '';
+      };
+    };
+
+in
+
+{
+
+  ###### interface
+
+  options.services.quagga =
+    {
+
+      zebra = (serviceOptions "zebra") // {
+
+        enable = mkOption {
+          type = types.bool;
+          default = any isEnabled services;
+          example = true;
+          description = ''
+            Whether to enable the Zebra routing manager.
+
+            The Zebra routing manager is automatically enabled
+            if any routing protocols are configured.
+          '';
+        };
+
+      };
+
+    } // (genAttrs services serviceOptions);
+
+  ###### implementation
+
+  config = mkIf (any isEnabled allServices) {
+
+    environment.systemPackages = [
+      pkgs.quagga               # for the vtysh tool
+    ];
+
+    users.users.quagga = {
+      description = "Quagga daemon user";
+      isSystemUser = true;
+      group = "quagga";
+    };
+
+    users.groups = {
+      quagga = {};
+      # Members of the quaggavty group can use vtysh to inspect the Quagga daemons
+      quaggavty = {};
+    };
+
+    systemd.services =
+      let
+        quaggaService = service:
+          let
+            scfg = cfg.${service};
+            daemon = daemonName service;
+          in
+            nameValuePair daemon ({
+              wantedBy = [ "multi-user.target" ];
+              restartTriggers = [ (configFile service) ];
+
+              serviceConfig = {
+                Type = "forking";
+                PIDFile = "/run/quagga/${daemon}.pid";
+                ExecStart = "@${pkgs.quagga}/libexec/quagga/${daemon} ${daemon} -d -f ${configFile service}"
+                  + optionalString (scfg.vtyListenAddress != "") " -A ${scfg.vtyListenAddress}"
+                  + optionalString (scfg.vtyListenPort != null) " -P ${toString scfg.vtyListenPort}";
+                ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+                Restart = "on-abort";
+              };
+            } // (
+              if service == "zebra" then
+                {
+                  description = "Quagga Zebra routing manager";
+                  unitConfig.Documentation = "man:zebra(8)";
+                  after = [ "network.target" ];
+                  preStart = ''
+                    install -m 0755 -o quagga -g quagga -d /run/quagga
+
+                    ${pkgs.iproute}/bin/ip route flush proto zebra
+                  '';
+                }
+              else
+                {
+                  description = "Quagga ${toUpper service} routing daemon";
+                  unitConfig.Documentation = "man:${daemon}(8) man:zebra(8)";
+                  bindsTo = [ "zebra.service" ];
+                  after = [ "network.target" "zebra.service" ];
+                }
+            ));
+       in
+         listToAttrs (map quaggaService (filter isEnabled allServices));
+
+  };
+
+  meta.maintainers = with lib.maintainers; [ tavyc ];
+
+}
diff --git a/nixos/modules/services/networking/teamspeak3.nix b/nixos/modules/services/networking/teamspeak3.nix
index 5f04926eed24..3703921ff703 100644
--- a/nixos/modules/services/networking/teamspeak3.nix
+++ b/nixos/modules/services/networking/teamspeak3.nix
@@ -95,47 +95,44 @@ in
 
   ###### implementation
 
-  config = mkMerge [
-    (mkIf cfg.enable {
-      users.users.teamspeak = {
-        description = "Teamspeak3 voice communication server daemon";
-        group = group;
-        uid = config.ids.uids.teamspeak;
-        home = cfg.dataDir;
-        createHome = true;
-      };
-
-      users.groups.teamspeak = {
-        gid = config.ids.gids.teamspeak;
-      };
+  config = mkIf cfg.enable {
+    users.users.teamspeak = {
+      description = "Teamspeak3 voice communication server daemon";
+      group = group;
+      uid = config.ids.uids.teamspeak;
+      home = cfg.dataDir;
+      createHome = true;
+    };
 
-      systemd.services.teamspeak3-server = {
-        description = "Teamspeak3 voice communication server daemon";
-        after = [ "network.target" ];
-        wantedBy = [ "multi-user.target" ];
+    users.groups.teamspeak = {
+      gid = config.ids.gids.teamspeak;
+    };
 
-        preStart = ''
-          mkdir -p ${cfg.logPath}
-          chown ${user}:${group} ${cfg.logPath}
+    systemd.services.teamspeak3-server = {
+      description = "Teamspeak3 voice communication server daemon";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = ''
+        mkdir -p ${cfg.logPath}
+        chown ${user}:${group} ${cfg.logPath}
+      '';
+
+      serviceConfig = {
+        ExecStart = ''
+          ${ts3}/bin/ts3server \
+            dbsqlpath=${ts3}/lib/teamspeak/sql/ logpath=${cfg.logPath} \
+            voice_ip=${cfg.voiceIP} default_voice_port=${toString cfg.defaultVoicePort} \
+            filetransfer_ip=${cfg.fileTransferIP} filetransfer_port=${toString cfg.fileTransferPort} \
+            query_ip=${cfg.queryIP} query_port=${toString cfg.queryPort}
         '';
-
-        serviceConfig = {
-          ExecStart = ''
-            ${ts3}/bin/ts3server \
-              dbsqlpath=${ts3}/lib/teamspeak/sql/ logpath=${cfg.logPath} \
-              voice_ip=${cfg.voiceIP} default_voice_port=${toString cfg.defaultVoicePort} \
-              filetransfer_ip=${cfg.fileTransferIP} filetransfer_port=${toString cfg.fileTransferPort} \
-              query_ip=${cfg.queryIP} query_port=${toString cfg.queryPort}
-          '';
-          WorkingDirectory = cfg.dataDir;
-          User = user;
-          Group = group;
-          PermissionsStartOnly = true;
-        };
+        WorkingDirectory = cfg.dataDir;
+        User = user;
+        Group = group;
+        PermissionsStartOnly = true;
       };
-    })
-    {
-      meta.maintainers = with lib.maintainers; [ arobyn ];
-    }
-  ];
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ arobyn ];
 }
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index 0dd24478f409..ed0744c44ccf 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -43,14 +43,10 @@ in
   options = {
     services.unbound = {
 
-      enable = mkOption {
-        default = false;
-        type = types.bool;
-        description = "Whether to enable the Unbound domain name server.";
-      };
+      enable = mkEnableOption "Unbound domain name server";
 
       allowedAccess = mkOption {
-        default = ["127.0.0.0/24"];
+        default = [ "127.0.0.0/24" ];
         type = types.listOf types.str;
         description = "What networks are allowed to use unbound as a resolver.";
       };
@@ -97,7 +93,7 @@ in
     };
 
     systemd.services.unbound = {
-      description="Unbound recursive Domain Name Server";
+      description = "Unbound recursive Domain Name Server";
       after = [ "network.target" ];
       before = [ "nss-lookup.target" ];
       wants = [" nss-lookup.target" ];
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 8d22c10d3f78..de99ce4f0260 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -111,57 +111,54 @@ in {
     };
   };
 
-  config = mkMerge [
-    (mkIf cfg.enable {
-      assertions = flip mapAttrsToList cfg.networks (name: cfg: {
-        assertion = cfg.psk == null || cfg.pskRaw == null;
-        message = ''networking.wireless."${name}".psk and networking.wireless."${name}".pskRaw are mutually exclusive'';
-      });
-
-      environment.systemPackages =  [ pkgs.wpa_supplicant ];
-
-      services.dbus.packages = [ pkgs.wpa_supplicant ];
-
-      # FIXME: start a separate wpa_supplicant instance per interface.
-      systemd.services.wpa_supplicant = let
-        ifaces = cfg.interfaces;
-        deviceUnit = interface: [ "sys-subsystem-net-devices-${interface}.device" ];
-      in {
-        description = "WPA Supplicant";
-
-        after = [ "network-interfaces.target" ] ++ lib.concatMap deviceUnit ifaces;
-        requires = lib.concatMap deviceUnit ifaces;
-        wantedBy = [ "network.target" ];
-
-        path = [ pkgs.wpa_supplicant ];
-
-        script = ''
-          ${if ifaces == [] then ''
-            for i in $(cd /sys/class/net && echo *); do
-              DEVTYPE=
-              source /sys/class/net/$i/uevent
-              if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then
-                ifaces="$ifaces''${ifaces:+ -N} -i$i"
-              fi
-            done
-          '' else ''
-            ifaces="${concatStringsSep " -N " (map (i: "-i${i}") ifaces)}"
-          ''}
-          exec wpa_supplicant -s -u -D${cfg.driver} -c ${configFile} $ifaces
-        '';
-      };
-
-      powerManagement.resumeCommands = ''
-        ${config.systemd.package}/bin/systemctl try-restart wpa_supplicant
+  config = mkIf cfg.enable {
+    assertions = flip mapAttrsToList cfg.networks (name: cfg: {
+      assertion = cfg.psk == null || cfg.pskRaw == null;
+      message = ''networking.wireless."${name}".psk and networking.wireless."${name}".pskRaw are mutually exclusive'';
+    });
+
+    environment.systemPackages =  [ pkgs.wpa_supplicant ];
+
+    services.dbus.packages = [ pkgs.wpa_supplicant ];
+
+    # FIXME: start a separate wpa_supplicant instance per interface.
+    systemd.services.wpa_supplicant = let
+      ifaces = cfg.interfaces;
+      deviceUnit = interface: [ "sys-subsystem-net-devices-${interface}.device" ];
+    in {
+      description = "WPA Supplicant";
+
+      after = [ "network-interfaces.target" ] ++ lib.concatMap deviceUnit ifaces;
+      requires = lib.concatMap deviceUnit ifaces;
+      wantedBy = [ "network.target" ];
+
+      path = [ pkgs.wpa_supplicant ];
+
+      script = ''
+        ${if ifaces == [] then ''
+          for i in $(cd /sys/class/net && echo *); do
+            DEVTYPE=
+            source /sys/class/net/$i/uevent
+            if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then
+              ifaces="$ifaces''${ifaces:+ -N} -i$i"
+            fi
+          done
+        '' else ''
+          ifaces="${concatStringsSep " -N " (map (i: "-i${i}") ifaces)}"
+        ''}
+        exec wpa_supplicant -s -u -D${cfg.driver} -c ${configFile} $ifaces
       '';
+    };
 
-      # Restart wpa_supplicant when a wlan device appears or disappears.
-      services.udev.extraRules = ''
-        ACTION=="add|remove", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", RUN+="${config.systemd.package}/bin/systemctl try-restart wpa_supplicant.service"
-      '';
-    })
-    {
-      meta.maintainers = with lib.maintainers; [ globin ];
-    }
-  ];
+    powerManagement.resumeCommands = ''
+      ${config.systemd.package}/bin/systemctl try-restart wpa_supplicant
+    '';
+
+    # Restart wpa_supplicant when a wlan device appears or disappears.
+    services.udev.extraRules = ''
+      ACTION=="add|remove", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", RUN+="${config.systemd.package}/bin/systemctl try-restart wpa_supplicant.service"
+    '';
+  };
+
+  meta.maintainers = with lib.maintainers; [ globin ];
 }
diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix
index e66648f683f4..86e0204ec2f7 100644
--- a/nixos/modules/services/networking/zerotierone.nix
+++ b/nixos/modules/services/networking/zerotierone.nix
@@ -7,11 +7,19 @@ let
 in
 {
   options.services.zerotierone.enable = mkEnableOption "ZeroTierOne";
-  
+  options.services.zerotierone.package = mkOption {
+    default = pkgs.zerotierone;
+    defaultText = "pkgs.zerotierone";
+    type = types.package;
+    description = ''
+      ZeroTier One package to use.
+    '';
+  };
+
   config = mkIf cfg.enable {
     systemd.services.zerotierone = {
       description = "ZeroTierOne";
-      path = [ pkgs.zerotierone ];
+      path = [ cfg.package ];
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       preStart =
@@ -21,7 +29,7 @@ in
         chown -R root:root /var/lib/zerotier-one
         '';
       serviceConfig = {
-        ExecStart = "${pkgs.zerotierone}/bin/zerotier-one";
+        ExecStart = "${cfg.package}/bin/zerotier-one";
         Restart = "always";
         KillMode = "process";
       };
@@ -30,6 +38,6 @@ in
     # ZeroTier does not issue DHCP leases, but some strangers might...
     networking.dhcpcd.denyInterfaces = [ "zt0" ];
 
-    environment.systemPackages = [ pkgs.zerotierone ];
+    environment.systemPackages = [ cfg.package ];
   };
 }
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index 0bcb1a0c20c4..368d7ac761ac 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -4,7 +4,7 @@ with lib;
 
 let
 
-  inherit (pkgs) cups cups-pk-helper cups_filters gutenprint;
+  inherit (pkgs) cups cups-pk-helper cups-filters gutenprint;
 
   cfg = config.services.printing;
 
@@ -34,7 +34,7 @@ let
   bindir = pkgs.buildEnv {
     name = "cups-progs";
     paths =
-      [ cups.out additionalBackends cups_filters pkgs.ghostscript ]
+      [ cups.out additionalBackends cups-filters pkgs.ghostscript ]
       ++ optional cfg.gutenprint gutenprint
       ++ cfg.drivers;
     pathsToLink = [ "/lib/cups" "/share/cups" "/bin" ];
@@ -329,7 +329,7 @@ in
 
         path = [ cups ];
 
-        serviceConfig.ExecStart = "${cups_filters}/bin/cups-browsed";
+        serviceConfig.ExecStart = "${cups-filters}/bin/cups-browsed";
 
         restartTriggers = [ browsedFile ];
       };
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index af7753470de6..6e62606f323e 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -165,6 +165,8 @@ let
   mkLocations = locations: concatStringsSep "\n" (mapAttrsToList (location: config: ''
     location ${location} {
       ${optionalString (config.proxyPass != null) "proxy_pass ${config.proxyPass};"}
+      ${optionalString (config.index != null) "index ${config.index};"}
+      ${optionalString (config.tryFiles != null) "try_files ${config.tryFiles};"}
       ${optionalString (config.root != null) "root ${config.root};"}
       ${config.extraConfig}
     }
diff --git a/nixos/modules/services/web-servers/nginx/location-options.nix b/nixos/modules/services/web-servers/nginx/location-options.nix
index 8aaa3e96f800..e1885b160664 100644
--- a/nixos/modules/services/web-servers/nginx/location-options.nix
+++ b/nixos/modules/services/web-servers/nginx/location-options.nix
@@ -14,8 +14,25 @@ with lib;
       default = null;
       example = "http://www.example.org/";
       description = ''
-        Adds proxy_pass directive and sets default proxy headers Host, X-Real-Ip
-        and X-Forwarded-For.
+        Adds proxy_pass directive.
+      '';
+    };
+
+    index = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      example = "index.php index.html";
+      description = ''
+        Adds index directive.
+      '';
+    };
+
+    tryFiles = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      example = "$uri =404";
+      description = ''
+        Adds try_files directive.
       '';
     };
 
diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 2e788d869607..8a03dd65b335 100644
--- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix
+++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -29,7 +29,7 @@ in
   config = mkIf (xcfg.enable && cfg.enable) {
 
     environment.systemPackages = [
-      e.efl e.evas e.emotion e.elementary e.enlightenment
+      e.efl e.enlightenment
       e.terminology e.econnman
       pkgs.xorg.xauth # used by kdesu
       pkgs.gtk # To get GTK+'s themes.
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 1c928ff22a1f..75d80609f73f 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -306,7 +306,8 @@ in
   };
 
   imports = [
-   (mkRemovedOptionModule [ "services" "xserver" "displayManager" "desktopManagerHandlesLidAndPower" ])
+   (mkRemovedOptionModule [ "services" "xserver" "displayManager" "desktopManagerHandlesLidAndPower" ]
+     "The option is no longer necessary because all display managers have already delegated lid management to systemd.")
   ];
 
 }
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index 4489e34831da..1c587413121e 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -154,9 +154,15 @@ in
 
     system.activationScripts.tmpfs =
       ''
-        ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" none /dev
-        ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" none /dev/shm
-        ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" none /run
+        specialMount() {
+          local device="$1"
+          local mountPoint="$2"
+          local options="$3"
+          local fsType="$4"
+
+          ${pkgs.utillinux}/bin/mount -t "$fsType" -o "remount,$options" "$device" "$mountPoint"
+        }
+        source ${config.system.build.earlyMountScript}
       '';
 
   };
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 0640ec306e18..61c34cc2f034 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -341,7 +341,7 @@ in
         default = false;
         type = types.bool;
         description = ''
-          Whether GRUB should be build against libzfs.
+          Whether GRUB should be built against libzfs.
           ZFS support is only available for GRUB v2.
           This option is ignored for GRUB v1.
         '';
@@ -351,7 +351,7 @@ in
         default = false;
         type = types.bool;
         description = ''
-          Whether GRUB should be build with EFI support.
+          Whether GRUB should be built with EFI support.
           EFI support is only available for GRUB v2.
           This option is ignored for GRUB v1.
         '';
@@ -425,13 +425,20 @@ in
         { path = "/boot"; inherit (cfg) devices; inherit (efi) efiSysMountPoint; }
       ];
 
-      system.build.installBootLoader = pkgs.writeScript "install-grub.sh" (''
+      system.build.installBootLoader =
+        let
+          install-grub-pl = pkgs.substituteAll {
+            src = ./install-grub.pl;
+            inherit (pkgs) utillinux;
+            btrfsprogs = pkgs.btrfs-progs;
+          };
+        in pkgs.writeScript "install-grub.sh" (''
         #!${pkgs.stdenv.shell}
         set -e
         export PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX ListCompare ])}
         ${optionalString cfg.enableCryptodisk "export GRUB_ENABLE_CRYPTODISK=y"}
       '' + flip concatMapStrings cfg.mirroredBoots (args: ''
-        ${pkgs.perl}/bin/perl ${./install-grub.pl} ${grubConfig args} $@
+        ${pkgs.perl}/bin/perl ${install-grub-pl} ${grubConfig args} $@
       ''));
 
       system.build.grub = grub;
@@ -500,7 +507,7 @@ in
 
 
   imports =
-    [ (mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ])
+    [ (mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "")
       (mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ])
       (mkRenamedOptionModule [ "boot" "extraGrubEntries" ] [ "boot" "loader" "grub" "extraEntries" ])
       (mkRenamedOptionModule [ "boot" "extraGrubEntriesBeforeNixos" ] [ "boot" "loader" "grub" "extraEntriesBeforeNixOS" ])
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index 4fa157641a4a..06eece5025f8 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -12,8 +12,10 @@ require List::Compare;
 use POSIX;
 use Cwd;
 
+# system.build.toplevel path
 my $defaultConfig = $ARGV[1] or die;
 
+# Grub config XML generated by grubConfig function in grub.nix
 my $dom = XML::LibXML->load_xml(location => $ARGV[0]);
 
 sub get { my ($name) = @_; return $dom->findvalue("/expr/attrs/attr[\@name = '$name']/*/\@value"); }
@@ -97,6 +99,8 @@ sub PathInMount {
     }
     return 1;
 }
+
+# Figure out what filesystem is used for the directory with init/initrd/kernel files
 sub GetFs {
     my ($dir) = @_;
     my $bestFs = Fs->new(device => "", type => "", mount => "");
@@ -136,7 +140,10 @@ my $driveid = 1;
 sub GrubFs {
     my ($dir) = @_;
     my $fs = GetFs($dir);
-    my $path = "/" . substr($dir, length($fs->mount));
+    my $path = substr($dir, length($fs->mount));
+    if (substr($path, 0, 1) ne "/") {
+      $path = "/$path";
+    }
     my $search = "";
 
     if ($grubVersion > 1) {
@@ -169,7 +176,7 @@ sub GrubFs {
                 $search = $types{$fsIdentifier} . ' ';
 
                 # Based on the type pull in the identifier from the system
-                my ($status, @devInfo) = runCommand("blkid -o export @{[$fs->device]}");
+                my ($status, @devInfo) = runCommand("@utillinux@/bin/blkid -o export @{[$fs->device]}");
                 if ($status != 0) {
                     die "Failed to get blkid info for @{[$fs->mount]} on @{[$fs->device]}";
                 }
@@ -182,7 +189,7 @@ sub GrubFs {
 
             # BTRFS is a special case in that we need to fix the referrenced path based on subvolumes
             if ($fs->type eq 'btrfs') {
-                my ($status, @id_info) = runCommand("btrfs subvol show @{[$fs->mount]}");
+                my ($status, @id_info) = runCommand("@btrfsprogs@/bin/btrfs subvol show @{[$fs->mount]}");
                 if ($status != 0) {
                     die "Failed to retrieve subvolume info for @{[$fs->mount]}\n";
                 }
@@ -190,7 +197,7 @@ sub GrubFs {
                 if ($#ids > 0) {
                     die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
                 } elsif ($#ids == 0) {
-                    my ($status, @path_info) = runCommand("btrfs subvol list @{[$fs->mount]}");
+                    my ($status, @path_info) = runCommand("@btrfsprogs@/bin/btrfs subvol list @{[$fs->mount]}");
                     if ($status != 0) {
                         die "Failed to find @{[$fs->mount]} subvolume id from btrfs\n";
                     }
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 65d1dcb61681..abab5f20baac 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -59,22 +59,24 @@ echo
 echo "<<< NixOS Stage 1 >>>"
 echo
 
-
-# Mount special file systems.
+# Make several required directories.
 mkdir -p /etc/udev
 touch /etc/fstab # to shut up mount
-touch /etc/mtab # to shut up mke2fs
+ln -s /proc/mounts /etc/mtab # to shut up mke2fs
 touch /etc/udev/hwdb.bin # to shut up udev
 touch /etc/initrd-release
-mkdir -p /proc
-mount -t proc proc /proc
-mkdir -p /sys
-mount -t sysfs sysfs /sys
-mount -t devtmpfs -o "size=@devSize@" devtmpfs /dev
-mkdir -p /run
-mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
-mkdir /dev/pts
-mount -t devpts devpts /dev/pts
+
+# Mount special file systems.
+specialMount() {
+  local device="$1"
+  local mountPoint="$2"
+  local options="$3"
+  local fsType="$4"
+
+  mkdir -m 0755 -p "$mountPoint"
+  mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
+}
+source @earlyMountScript@
 
 # Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
 mkdir -p /tmp
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 9be7ad4ae077..513c121347b1 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -3,7 +3,7 @@
 # the modules necessary to mount the root file system, then calls the
 # init in the root file system to start the second boot stage.
 
-{ config, lib, pkgs, ... }:
+{ config, lib, utils, pkgs, ... }:
 
 with lib;
 
@@ -23,6 +23,12 @@ let
   };
 
 
+  # The initrd only has to mount `/` or any FS marked as necessary for
+  # booting (such as the FS containing `/nix/store`, or an FS needed for
+  # mounting `/`, like `/` on a loopback).
+  fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems;
+
+
   # Some additional utilities needed in stage 1, like mount, lvm, fsck
   # etc.  We don't want to bring in all of those packages, so we just
   # copy what we need.  Instead of using statically linked binaries,
@@ -71,7 +77,7 @@ let
       ln -sf kmod $out/bin/modprobe
 
       # Copy resize2fs if needed.
-      ${optionalString (any (fs: fs.autoResize) (attrValues config.fileSystems)) ''
+      ${optionalString (any (fs: fs.autoResize) fileSystems) ''
         # We need mke2fs in the initrd.
         copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs
       ''}
@@ -128,21 +134,6 @@ let
     ''; # */
 
 
-  # The initrd only has to mount / or any FS marked as necessary for
-  # booting (such as the FS containing /nix/store, or an FS needed for
-  # mounting /, like / on a loopback).
-  #
-  # We need to guarantee that / is the first filesystem in the list so
-  # that if and when lustrateRoot is invoked, nothing else is mounted
-  fileSystems = let
-    filterNeeded = filter
-      (fs: fs.mountPoint != "/" && (fs.neededForBoot || elem fs.mountPoint [ "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ]));
-    filterRoot = filter
-      (fs: fs.mountPoint == "/");
-    allFileSystems = attrValues config.fileSystems;
-  in (filterRoot allFileSystems) ++ (filterNeeded allFileSystems);
-
-
   udevRules = pkgs.stdenv.mkDerivation {
     name = "udev-rules";
     allowedReferences = [ extraUtils ];
@@ -199,7 +190,9 @@ let
 
     inherit udevRules extraUtils modulesClosure;
 
-    inherit (config.boot) resumeDevice devSize runSize;
+    inherit (config.boot) resumeDevice;
+
+    inherit (config.system.build) earlyMountScript;
 
     inherit (config.boot.initrd) checkJournalingFS
       preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules;
@@ -405,9 +398,8 @@ in
   };
 
   config = mkIf (!config.boot.isContainer) {
-
     assertions = [
-      { assertion = any (fs: fs.mountPoint == "/") (attrValues config.fileSystems);
+      { assertion = any (fs: fs.mountPoint == "/") fileSystems;
         message = "The ‘fileSystems’ option does not specify your root file system.";
       }
       { assertion = let inherit (config.boot) resumeDevice; in
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index c5a14f0766d5..704150e77d72 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -37,12 +37,16 @@ fi
 # Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
 # stage 1, we need to do that here.
 if [ ! -e /proc/1 ]; then
-    mkdir -m 0755 -p /proc
-    mount -n -t proc proc /proc
-    mkdir -m 0755 -p /dev
-    mount -t devtmpfs devtmpfs /dev
-    mkdir -m 0755 -p /sys
-    mount -t sysfs sysfs /sys
+    specialMount() {
+        local device="$1"
+        local mountPoint="$2"
+        local options="$3"
+        local fsType="$4"
+
+        mkdir -m 0755 -p "$mountPoint"
+        mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
+    }
+    source @earlyMountScript@
 fi
 
 
@@ -87,11 +91,6 @@ done
 
 
 # More special file systems, initialise required directories.
-if ! mountpoint -q /dev/shm; then
-    mkdir -m 0755 /dev/shm
-    mount -t tmpfs -o "rw,nosuid,nodev,size=@devShmSize@" tmpfs /dev/shm
-fi
-mkdir -m 0755 -p /dev/pts
 [ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default
 mkdir -m 01777 -p /tmp
 mkdir -m 0755 -p /var /var/log /var/lib /var/db
@@ -112,14 +111,6 @@ rm -f /etc/{group,passwd,shadow}.lock
 rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots
 
 
-# Create a tmpfs on /run to hold runtime state for programs such as
-# udev (if stage 1 hasn't already done so).
-if ! mountpoint -q /run; then
-    rm -rf /run
-    mkdir -m 0755 -p /run
-    mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
-fi
-
 # Create a ramfs on /run/keys to hold secrets that shouldn't be
 # written to disk (generally used for NixOps, harmless elsewhere).
 if ! mountpoint -q /run/keys; then
@@ -150,13 +141,6 @@ if [ -n "@useHostResolvConf@" -a -e /etc/resolv.conf ]; then
     cat /etc/resolv.conf | resolvconf -m 1000 -a host
 fi
 
-
-# Create /var/setuid-wrappers as a tmpfs.
-rm -rf /var/setuid-wrappers
-mkdir -m 0755 -p /var/setuid-wrappers
-mount -t tmpfs -o "mode=0755" tmpfs /var/setuid-wrappers
-
-
 # Log the script output to /dev/kmsg or /run/log/stage-2-init.log.
 # Only at this point are all the necessary prerequisites ready for these commands.
 exec {logOutFd}>&1 {logErrFd}>&2
diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix
index b67f42a017e6..7e4ec2a4a670 100644
--- a/nixos/modules/system/boot/stage-2.nix
+++ b/nixos/modules/system/boot/stage-2.nix
@@ -20,10 +20,9 @@ let
     src = ./stage-2-init.sh;
     shellDebug = "${pkgs.bashInteractive}/bin/bash";
     isExecutable = true;
-    inherit (config.boot) devShmSize runSize;
     inherit (config.nix) readOnlyStore;
     inherit (config.networking) useHostResolvConf;
-    ttyGid = config.ids.gids.tty;
+    inherit (config.system.build) earlyMountScript;
     path =
       [ pkgs.coreutils
         pkgs.utillinux
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index f2a22e4ada8a..f4892244de47 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -309,7 +309,7 @@ in rec {
     };
 
     startAt = mkOption {
-      type = types.str;
+      type = with types; either str (listOf str);
       default = "";
       example = "Sun 14:00:00";
       description = ''
diff --git a/nixos/modules/tasks/cpu-freq.nix b/nixos/modules/tasks/cpu-freq.nix
index 2fe7f4f8197a..5f8b5df52acf 100644
--- a/nixos/modules/tasks/cpu-freq.nix
+++ b/nixos/modules/tasks/cpu-freq.nix
@@ -19,7 +19,7 @@ in
       description = ''
         Configure the governor used to regulate the frequence of the
         available CPUs. By default, the kernel configures the
-        on-demand governor.
+        performance governor.
       '';
     };
 
diff --git a/nixos/modules/tasks/encrypted-devices.nix b/nixos/modules/tasks/encrypted-devices.nix
index 457b86e95ab5..b1a7711ddcb4 100644
--- a/nixos/modules/tasks/encrypted-devices.nix
+++ b/nixos/modules/tasks/encrypted-devices.nix
@@ -3,7 +3,7 @@
 with lib;
 
 let
-  fileSystems = attrValues config.fileSystems ++ config.swapDevices;
+  fileSystems = config.system.build.fileSystems ++ config.swapDevices;
   encDevs = filter (dev: dev.encrypted.enable) fileSystems;
   keyedEncDevs = filter (dev: dev.encrypted.keyFile != null) encDevs;
   keylessEncDevs = filter (dev: dev.encrypted.keyFile == null) encDevs;
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index cf8232c36154..a66ece1020f8 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -5,11 +5,22 @@ with utils;
 
 let
 
-  fileSystems = attrValues config.fileSystems;
+  fileSystems' = toposort fsBefore (attrValues config.fileSystems);
+
+  fileSystems = if fileSystems' ? "result"
+                then # use topologically sorted fileSystems everywhere
+                     fileSystems'.result
+                else # the assertion below will catch this,
+                     # but we fall back to the original order
+                     # anyway so that other modules could check
+                     # their assertions too
+                     (attrValues config.fileSystems);
 
   prioOption = prio: optionalString (prio != null) " pri=${toString prio}";
 
-  fileSystemOpts = { name, config, ... }: {
+  specialFSTypes = [ "proc" "sysfs" "tmpfs" "devtmpfs" "devpts" ];
+
+  coreFileSystemOpts = { name, config, ... }: {
 
     options = {
 
@@ -26,13 +37,6 @@ let
         description = "Location of the device.";
       };
 
-      label = mkOption {
-        default = null;
-        example = "root-partition";
-        type = types.nullOr types.str;
-        description = "Label of the device (if any).";
-      };
-
       fsType = mkOption {
         default = "auto";
         example = "ext3";
@@ -44,12 +48,28 @@ let
         default = [ "defaults" ];
         example = [ "data=journal" ];
         description = "Options used to mount the file system.";
-      } // (if versionAtLeast lib.nixpkgsVersion "16.09" then {
         type = types.listOf types.str;
-      } else {
-        type = types.either types.commas (types.listOf types.str);
-        apply = x: if isList x then x else lib.strings.splitString "," (builtins.trace "warning: passing a comma-separated string for filesystem options is deprecated; use a list of strings instead. This will become a hard error in 16.09." x);
-      });
+      };
+
+    };
+
+    config = {
+      mountPoint = mkDefault name;
+      device = mkIf (elem config.fsType specialFSTypes) (mkDefault config.fsType);
+    };
+
+  };
+
+  fileSystemOpts = { config, ... }: {
+
+    options = {
+
+      label = mkOption {
+        default = null;
+        example = "root-partition";
+        type = types.nullOr types.str;
+        description = "Label of the device (if any).";
+      };
 
       autoFormat = mkOption {
         default = false;
@@ -91,8 +111,6 @@ let
     };
 
     config = {
-      mountPoint = mkDefault name;
-      device = mkIf (config.fsType == "tmpfs") (mkDefault config.fsType);
       options = mkIf config.autoResize [ "x-nixos.autoresize" ];
 
       # -F needed to allow bare block device without partitions
@@ -101,6 +119,13 @@ let
 
   };
 
+  # Makes sequence of `specialMount device mountPoint options fsType` commands.
+  # `systemMount` should be defined in the sourcing script.
+  makeSpecialMounts = mounts:
+    pkgs.writeText "mounts.sh" (concatMapStringsSep "\n" (mount: ''
+      specialMount "${mount.device}" "${mount.mountPoint}" "${concatStringsSep "," mount.options}" "${mount.fsType}"
+    '') mounts);
+
 in
 
 {
@@ -122,8 +147,7 @@ in
           "/bigdisk".label = "bigdisk";
         }
       '';
-      type = types.loaOf types.optionSet;
-      options = [ fileSystemOpts ];
+      type = types.loaOf (types.submodule [coreFileSystemOpts fileSystemOpts]);
       description = ''
         The file systems to be mounted.  It must include an entry for
         the root directory (<literal>mountPoint = "/"</literal>).  Each
@@ -155,6 +179,15 @@ in
       description = "Names of supported filesystem types.";
     };
 
+    boot.specialFileSystems = mkOption {
+      default = {};
+      type = types.loaOf (types.submodule coreFileSystemOpts);
+      internal = true;
+      description = ''
+        Special filesystems that are mounted very early during boot.
+      '';
+    };
+
   };
 
 
@@ -162,6 +195,18 @@ in
 
   config = {
 
+    assertions = let
+      ls = sep: concatMapStringsSep sep (x: x.mountPoint);
+    in [
+      { assertion = ! (fileSystems' ? "cycle");
+        message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";
+      }
+    ];
+
+    # Export for use in other modules
+    system.build.fileSystems = fileSystems;
+    system.build.earlyMountScript = makeSpecialMounts (toposort fsBefore (attrValues config.boot.specialFileSystems)).result;
+
     boot.supportedFilesystems = map (fs: fs.fsType) fileSystems;
 
     # Add the mount helpers to the system path so that `mount' can find them.
@@ -175,9 +220,12 @@ in
         skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck;
       in ''
         # This is a generated file.  Do not edit!
+        #
+        # To make changes, edit the fileSystems and swapDevices NixOS options
+        # in your /etc/nixos/configuration.nix file.
 
         # Filesystems.
-        ${flip concatMapStrings fileSystems (fs:
+        ${concatMapStrings (fs:
             (if fs.device != null then fs.device
              else if fs.label != null then "/dev/disk/by-label/${fs.label}"
              else throw "No device specified for mount point ‘${fs.mountPoint}’.")
@@ -188,7 +236,7 @@ in
             + " " + (if skipCheck fs then "0" else
                      if fs.mountPoint == "/" then "1" else "2")
             + "\n"
-        )}
+        ) fileSystems}
 
         # Swap devices.
         ${flip concatMapStrings config.swapDevices (sw:
@@ -208,14 +256,15 @@ in
 
         formatDevice = fs:
           let
-            mountPoint' = escapeSystemdPath fs.mountPoint;
-            device' = escapeSystemdPath fs.device;
+            mountPoint' = "${escapeSystemdPath fs.mountPoint}.mount";
+            device'  = escapeSystemdPath fs.device;
+            device'' = "${device}.device";
           in nameValuePair "mkfs-${device'}"
           { description = "Initialisation of Filesystem ${fs.device}";
-            wantedBy = [ "${mountPoint'}.mount" ];
-            before = [ "${mountPoint'}.mount" "systemd-fsck@${device'}.service" ];
-            requires = [ "${device'}.device" ];
-            after = [ "${device'}.device" ];
+            wantedBy = [ mountPoint' ];
+            before = [ mountPoint' "systemd-fsck@${device'}.service" ];
+            requires = [ device'' ];
+            after = [ device'' ];
             path = [ pkgs.utillinux ] ++ config.system.fsPackages;
             script =
               ''
@@ -234,6 +283,16 @@ in
 
       in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
 
+    # Sync mount options with systemd's src/core/mount-setup.c: mount_table.
+    boot.specialFileSystems = {
+      "/proc" = { fsType = "proc"; options = [ "nosuid" "noexec" "nodev" ]; };
+      "/sys" = { fsType = "sysfs"; options = [ "nosuid" "noexec" "nodev" ]; };
+      "/run" = { fsType = "tmpfs"; options = [ "nodev" "strictatime" "mode=755" "size=${config.boot.runSize}" ]; };
+      "/dev" = { fsType = "devtmpfs"; options = [ "nosuid" "strictatime" "mode=755" "size=${config.boot.devSize}" ]; };
+      "/dev/shm" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=1777" "size=${config.boot.devShmSize}" ]; };
+      "/dev/pts" = { fsType = "devpts"; options = [ "nosuid" "noexec" "mode=620" "gid=${toString config.ids.gids.tty}" ]; };
+    };
+
   };
 
 }
diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix
index 4ff3ffc74b16..c5f41cc338cf 100644
--- a/nixos/modules/tasks/filesystems/zfs.nix
+++ b/nixos/modules/tasks/filesystems/zfs.nix
@@ -36,13 +36,11 @@ let
 
   fsToPool = fs: datasetToPool fs.device;
 
-  zfsFilesystems = filter (x: x.fsType == "zfs") (attrValues config.fileSystems);
-
-  isRoot = fs: fs.neededForBoot || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ];
+  zfsFilesystems = filter (x: x.fsType == "zfs") config.system.build.fileSystems;
 
   allPools = unique ((map fsToPool zfsFilesystems) ++ cfgZfs.extraPools);
 
-  rootPools = unique (map fsToPool (filter isRoot zfsFilesystems));
+  rootPools = unique (map fsToPool (filter fsNeededForBoot zfsFilesystems));
 
   dataPools = unique (filter (pool: !(elem pool rootPools)) allPools);
 
@@ -277,7 +275,7 @@ in
 
       systemd.services = let
         getPoolFilesystems = pool:
-          filter (x: x.fsType == "zfs" && (fsToPool x) == pool) (attrValues config.fileSystems);
+          filter (x: x.fsType == "zfs" && (fsToPool x) == pool) config.system.build.fileSystems;
 
         getPoolMounts = pool:
           let
diff --git a/nixos/modules/virtualisation/amazon-grow-partition.nix b/nixos/modules/virtualisation/amazon-grow-partition.nix
deleted file mode 100644
index 69b80d900bad..000000000000
--- a/nixos/modules/virtualisation/amazon-grow-partition.nix
+++ /dev/null
@@ -1,24 +0,0 @@
-# This module automatically grows the root partition on Amazon EC2 HVM
-# instances. This allows an instance to be created with a bigger root
-# filesystem than provided by the AMI.
-
-{ config, lib, pkgs, ... }:
-
-{
-  config = lib.mkIf config.ec2.hvm {
-    boot.initrd.extraUtilsCommands = ''
-      copy_bin_and_libs ${pkgs.gawk}/bin/gawk
-      copy_bin_and_libs ${pkgs.gnused}/bin/sed
-      copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
-      cp -v ${pkgs.cloud-utils}/bin/growpart $out/bin/growpart
-      ln -s sed $out/bin/gnused
-    '';
-
-    boot.initrd.postDeviceCommands = ''
-      if [ -e /dev/xvda ] && [ -e /dev/xvda1 ]; then
-        TMPDIR=/run sh $(type -P growpart) /dev/xvda 1
-        udevadm settle
-      fi
-    '';
-  };
-}
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index ebf398fa266f..f9c3f2e53adc 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -11,10 +11,12 @@ with lib;
 let cfg = config.ec2; in
 
 {
-  imports = [ ../profiles/headless.nix ./ec2-data.nix ./amazon-grow-partition.nix ./amazon-init.nix ];
+  imports = [ ../profiles/headless.nix ./ec2-data.nix ./grow-partition.nix ./amazon-init.nix ];
 
   config = {
 
+    virtualisation.growPartition = cfg.hvm;
+
     fileSystems."/" = {
       device = "/dev/disk/by-label/nixos";
       autoResize = true;
diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix
index 760a7100c6e0..ab49d8871f85 100644
--- a/nixos/modules/virtualisation/brightbox-image.nix
+++ b/nixos/modules/virtualisation/brightbox-image.nix
@@ -20,7 +20,7 @@ in
 
           postVM =
             ''
-              PATH=$PATH:${stdenv.lib.makeBinPath [ pkgs.gnutar pkgs.gzip ]}
+              PATH=$PATH:${lib.makeBinPath [ pkgs.gnutar pkgs.gzip ]}
               pushd $out
               ${pkgs.qemu_kvm}/bin/qemu-img convert -c -O qcow2 $diskImageBase nixos.qcow2
               rm $diskImageBase
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index d83841452f95..413aa94339f1 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -340,6 +340,20 @@ in
                 A specification of the desired configuration of this
                 container, as a NixOS module.
               '';
+              type = lib.mkOptionType {
+                name = "Toplevel NixOS config";
+                merge = loc: defs: (import ../../lib/eval-config.nix {
+                  inherit system;
+                  modules =
+                    let extraConfig =
+                      { boot.isContainer = true;
+                        networking.hostName = mkDefault name;
+                        networking.useDHCP = false;
+                      };
+                    in [ extraConfig ] ++ (map (x: x.value) defs);
+                  prefix = [ "containers" name ];
+                }).config;
+              };
             };
 
             path = mkOption {
@@ -410,18 +424,9 @@ in
           } // networkOptions;
 
           config = mkMerge
-            [ (mkIf options.config.isDefined {
-                path = (import ../../lib/eval-config.nix {
-                  inherit system;
-                  modules =
-                    let extraConfig =
-                      { boot.isContainer = true;
-                        networking.hostName = mkDefault name;
-                        networking.useDHCP = false;
-                      };
-                    in [ extraConfig config.config ];
-                  prefix = [ "containers" name ];
-                }).config.system.build.toplevel;
+            [
+              (mkIf options.config.isDefined {
+                path = config.config.system.build.toplevel;
               })
             ];
         }));
diff --git a/nixos/modules/virtualisation/grow-partition.nix b/nixos/modules/virtualisation/grow-partition.nix
new file mode 100644
index 000000000000..abc2e766959e
--- /dev/null
+++ b/nixos/modules/virtualisation/grow-partition.nix
@@ -0,0 +1,43 @@
+# This module automatically grows the root partition on virtual machines.
+# This allows an instance to be created with a bigger root filesystem
+# than provided by the machine image.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  options = {
+
+    virtualisation.growPartition = mkOption {
+      type = types.bool;
+      default = true;
+    };
+
+  };
+
+  config = mkIf config.virtualisation.growPartition {
+
+    boot.initrd.extraUtilsCommands = ''
+      copy_bin_and_libs ${pkgs.gawk}/bin/gawk
+      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
+      ln -s sed $out/bin/gnused
+    '';
+
+    boot.initrd.postDeviceCommands = ''
+      rootDevice="${config.fileSystems."/".device}"
+      if [ -e "$rootDevice" ]; then
+        rootDevice="$(readlink -f "$rootDevice")"
+        parentDevice="$(lsblk -npo PKNAME "$rootDevice")"
+        TMPDIR=/run sh $(type -P growpart) "$parentDevice" "''${rootDevice#$parentDevice}"
+        udevadm settle
+      fi
+    '';
+
+  };
+
+}
diff --git a/nixos/modules/virtualisation/qemu-opts b/nixos/modules/virtualisation/qemu-opts
deleted file mode 100644
index f06a5136608a..000000000000
--- a/nixos/modules/virtualisation/qemu-opts
+++ /dev/null
@@ -1,4 +0,0 @@
-          -device virtio-serial \
-          -chardev socket,id=charconsole0,path=/tmp/nixos-socket,server,nowait \
-          #-device virtconsole,chardev=charconsole0,id=console0 \
-          -device virtserialport,chardev=chardev=charconsole0,id=serial0
diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index 5fb472ebfc32..ce4abecd6762 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -5,7 +5,7 @@ with lib;
 let
   cfg = config.virtualisation.virtualbox.host;
   virtualbox = config.boot.kernelPackages.virtualbox.override {
-    inherit (cfg) enableHardening;
+    inherit (cfg) enableHardening headless;
   };
 
 in
@@ -47,6 +47,15 @@ in
         </para></important>
       '';
     };
+
+    headless = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Use VirtualBox installation without GUI and Qt dependency. Useful to enable on servers
+        and when virtual machines are controlled only via SSH.
+      '';
+    };
   };
 
   config = mkIf cfg.enable (mkMerge [{
diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix
index fab59b2525a5..b6a5b3e4788d 100644
--- a/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixos/modules/virtualisation/virtualbox-image.nix
@@ -8,6 +8,8 @@ let
 
 in {
 
+  imports = [ ./grow-partition.nix ];
+
   options = {
     virtualbox = {
       baseImageSize = mkOption {
@@ -29,22 +31,15 @@ in {
       partitioned = true;
       diskSize = cfg.baseImageSize;
 
-      configFile = pkgs.writeText "configuration.nix"
-        ''
-          {
-            imports = [ <nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix> ];
-          }
-        '';
-
       postVM =
         ''
-          echo "creating VirtualBox disk image..."
-          ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vdi $diskImage disk.vdi
-          rm $diskImage
-
-          echo "creating VirtualBox VM..."
           export HOME=$PWD
           export PATH=${pkgs.linuxPackages.virtualbox}/bin:$PATH
+
+          echo "creating VirtualBox pass-through disk wrapper (no copying invovled)..."
+          VBoxManage internalcommands createrawvmdk -filename disk.vmdk -rawdisk $diskImage
+
+          echo "creating VirtualBox VM..."
           vmName="NixOS ${config.system.nixosLabel} (${pkgs.stdenv.system})"
           VBoxManage createvm --name "$vmName" --register \
             --ostype ${if pkgs.stdenv.system == "x86_64-linux" then "Linux26_64" else "Linux26"}
@@ -57,19 +52,24 @@ in {
             --usb on --mouse usbtablet
           VBoxManage storagectl "$vmName" --name SATA --add sata --portcount 4 --bootable on --hostiocache on
           VBoxManage storageattach "$vmName" --storagectl SATA --port 0 --device 0 --type hdd \
-            --medium disk.vdi
+            --medium disk.vmdk
 
           echo "exporting VirtualBox VM..."
           mkdir -p $out
           fn="$out/nixos-${config.system.nixosLabel}-${pkgs.stdenv.system}.ova"
           VBoxManage export "$vmName" --output "$fn"
 
+          rm -v $diskImage
+
           mkdir -p $out/nix-support
           echo "file ova $fn" >> $out/nix-support/hydra-build-products
         '';
     };
 
-    fileSystems."/".device = "/dev/disk/by-label/nixos";
+    fileSystems."/" = {
+      device = "/dev/disk/by-label/nixos";
+      autoResize = true;
+    };
 
     boot.loader.grub.device = "/dev/sda";
 
diff --git a/nixos/release.nix b/nixos/release.nix
index 70a7ba5af89d..a5b4ab5f04cf 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -234,6 +234,7 @@ in rec {
   tests.etcd = hydraJob (import tests/etcd.nix { system = "x86_64-linux"; });
   tests.ec2-nixops = hydraJob (import tests/ec2.nix { system = "x86_64-linux"; }).boot-ec2-nixops;
   tests.ec2-config = hydraJob (import tests/ec2.nix { system = "x86_64-linux"; }).boot-ec2-config;
+  tests.ferm = callTest tests/ferm.nix {};
   tests.firefox = callTest tests/firefox.nix {};
   tests.firewall = callTest tests/firewall.nix {};
   tests.fleet = hydraJob (import tests/fleet.nix { system = "x86_64-linux"; });
@@ -279,6 +280,7 @@ in rec {
   tests.printing = callTest tests/printing.nix {};
   tests.proxy = callTest tests/proxy.nix {};
   tests.pumpio = callTest tests/pump.io.nix {};
+  tests.quagga = callTest tests/quagga.nix {};
   tests.quake3 = callTest tests/quake3.nix {};
   tests.runInMachine = callTest tests/run-in-machine.nix {};
   tests.sddm = callTest tests/sddm.nix {};
diff --git a/nixos/tests/boot-stage1.nix b/nixos/tests/boot-stage1.nix
index ad253d23c543..ccd8394a1f03 100644
--- a/nixos/tests/boot-stage1.nix
+++ b/nixos/tests/boot-stage1.nix
@@ -8,6 +8,7 @@ import ./make-test.nix ({ pkgs, ... }: {
         kdev = config.boot.kernelPackages.kernel.dev;
         kver = config.boot.kernelPackages.kernel.modDirVersion;
         ksrc = "${kdev}/lib/modules/${kver}/build";
+        hardeningDisable = [ "pic" ];
       } ''
         echo "obj-m += $name.o" > Makefile
         echo "$source" > "$name.c"
diff --git a/nixos/tests/ferm.nix b/nixos/tests/ferm.nix
new file mode 100644
index 000000000000..8f2a8c01eebc
--- /dev/null
+++ b/nixos/tests/ferm.nix
@@ -0,0 +1,72 @@
+
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "ferm";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ mic92 ];
+  };
+
+  nodes =
+    { client =
+        { config, pkgs, ... }:
+        with pkgs.lib;
+        {
+          networking = {
+            interfaces.eth1.ip6 = mkOverride 0 [ { address = "fd00::2"; prefixLength = 64; } ];
+            interfaces.eth1.ip4 = mkOverride 0 [ { address = "192.168.1.2"; prefixLength = 24; } ];
+          };
+      };
+      server =
+        { config, pkgs, ... }:
+        with pkgs.lib;
+        {
+          networking = {
+            interfaces.eth1.ip6 = mkOverride 0 [ { address = "fd00::1"; prefixLength = 64; } ];
+            interfaces.eth1.ip4 = mkOverride 0 [ { address = "192.168.1.1"; prefixLength = 24; } ];
+          };
+
+          services = {
+            ferm.enable = true;
+            ferm.config = ''
+              domain (ip ip6) table filter chain INPUT {
+                interface lo ACCEPT;
+                proto tcp dport 8080 REJECT reject-with tcp-reset;
+              }
+            '';
+            nginx.enable = true;
+            nginx.httpConfig = ''
+              server {
+                listen 80;
+                listen [::]:80;
+                listen 8080;
+                listen [::]:8080;
+
+                location /status { stub_status on; }
+              }
+            '';
+          };
+        };
+    };
+
+  testScript =
+    ''
+      startAll;
+
+      $client->waitForUnit("network.target");
+      $server->waitForUnit("ferm.service");
+      $server->waitForUnit("nginx.service");
+      $server->waitUntilSucceeds("ss -ntl | grep -q 80");
+
+      subtest "port 80 is allowed", sub {
+          $client->succeed("curl --fail -g http://192.168.1.1:80/status");
+          $client->succeed("curl --fail -g http://[fd00::1]:80/status");
+      };
+
+      subtest "port 8080 is not allowed", sub {
+          $server->succeed("curl --fail -g http://192.168.1.1:8080/status");
+          $server->succeed("curl --fail -g http://[fd00::1]:8080/status");
+
+          $client->fail("curl --fail -g http://192.168.1.1:8080/status");
+          $client->fail("curl --fail -g http://[fd00::1]:8080/status");
+      };
+    '';
+})
diff --git a/nixos/tests/postgis.nix b/nixos/tests/postgis.nix
new file mode 100644
index 000000000000..1dba5c363c09
--- /dev/null
+++ b/nixos/tests/postgis.nix
@@ -0,0 +1,30 @@
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "postgis";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ lsix ];
+  };
+
+  nodes = {
+    master =
+      { pkgs, config, ... }:
+
+      {
+        services.postgresql = let mypg = pkgs.postgresql95; in {
+            enable = true;
+            package = mypg;
+            extraPlugins = [ (pkgs.postgis.override { postgresql = mypg; }).v_2_2_1 ];
+            initialScript =  pkgs.writeText "postgresql-init.sql"
+          ''
+          CREATE ROLE postgres WITH superuser login createdb;
+          '';
+          };
+      };
+  };
+
+  testScript = ''
+    startAll;
+    $master->waitForUnit("postgresql");
+    $master->sleep(10); # Hopefully this is long enough!!
+    $master->succeed("sudo -u postgres psql -c 'CREATE EXTENSION postgis;'");
+  '';
+})
diff --git a/nixos/tests/quagga.nix b/nixos/tests/quagga.nix
new file mode 100644
index 000000000000..b9644b4768c0
--- /dev/null
+++ b/nixos/tests/quagga.nix
@@ -0,0 +1,97 @@
+# This test runs Quagga and checks if OSPF routing works.
+#
+# Network topology:
+#   [ client ]--net1--[ router1 ]--net2--[ router2 ]--net3--[ server ]
+#
+# All interfaces are in OSPF Area 0.
+
+import ./make-test.nix ({ pkgs, ... }:
+  let
+
+    ifAddr = node: iface: (pkgs.lib.head node.config.networking.interfaces.${iface}.ip4).address;
+
+    ospfConf = ''
+      interface eth2
+        ip ospf hello-interval 1
+        ip ospf dead-interval 5
+      !
+      router ospf
+        network 192.168.0.0/16 area 0
+    '';
+
+  in
+    {
+      name = "quagga";
+
+      meta = with pkgs.stdenv.lib.maintainers; {
+        maintainers = [ tavyc ];
+      };
+
+      nodes = {
+
+        client =
+          { config, pkgs, nodes, ... }:
+          {
+            virtualisation.vlans = [ 1 ];
+            networking.defaultGateway = ifAddr nodes.router1 "eth1";
+          };
+
+        router1 =
+          { config, pkgs, nodes, ... }:
+          {
+            virtualisation.vlans = [ 1 2 ];
+            boot.kernel.sysctl."net.ipv4.ip_forward" = "1";
+            networking.firewall.extraCommands = "iptables -A nixos-fw -i eth2 -p ospf -j ACCEPT";
+            services.quagga.ospf = {
+              enable = true;
+              config = ospfConf;
+            };
+          };
+
+        router2 =
+          { config, pkgs, nodes, ... }:
+          {
+            virtualisation.vlans = [ 3 2 ];
+            boot.kernel.sysctl."net.ipv4.ip_forward" = "1";
+            networking.firewall.extraCommands = "iptables -A nixos-fw -i eth2 -p ospf -j ACCEPT";
+            services.quagga.ospf = {
+              enable = true;
+              config = ospfConf;
+            };
+          };
+
+        server =
+          { config, pkgs, nodes, ... }:
+          {
+            virtualisation.vlans = [ 3 ];
+            networking.defaultGateway = ifAddr nodes.router2 "eth1";
+            networking.firewall.allowedTCPPorts = [ 80 ];
+            networking.firewall.allowPing = true;
+            services.httpd.enable = true;
+            services.httpd.adminAddr = "foo@example.com";
+          };
+      };
+
+      testScript =
+        { nodes, ... }:
+        ''
+          startAll;
+
+          # Wait for the networking to start on all machines
+          $_->waitForUnit("network.target") foreach values %vms;
+
+          # Wait for OSPF to form adjacencies
+          for my $gw ($router1, $router2) {
+              $gw->waitForUnit("ospfd");
+              $gw->waitUntilSucceeds("vtysh -c 'show ip ospf neighbor' | grep Full");
+              $gw->waitUntilSucceeds("vtysh -c 'show ip route' | grep '^O>'");
+          }
+
+          # Test ICMP.
+          $client->succeed("ping -c 3 server >&2");
+
+          # Test whether HTTP works.
+          $server->waitForUnit("httpd");
+          $client->succeed("curl --fail http://server/ >&2");
+        '';
+    })
diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix
index e85ff2380893..ab4d46ab7e15 100644
--- a/nixos/tests/virtualbox.nix
+++ b/nixos/tests/virtualbox.nix
@@ -314,6 +314,9 @@ let
 
     test2.vmFlags = hostonlyVMFlags;
     test2.vmScript = dhcpScript;
+
+    headless.virtualisation.virtualbox.headless = true;
+    headless.services.xserver.enable = false;
   };
 
   mkVBoxTest = name: testScript: makeTest {
@@ -402,6 +405,14 @@ in mapAttrs mkVBoxTest {
     shutdownVM_simple;
   '';
 
+  headless = ''
+    createVM_headless;
+    $machine->succeed(ru("VBoxHeadless --startvm headless & disown %1"));
+    waitForStartup_headless;
+    waitForVMBoot_headless;
+    shutdownVM_headless;
+  '';
+
   host-usb-permissions = ''
     my $userUSB = removeUUIDs vbm("list usbhost");
     print STDERR $userUSB;