summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/fonts/fonts.nix14
-rw-r--r--nixos/modules/config/gnu.nix1
-rw-r--r--nixos/modules/config/networking.nix10
-rw-r--r--nixos/modules/config/pulseaudio.nix2
-rw-r--r--nixos/modules/config/swap.nix8
-rw-r--r--nixos/modules/config/system-path.nix6
-rw-r--r--nixos/modules/config/update-users-groups.pl4
-rw-r--r--nixos/modules/hardware/opengl.nix2
-rw-r--r--nixos/modules/hardware/video/displaylink.nix61
-rw-r--r--nixos/modules/i18n/input-method/default.nix34
-rw-r--r--nixos/modules/i18n/input-method/fcitx.nix7
-rw-r--r--nixos/modules/i18n/input-method/ibus.nix7
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix11
-rw-r--r--nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix2
-rw-r--r--nixos/modules/installer/tools/nix-fallback-paths.nix5
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl5
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh14
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh4
-rw-r--r--nixos/modules/installer/tools/tools.nix14
-rw-r--r--nixos/modules/misc/ids.nix18
-rw-r--r--nixos/modules/misc/meta.nix8
-rw-r--r--nixos/modules/misc/nixpkgs.nix5
-rw-r--r--nixos/modules/misc/version.nix2
-rw-r--r--nixos/modules/module-list.nix23
-rw-r--r--nixos/modules/profiles/base.nix2
-rw-r--r--nixos/modules/profiles/minimal.nix3
-rw-r--r--nixos/modules/programs/bash/bash.nix2
-rw-r--r--nixos/modules/programs/info.nix30
-rw-r--r--nixos/modules/programs/shadow.nix1
-rw-r--r--nixos/modules/programs/ssh.nix4
-rw-r--r--nixos/modules/programs/zsh/zsh.nix11
-rw-r--r--nixos/modules/rename.nix72
-rw-r--r--nixos/modules/security/acme.nix10
-rw-r--r--nixos/modules/security/audit.nix16
-rw-r--r--nixos/modules/security/grsecurity.nix9
-rw-r--r--nixos/modules/security/grsecurity.xml345
-rw-r--r--nixos/modules/security/hidepid.nix43
-rw-r--r--nixos/modules/security/hidepid.xml33
-rw-r--r--nixos/modules/security/pam.nix21
-rw-r--r--nixos/modules/security/rngd.nix2
-rw-r--r--nixos/modules/security/setuid-wrappers.nix35
-rw-r--r--nixos/modules/security/sudo.nix2
-rw-r--r--nixos/modules/services/audio/mopidy.nix8
-rw-r--r--nixos/modules/services/audio/mpd.nix12
-rw-r--r--nixos/modules/services/audio/ympd.nix57
-rw-r--r--nixos/modules/services/backup/rsnapshot.nix3
-rw-r--r--nixos/modules/services/continuous-integration/gitlab-runner.nix51
-rw-r--r--nixos/modules/services/continuous-integration/gocd-agent/default.nix2
-rw-r--r--nixos/modules/services/continuous-integration/gocd-server/default.nix14
-rw-r--r--nixos/modules/services/databases/4store-endpoint.nix4
-rw-r--r--nixos/modules/services/databases/4store.nix3
-rw-r--r--nixos/modules/services/databases/influxdb.nix13
-rw-r--r--nixos/modules/services/databases/monetdb.nix88
-rw-r--r--nixos/modules/services/databases/mongodb.nix18
-rw-r--r--nixos/modules/services/databases/postgresql.nix6
-rw-r--r--nixos/modules/services/databases/redis.nix5
-rw-r--r--nixos/modules/services/databases/riak.nix3
-rw-r--r--nixos/modules/services/databases/virtuoso.nix3
-rw-r--r--nixos/modules/services/desktops/accountsservice.nix8
-rw-r--r--nixos/modules/services/editors/emacs.nix12
-rw-r--r--nixos/modules/services/editors/emacs.xml15
-rw-r--r--nixos/modules/services/hardware/udev.nix26
-rw-r--r--nixos/modules/services/mail/dovecot.nix3
-rw-r--r--nixos/modules/services/mail/freepops.nix3
-rw-r--r--nixos/modules/services/mail/offlineimap.nix (renamed from nixos/modules/services/networking/offlineimap.nix)2
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix2
-rw-r--r--nixos/modules/services/mail/postgrey.nix79
-rw-r--r--nixos/modules/services/misc/autofs.nix2
-rwxr-xr-x[-rw-r--r--]nixos/modules/services/misc/confd.nix2
-rw-r--r--nixos/modules/services/misc/docker-registry.nix81
-rw-r--r--nixos/modules/services/misc/etcd.nix65
-rw-r--r--nixos/modules/services/misc/gitit.nix2
-rw-r--r--nixos/modules/services/misc/gitlab.nix61
-rw-r--r--nixos/modules/services/misc/gitlab.xml17
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix55
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix2
-rw-r--r--nixos/modules/services/misc/nix-optimise.nix49
-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/monitoring/cadvisor.nix1
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager.nix116
-rw-r--r--nixos/modules/services/monitoring/prometheus/default.nix445
-rw-r--r--nixos/modules/services/monitoring/prometheus/node-exporter.nix71
-rw-r--r--nixos/modules/services/monitoring/telegraf.nix71
-rw-r--r--nixos/modules/services/monitoring/ups.nix7
-rw-r--r--nixos/modules/services/network-filesystems/drbd.nix4
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix13
-rw-r--r--nixos/modules/services/networking/amuled.nix3
-rw-r--r--nixos/modules/services/networking/avahi-daemon.nix15
-rw-r--r--nixos/modules/services/networking/cjdns.nix2
-rw-r--r--nixos/modules/services/networking/connman.nix12
-rw-r--r--nixos/modules/services/networking/ddclient.nix17
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix26
-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/docker-registry-server.nix98
-rw-r--r--nixos/modules/services/networking/ferm.nix63
-rw-r--r--nixos/modules/services/networking/firewall.nix4
-rw-r--r--nixos/modules/services/networking/flannel.nix153
-rw-r--r--nixos/modules/services/networking/git-daemon.nix3
-rw-r--r--nixos/modules/services/networking/htpdate.nix80
-rw-r--r--nixos/modules/services/networking/iodine.nix6
-rw-r--r--nixos/modules/services/networking/mjpg-streamer.nix8
-rw-r--r--nixos/modules/services/networking/murmur.nix4
-rw-r--r--nixos/modules/services/networking/networkmanager.nix11
-rw-r--r--nixos/modules/services/networking/nsd.nix58
-rw-r--r--nixos/modules/services/networking/powerdns.nix50
-rw-r--r--nixos/modules/services/networking/quagga.nix187
-rw-r--r--nixos/modules/services/networking/radicale.nix5
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix4
-rw-r--r--nixos/modules/services/networking/supplicant.nix2
-rw-r--r--nixos/modules/services/networking/teamspeak3.nix75
-rw-r--r--nixos/modules/services/networking/toxvpn.nix2
-rw-r--r--nixos/modules/services/networking/unbound.nix43
-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/security/haveged.nix18
-rw-r--r--nixos/modules/services/system/dbus.nix62
-rw-r--r--nixos/modules/services/ttys/agetty.nix3
-rw-r--r--nixos/modules/services/web-apps/selfoss.nix166
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix158
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/mediawiki.nix6
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/moodle.nix4
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/wordpress.nix11
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix28
-rw-r--r--nixos/modules/services/web-servers/nginx/location-options.nix21
-rw-r--r--nixos/modules/services/web-servers/nginx/vhost-options.nix4
-rw-r--r--nixos/modules/services/web-servers/phpfpm/default.nix24
-rw-r--r--nixos/modules/services/web-servers/tomcat.nix16
-rw-r--r--nixos/modules/services/x11/desktop-managers/enlightenment.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde4.nix37
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix3
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix12
-rw-r--r--nixos/modules/services/x11/display-managers/kdm.nix22
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/slim.nix6
-rw-r--r--nixos/modules/services/x11/window-managers/awesome.nix9
-rw-r--r--nixos/modules/services/x11/xserver.nix17
-rw-r--r--nixos/modules/system/activation/activation-script.nix40
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl40
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix12
-rw-r--r--nixos/modules/system/boot/kernel.nix6
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix67
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl26
-rw-r--r--nixos/modules/system/boot/networkd.nix3
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh26
-rw-r--r--nixos/modules/system/boot/stage-1.nix57
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh48
-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/system/boot/systemd.nix31
-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.nix118
-rw-r--r--nixos/modules/tasks/filesystems/nfs.nix16
-rw-r--r--nixos/modules/tasks/filesystems/zfs.nix8
-rw-r--r--nixos/modules/tasks/network-interfaces-scripted.nix1
-rw-r--r--nixos/modules/tasks/network-interfaces-systemd.nix2
-rw-r--r--nixos/modules/tasks/network-interfaces.nix4
-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/azure-agent.nix3
-rw-r--r--nixos/modules/virtualisation/azure-bootstrap-blobs.nix3
-rw-r--r--nixos/modules/virtualisation/brightbox-image.nix6
-rw-r--r--nixos/modules/virtualisation/containers.nix293
-rw-r--r--nixos/modules/virtualisation/docker.nix25
-rw-r--r--nixos/modules/virtualisation/google-compute-image.nix4
-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.nix20
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix28
176 files changed, 3899 insertions, 1323 deletions
diff --git a/nixos/modules/config/fonts/fonts.nix b/nixos/modules/config/fonts/fonts.nix
index ea0a67038572..af3d93fc1bc4 100644
--- a/nixos/modules/config/fonts/fonts.nix
+++ b/nixos/modules/config/fonts/fonts.nix
@@ -11,18 +11,28 @@ with lib;
       # TODO: find another name for it.
       fonts = mkOption {
         type = types.listOf types.path;
+        default = [];
         example = literalExample "[ pkgs.dejavu_fonts ]";
         description = "List of primary font paths.";
       };
 
+      enableDefaultFonts = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable a basic set of fonts providing several font styles
+          and families and reasonable coverage of Unicode.
+        '';
+      };
+
     };
 
   };
 
   config = {
 
-    fonts.fonts =
-      [ pkgs.xorg.fontbhttf
+    fonts.fonts = mkIf config.fonts.enableDefaultFonts
+      [
         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/networking.nix b/nixos/modules/config/networking.nix
index 8a2e630a917a..952f62569c93 100644
--- a/nixos/modules/config/networking.nix
+++ b/nixos/modules/config/networking.nix
@@ -223,16 +223,16 @@ in
     # Install the proxy environment variables
     environment.sessionVariables = cfg.proxy.envVars;
 
-    # The ‘ip-up’ target is started when we have IP connectivity.  So
-    # services that depend on IP connectivity (like ntpd) should be
-    # pulled in by this target.
-    systemd.targets.ip-up.description = "Services Requiring IP Connectivity";
+    # The ‘ip-up’ target is kept for backwards compatibility.
+    # New services should use systemd upstream targets:
+    # See https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
+    systemd.targets.ip-up.description = "Services Requiring IP Connectivity (deprecated)";
 
     # This is needed when /etc/resolv.conf is being overriden by networkd
     # and other configurations. If the file is destroyed by an environment
     # activation then it must be rebuilt so that applications which interface
     # with /etc/resolv.conf directly don't break.
-    system.activationScripts.resolvconf = stringAfter [ "etc" "tmpfs" "var" ]
+    system.activationScripts.resolvconf = stringAfter [ "etc" "specialfs" "var" ]
       ''
         # Systemd resolved controls its own resolv.conf
         rm -f /run/resolvconf/interfaces/systemd
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..775d0c39c4fa 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -34,10 +34,10 @@ let
       config.programs.ssh.package
       pkgs.perl
       pkgs.procps
+      pkgs.rsync
       pkgs.strace
       pkgs.su
       pkgs.time
-      pkgs.texinfoInteractive
       pkgs.utillinux
       pkgs.which # 88K size
     ];
@@ -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>.";
       };
 
@@ -104,7 +104,6 @@ in
         "/etc/xdg"
         "/etc/gtk-2.0"
         "/etc/gtk-3.0"
-        "/info"
         "/lib" # FIXME: remove and update debug-info.nix
         "/sbin"
         "/share/applications"
@@ -112,7 +111,6 @@ in
         "/share/doc"
         "/share/emacs"
         "/share/icons"
-        "/share/info"
         "/share/menus"
         "/share/mime"
         "/share/nano"
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/hardware/opengl.nix b/nixos/modules/hardware/opengl.nix
index 0bc574d48190..bef500e30c0b 100644
--- a/nixos/modules/hardware/opengl.nix
+++ b/nixos/modules/hardware/opengl.nix
@@ -14,7 +14,7 @@ let
     name = "mesa-drivers+txc-${p.mesa_drivers.version}";
     paths =
       [ p.mesa_drivers
-        p.mesa_noglu # mainly for libGL
+        p.mesa_drivers.out # mainly for libGL
         (if cfg.s3tcSupport then p.libtxc_dxtn else p.libtxc_dxtn_s2tc)
       ];
   };
diff --git a/nixos/modules/hardware/video/displaylink.nix b/nixos/modules/hardware/video/displaylink.nix
new file mode 100644
index 000000000000..2a9382f39410
--- /dev/null
+++ b/nixos/modules/hardware/video/displaylink.nix
@@ -0,0 +1,61 @@
+{ config, lib, ... }:
+
+with lib;
+
+let
+
+  enabled = elem "displaylink" config.services.xserver.videoDrivers;
+
+  displaylink = config.boot.kernelPackages.displaylink;
+
+in
+
+{
+
+  config = mkIf enabled {
+
+    boot.extraModulePackages = [ displaylink ];
+
+    boot.kernelModules = [ "evdi" ];
+
+    # Those are taken from displaylink-installer.sh and from Arch Linux AUR package.
+
+    services.udev.extraRules = ''
+      ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="17e9", ATTR{bNumInterfaces}=="*5", TAG+="uaccess"
+    '';
+
+    powerManagement.powerDownCommands = ''
+      #flush any bytes in pipe
+      while read -n 1 -t 1 SUSPEND_RESULT < /tmp/PmMessagesPort_out; do : ; done;
+
+      #suspend DisplayLinkManager
+      echo "S" > /tmp/PmMessagesPort_in
+
+      #wait until suspend of DisplayLinkManager finish
+      read -n 1 -t 10 SUSPEND_RESULT < /tmp/PmMessagesPort_out
+    '';
+
+    powerManagement.resumeCommands = ''
+      #resume DisplayLinkManager
+      echo "R" > /tmp/PmMessagesPort_in
+    '';
+
+    systemd.services.displaylink = {
+      description = "DisplayLink Manager Service";
+      after = [ "display-manager.service" ];
+      wantedBy = [ "graphical.target" ];
+
+      serviceConfig = {
+        ExecStart = "${displaylink}/bin/DisplayLinkManager";
+        Restart = "always";
+        RestartSec = 5;
+      };
+
+      preStart = ''
+        mkdir -p /var/log/displaylink
+      '';
+    };
+
+  };
+
+}
diff --git a/nixos/modules/i18n/input-method/default.nix b/nixos/modules/i18n/input-method/default.nix
index 5d57a7f99666..7ed4a584d646 100644
--- a/nixos/modules/i18n/input-method/default.nix
+++ b/nixos/modules/i18n/input-method/default.nix
@@ -3,26 +3,27 @@
 with lib;
 let
   cfg = config.i18n.inputMethod;
-  gtk2_cache = pkgs.stdenv.mkDerivation {
-    preferLocalBuild = true; 
-    allowSubstitutes = false;
-    name = "gtk2-immodule.cache";
-    buildInputs = [ pkgs.gtk cfg.package ];
-    buildCommand = ''
+
+  gtk2_cache = pkgs.runCommand "gtk2-immodule.cache"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+      buildInputs = [ pkgs.gtk2 cfg.package ];
+    }
+    ''
       mkdir -p $out/etc/gtk-2.0/
       GTK_PATH=${cfg.package}/lib/gtk-2.0/ gtk-query-immodules-2.0 > $out/etc/gtk-2.0/immodules.cache
     '';
-  };
-  gtk3_cache = pkgs.stdenv.mkDerivation {
-    preferLocalBuild = true; 
-    allowSubstitutes = false;
-    name = "gtk3-immodule.cache";
-    buildInputs = [ pkgs.gtk3 cfg.package ];
-    buildCommand = ''
+
+  gtk3_cache = pkgs.runCommand "gtk3-immodule.cache"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+      buildInputs = [ pkgs.gtk3 cfg.package ];
+    }
+    ''
       mkdir -p $out/etc/gtk-3.0/
       GTK_PATH=${cfg.package}/lib/gtk-3.0/ gtk-query-immodules-3.0 > $out/etc/gtk-3.0/immodules.cache
     '';
-  };
+
 in
 {
   options.i18n = {
@@ -62,4 +63,9 @@ in
     environment.systemPackages = [ cfg.package gtk2_cache gtk3_cache ];
   };
 
+  meta = {
+    maintainers = with lib.maintainers; [ ericsagnes ];
+    doc = ./default.xml;
+  };
+
 }
diff --git a/nixos/modules/i18n/input-method/fcitx.nix b/nixos/modules/i18n/input-method/fcitx.nix
index e97bb9f80eb5..440f13b41522 100644
--- a/nixos/modules/i18n/input-method/fcitx.nix
+++ b/nixos/modules/i18n/input-method/fcitx.nix
@@ -20,10 +20,9 @@ in
         example = literalExample "with pkgs.fcitx-engines; [ mozc hangul ]";
         description =
           let
-            engines =
-              lib.concatStringsSep ", "
-              (map (name: "<literal>${name}</literal>")
-               (lib.attrNames pkgs.fcitx-engines));
+            enginesDrv = filterAttrs (const isDerivation) pkgs.fcitx-engines;
+            engines = concatStringsSep ", "
+              (map (name: "<literal>${name}</literal>") (attrNames enginesDrv));
           in
             "Enabled Fcitx engines. Available engines are: ${engines}.";
       };
diff --git a/nixos/modules/i18n/input-method/ibus.nix b/nixos/modules/i18n/input-method/ibus.nix
index 097a662c3c6d..d64cf2f283bf 100644
--- a/nixos/modules/i18n/input-method/ibus.nix
+++ b/nixos/modules/i18n/input-method/ibus.nix
@@ -30,10 +30,9 @@ in
         example = literalExample "with pkgs.ibus-engines; [ mozc hangul ]";
         description =
           let
-            engines =
-              lib.concatStringsSep ", "
-              (map (name: "<literal>${name}</literal>")
-               (lib.attrNames pkgs.ibus-engines));
+            enginesDrv = filterAttrs (const isDerivation) pkgs.ibus-engines;
+            engines = concatStringsSep ", "
+              (map (name: "<literal>${name}</literal>") (attrNames enginesDrv));
           in
             "Enabled IBus engines. Available engines are: ${engines}.";
       };
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
index d14768bc1079..b5ee57d9e22e 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
@@ -96,15 +96,16 @@ with lib;
     '';
 
   in
-    pkgs.stdenv.mkDerivation {
-      inherit (pkg) name meta;
-
-      buildCommand = ''
+    pkgs.runCommand pkg.name
+      { inherit (pkg) meta; }
+      ''
         mkdir -p $out
         cp -prf ${pkg}/* $out/
         chmod a+w $out/share/apps/plasma-desktop/init
         cp -f ${plasmaInit} $out/share/apps/plasma-desktop/init/00-defaultLayout.js
       '';
-    };
+
+  # Disable large stuff that's not very useful on the installation CD.
+  services.xserver.desktopManager.kde4.enablePIM = false;
 
 }
diff --git a/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix b/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
index d984cb307170..ba84cd51098f 100644
--- a/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
+++ b/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
@@ -61,7 +61,7 @@ in
       pkgs.cryptsetup # needed for dm-crypt volumes
 
       # Some networking tools.
-      pkgs.sshfsFuse
+      pkgs.sshfs-fuse
       pkgs.socat
       pkgs.screen
       pkgs.wpa_supplicant # !!! should use the wpa module
diff --git a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
index 9e733241993d..7ec09acd5919 100644
--- a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
+++ b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
@@ -55,7 +55,7 @@ in
       pkgs.cryptsetup # needed for dm-crypt volumes
 
       # Some networking tools.
-      pkgs.sshfsFuse
+      pkgs.sshfs-fuse
       pkgs.socat
       pkgs.screen
       pkgs.wpa_supplicant # !!! should use the wpa module
diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix
new file mode 100644
index 000000000000..747d9d2bcec5
--- /dev/null
+++ b/nixos/modules/installer/tools/nix-fallback-paths.nix
@@ -0,0 +1,5 @@
+{
+  x86_64-linux = "/nix/store/i4mwf2gpvar7dqvlpp5m86llbq3ahbvb-nix-1.11.4";
+  i686-linux = "/nix/store/a3gjrbspb0q4hs3sv5g1y2nza43i8nzv-nix-1.11.4";
+  x86_64-darwin = "/nix/store/7v21yd3qpv0nclcy5cqr5njj9bril12s-nix-1.11.4";
+}
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index 5e576367eb2f..f1874f239778 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -527,8 +527,11 @@ EOF
   # Use the GRUB 2 boot loader.
   boot.loader.grub.enable = true;
   boot.loader.grub.version = 2;
+  # boot.loader.grub.efiSupport = true;
+  # boot.loader.grub.efiInstallAsRemovable = true;
+  # boot.loader.efi.efiSysMountPoint = "/boot/efi";
   # Define on which hard drive you want to install Grub.
-  # boot.loader.grub.device = "/dev/sda";
+  # boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
 EOF
         }
 
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index 3b3a7bd27fe8..da28c027c563 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))"
@@ -269,7 +259,7 @@ chroot $mountPoint /nix/var/nix/profiles/system/activate
 
 
 # Ask the user to set a root password.
-if [ -z "$noRootPasswd" ] && [ -x $mountPoint/var/setuid-wrappers/passwd ] && [ -t 0 ]; then
+if [ -z "$noRootPasswd" ] && chroot $mountPoint [ -x /var/setuid-wrappers/passwd ] && [ -t 0 ]; then
     echo "setting root password..."
     chroot $mountPoint /var/setuid-wrappers/passwd
 fi
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
index 803989789838..36700d2bf566 100644
--- a/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -261,9 +261,9 @@ fi
 prebuiltNix() {
     machine="$1"
     if [ "$machine" = x86_64 ]; then
-        echo /nix/store/xryr9g56h8yjddp89d6dw12anyb4ch7c-nix-1.10
+        echo @nix_x86_64_linux@
     elif [[ "$machine" =~ i.86 ]]; then
-        echo /nix/store/2w92k5wlpspf0q2k9mnf2z42prx3bwmv-nix-1.10
+        echo @nix_i686_linux@
     else
         echo "$0: unsupported platform"
         exit 1
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix
index fc39a653abdc..a35f6ad8ae54 100644
--- a/nixos/modules/installer/tools/tools.nix
+++ b/nixos/modules/installer/tools/tools.nix
@@ -32,11 +32,15 @@ let
       "cp refs $out";
   };
 
-  nixos-rebuild = makeProg {
-    name = "nixos-rebuild";
-    src = ./nixos-rebuild.sh;
-    nix = config.nix.package.out;
-  };
+  nixos-rebuild =
+    let fallback = import ./nix-fallback-paths.nix; in
+    makeProg {
+      name = "nixos-rebuild";
+      src = ./nixos-rebuild.sh;
+      nix = config.nix.package.out;
+      nix_x86_64_linux = fallback.x86_64-linux;
+      nix_i686_linux = fallback.i686-linux;
+    };
 
   nixos-generate-config = makeProg {
     name = "nixos-generate-config";
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 31c93028bc52..2881d843760d 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -74,7 +74,6 @@
       rtkit = 45;
       dovecot2 = 46;
       dovenull2 = 47;
-      unbound = 48;
       prayer = 49;
       mpd = 50;
       clamav = 51;
@@ -120,7 +119,6 @@
       minidlna = 91;
       elasticsearch = 92;
       tcpcryptd = 93; # tcpcryptd uses a hard-coded uid. We patch it in Nixpkgs to match this choice.
-      #connman = 94; # unused
       firebird = 95;
       #keys = 96; # unused
       haproxy = 97;
@@ -141,7 +139,7 @@
       ngircd = 112;
       btsync = 113;
       minecraft = 114;
-      monetdb = 115;
+      #monetdb = 115; # unused (not packaged), removed 2016-09-19
       rippled = 116;
       murmur = 117;
       foundationdb = 118;
@@ -181,7 +179,6 @@
       systemd-timesync = 154;
       liquidsoap = 155;
       etcd = 156;
-      docker-registry = 157;
       hbase = 158;
       opentsdb = 159;
       scollector = 160;
@@ -275,6 +272,10 @@
       gocd-server = 252;
       terraria = 253;
       mattermost = 254;
+      prometheus = 255;
+      telegraf = 256;
+      gitlab-runner = 257;
+      postgrey = 258;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -331,7 +332,6 @@
       #rtkit = 45; # unused
       dovecot2 = 46;
       #dovenull = 47; # unused
-      #unbound = 48; # unused
       prayer = 49;
       mpd = 50;
       clamav = 51;
@@ -377,7 +377,6 @@
       minidlna = 91;
       elasticsearch = 92;
       #tcpcryptd = 93; # unused
-      connman = 94;
       firebird = 95;
       keys = 96;
       haproxy = 97;
@@ -396,7 +395,7 @@
       #ngircd = 112; # unused
       btsync = 113;
       #minecraft = 114; # unused
-      monetdb = 115;
+      #monetdb = 115; # unused (not packaged), removed 2016-09-19
       #ripped = 116; # unused
       #murmur = 117; # unused
       foundationdb = 118;
@@ -436,7 +435,6 @@
       systemd-timesync = 154;
       liquidsoap = 155;
       #etcd = 156; # unused
-      #docker-registry = 157; # unused
       hbase = 158;
       opentsdb = 159;
       scollector = 160;
@@ -520,6 +518,10 @@
       gocd-server = 252;
       terraria = 253;
       mattermost = 254;
+      prometheus = 255;
+      #telegraf = 256; # unused
+      gitlab-runner = 257;
+      postgrey = 258;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/misc/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/misc/version.nix b/nixos/modules/misc/version.nix
index 2ecdbdbf3925..ec423768296a 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -95,7 +95,7 @@ in
       nixosVersionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId));
 
       # Note: code names must only increase in alphabetical order.
-      nixosCodeName = "Flounder";
+      nixosCodeName = "Gorilla";
     };
 
     # Generate /etc/os-release.  See
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index eb89ff83e2ce..7ae3722bc8f5 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -40,6 +40,7 @@
   ./hardware/video/amdgpu.nix
   ./hardware/video/ati.nix
   ./hardware/video/bumblebee.nix
+  ./hardware/video/displaylink.nix
   ./hardware/video/nvidia.nix
   ./hardware/video/webcam/facetimehd.nix
   ./i18n/input-method/default.nix
@@ -66,8 +67,9 @@
   ./programs/command-not-found/command-not-found.nix
   ./programs/dconf.nix
   ./programs/environment.nix
-  ./programs/freetds.nix
   ./programs/fish.nix
+  ./programs/freetds.nix
+  ./programs/info.nix
   ./programs/kbdlight.nix
   ./programs/light.nix
   ./programs/man.nix
@@ -113,6 +115,7 @@
   ./services/audio/mpd.nix
   ./services/audio/mopidy.nix
   ./services/audio/squeezelite.nix
+  ./services/audio/ympd.nix
   ./services/backup/almir.nix
   ./services/backup/bacula.nix
   ./services/backup/crashplan.nix
@@ -130,6 +133,7 @@
   ./services/computing/slurm/slurm.nix
   ./services/continuous-integration/buildkite-agent.nix
   ./services/continuous-integration/hydra/default.nix
+  ./services/continuous-integration/gitlab-runner.nix
   ./services/continuous-integration/gocd-agent/default.nix
   ./services/continuous-integration/gocd-server/default.nix
   ./services/continuous-integration/jenkins/default.nix
@@ -142,7 +146,6 @@
   ./services/databases/hbase.nix
   ./services/databases/influxdb.nix
   ./services/databases/memcached.nix
-  ./services/databases/monetdb.nix
   ./services/databases/mongodb.nix
   ./services/databases/mysql.nix
   ./services/databases/neo4j.nix
@@ -208,10 +211,12 @@
   ./services/mail/freepops.nix
   ./services/mail/mail.nix
   ./services/mail/mlmmj.nix
+  ./services/mail/offlineimap.nix
   ./services/mail/opendkim.nix
   ./services/mail/opensmtpd.nix
   ./services/mail/postfix.nix
   ./services/mail/postsrsd.nix
+  ./services/mail/postgrey.nix
   ./services/mail/spamassassin.nix
   ./services/mail/rspamd.nix
   ./services/mail/rmilter.nix
@@ -228,7 +233,6 @@
   ./services/misc/dictd.nix
   ./services/misc/dysnomia.nix
   ./services/misc/disnix.nix
-  ./services/misc/docker-registry.nix
   ./services/misc/emby.nix
   ./services/misc/etcd.nix
   ./services/misc/felix.nix
@@ -249,6 +253,7 @@
   ./services/misc/mwlib.nix
   ./services/misc/nix-daemon.nix
   ./services/misc/nix-gc.nix
+  ./services/misc/nix-optimise.nix
   ./services/misc/nixos-manual.nix
   ./services/misc/nix-ssh-serve.nix
   ./services/misc/nzbget.nix
@@ -286,6 +291,9 @@
   ./services/monitoring/monit.nix
   ./services/monitoring/munin.nix
   ./services/monitoring/nagios.nix
+  ./services/monitoring/prometheus/default.nix
+  ./services/monitoring/prometheus/node-exporter.nix
+  ./services/monitoring/prometheus/alertmanager.nix
   ./services/monitoring/riemann.nix
   ./services/monitoring/riemann-dash.nix
   ./services/monitoring/riemann-tools.nix
@@ -294,6 +302,7 @@
   ./services/monitoring/statsd.nix
   ./services/monitoring/systemhealth.nix
   ./services/monitoring/teamviewer.nix
+  ./services/monitoring/telegraf.nix
   ./services/monitoring/ups.nix
   ./services/monitoring/uptime.nix
   ./services/monitoring/zabbix-agent.nix
@@ -332,11 +341,12 @@
   ./services/networking/dnschain.nix
   ./services/networking/dnscrypt-proxy.nix
   ./services/networking/dnsmasq.nix
-  ./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/flannel.nix
   ./services/networking/flashpolicyd.nix
   ./services/networking/freenet.nix
   ./services/networking/gale.nix
@@ -349,6 +359,7 @@
   ./services/networking/haproxy.nix
   ./services/networking/heyefi.nix
   ./services/networking/hostapd.nix
+  ./services/networking/htpdate.nix
   ./services/networking/i2pd.nix
   ./services/networking/i2p.nix
   ./services/networking/iodine.nix
@@ -375,7 +386,6 @@
   ./services/networking/ntopng.nix
   ./services/networking/ntpd.nix
   ./services/networking/nylon.nix
-  ./services/networking/offlineimap.nix
   ./services/networking/oidentd.nix
   ./services/networking/openfire.nix
   ./services/networking/openntpd.nix
@@ -383,10 +393,12 @@
   ./services/networking/ostinato.nix
   ./services/networking/pdnsd.nix
   ./services/networking/polipo.nix
+  ./services/networking/powerdns.nix
   ./services/networking/pptpd.nix
   ./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
@@ -468,6 +480,7 @@
   ./services/web-apps/mattermost.nix
   ./services/web-apps/pump.io.nix
   ./services/web-apps/tt-rss.nix
+  ./services/web-apps/selfoss.nix
   ./services/web-servers/apache-httpd/default.nix
   ./services/web-servers/caddy.nix
   ./services/web-servers/fcgiwrap.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 20a1f7f1ed8c..32bea97823ce 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -20,7 +20,7 @@
 
     # Some networking tools.
     pkgs.fuse
-    pkgs.sshfsFuse
+    pkgs.sshfs-fuse
     pkgs.socat
     pkgs.screen
 
diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix
index c353da227aeb..b047b7063653 100644
--- a/nixos/modules/profiles/minimal.nix
+++ b/nixos/modules/profiles/minimal.nix
@@ -11,4 +11,7 @@ with lib;
   # This isn't perfect, but let's expect the user specifies an UTF-8 defaultLocale
   i18n.supportedLocales = [ (config.i18n.defaultLocale + "/UTF-8") ];
   services.nixosManual.enable = mkDefault false;
+
+  programs.man.enable = mkDefault false;
+  programs.info.enable = mkDefault false;
 }
diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix
index c09bcfb70e24..e23849d350b4 100644
--- a/nixos/modules/programs/bash/bash.nix
+++ b/nixos/modules/programs/bash/bash.nix
@@ -16,7 +16,7 @@ let
     # programmable completion. If we do, enable all modules installed in
     # the system (and user profile).
     if shopt -q progcomp &>/dev/null; then
-      . "${pkgs.bashCompletion}/etc/profile.d/bash_completion.sh"
+      . "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh"
       nullglobStatus=$(shopt -p nullglob)
       shopt -s nullglob
       for p in $NIX_PROFILES; do
diff --git a/nixos/modules/programs/info.nix b/nixos/modules/programs/info.nix
new file mode 100644
index 000000000000..be6439dca5ad
--- /dev/null
+++ b/nixos/modules/programs/info.nix
@@ -0,0 +1,30 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  options = {
+
+    programs.info.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to enable info pages and the <command>info</command> command.
+      '';
+    };
+
+  };
+
+
+  config = mkIf config.programs.info.enable {
+
+    environment.systemPackages = [ pkgs.texinfoInteractive ];
+
+    environment.pathsToLink = [ "/info" "/share/info" ];
+
+    environment.extraOutputsToInstall = [ "info" ];
+
+  };
+
+}
diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix
index 878c9cc0cf09..ce4d46e19bf9 100644
--- a/nixos/modules/programs/shadow.nix
+++ b/nixos/modules/programs/shadow.nix
@@ -99,7 +99,6 @@ in
         groupdel = { rootOK = true; };
         login = { startSession = true; allowNullPassword = true; showMotd = true; updateWtmp = true; };
         chpasswd = { rootOK = true; };
-        chgpasswd = { rootOK = true; };
       };
 
     security.setuidPrograms = [ "su" "chfn" ]
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index cc835081c9f9..b6fd9868f98f 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -56,7 +56,6 @@ in
 
       setXAuthLocation = mkOption {
         type = types.bool;
-        default = config.services.xserver.enable;
         description = ''
           Whether to set the path to <command>xauth</command> for X11-forwarded connections.
           This causes a dependency on X11 packages.
@@ -165,6 +164,9 @@ in
 
   config = {
 
+    programs.ssh.setXAuthLocation =
+      mkDefault (config.services.xserver.enable || config.programs.ssh.forwardX11);
+
     assertions =
       [ { assertion = cfg.forwardX11 -> cfg.setXAuthLocation;
           message = "cannot enable X11 forwarding without setting XAuth location";
diff --git a/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix
index 1b8b7a79593e..d81f63c2acca 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;
       };
@@ -99,9 +102,9 @@ in
 
       interactiveShellInit = ''
         # history defaults
-        export SAVEHIST=2000
-        export HISTSIZE=2000
-        export HISTFILE=$HOME/.zsh_history
+        SAVEHIST=2000
+        HISTSIZE=2000
+        HISTFILE=$HOME/.zsh_history
 
         setopt HIST_IGNORE_DUPS SHARE_HISTORY HIST_FCNTL_LOCK
 
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 3caac6c4ee60..9abe7d450c93 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -15,7 +15,6 @@ with lib;
     (mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "networking" "enableRalinkFirmware" ])
 
     (mkRenamedOptionModule [ "services" "cadvisor" "host" ] [ "services" "cadvisor" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "dockerRegistry" "host" ] [ "services" "dockerRegistry" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "elasticsearch" "host" ] [ "services" "elasticsearch" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "graphite" "api" "host" ] [ "services" "graphite" "api" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "graphite" "web" "host" ] [ "services" "graphite" "web" "listenAddress" ])
@@ -29,7 +28,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 +111,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" ])
@@ -140,19 +139,24 @@ with lib;
     # fontconfig-ultimate
     (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" ])
+    # murmur
+    (mkRenamedOptionModule [ "services" "murmur" "welcome" ] [ "services" "murmur" "welcometext" ])
 
+    # 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" ]
+      "See the 16.09 release notes for more information.")
+    (mkRemovedOptionModule [ "services" "phpfpm" "phpIni" ] "")
+    (mkRemovedOptionModule [ "services" "dovecot2" "package" ] "")
+    (mkRemovedOptionModule [ "services" "dockerRegistry" ]
+      "docker-registry has been deprecated upstream since a long time.")
   ];
 }
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index f646602221a4..45e8f64046b0 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -166,7 +166,8 @@ in
                           ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains);
                 acmeService = {
                   description = "Renew ACME Certificate for ${cert}";
-                  after = [ "network.target" ];
+                  after = [ "network.target" "network-online.target" ];
+                  wants = [ "network-online.target" ];
                   serviceConfig = {
                     Type = "oneshot";
                     SuccessExitStatus = [ "0" "1" ];
@@ -290,9 +291,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..7ba25f866f24 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";
@@ -67,6 +72,8 @@ in
         (isNO "GRKERNSEC_NO_RBAC")
       ];
 
+    nixpkgs.config.grsecurity = true;
+
     # Install PaX related utillities into the system profile.
     environment.systemPackages = with pkgs; [ gradm paxctl pax-utils ];
 
diff --git a/nixos/modules/security/grsecurity.xml b/nixos/modules/security/grsecurity.xml
new file mode 100644
index 000000000000..28415e89bfab
--- /dev/null
+++ b/nixos/modules/security/grsecurity.xml
@@ -0,0 +1,345 @@
+<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-grsecurity">
+
+  <title>Grsecurity/PaX</title>
+
+  <para>
+    Grsecurity/PaX is a set of patches against the Linux kernel that make it
+    harder to exploit bugs.  The patchset includes protections such as
+    enforcement of non-executable memory, address space layout randomization,
+    and chroot jail hardening.  These and other
+    <link xlink:href="https://grsecurity.net/features.php">features</link>
+    render entire classes of exploits inert without additional efforts on the
+    part of the adversary.
+  </para>
+
+  <para>
+    The NixOS grsecurity/PaX module is designed with casual users in mind and is
+    intended to be compatible with normal desktop usage, without unnecessarily
+    compromising security.  The following sections describe the configuration
+    and administration of a grsecurity/PaX enabled NixOS system.  For
+    more comprehensive coverage, please refer to the
+    <link xlink:href="https://en.wikibooks.org/wiki/Grsecurity">grsecurity wikibook</link>
+    and the
+    <link xlink:href="https://wiki.archlinux.org/index.php/Grsecurity">Arch
+    Linux wiki page on grsecurity</link>.
+
+    <note><para>grsecurity/PaX is only available for the latest linux -stable
+    kernel; patches against older kernels are available from upstream only for
+    a fee.</para></note>
+    <note><para>We standardise on a desktop oriented configuration primarily due
+    to lack of resources.  The grsecurity/PaX configuration state space is huge
+    and each configuration requires quite a bit of testing to ensure that the
+    resulting packages work as advertised.  Defining additional package sets
+    would likely result in a large number of functionally broken packages, to
+    nobody's benefit.</para></note>.
+  </para>
+
+  <sect1 xml:id="sec-grsec-enable"><title>Enabling grsecurity/PaX</title>
+
+  <para>
+    To make use of grsecurity/PaX on NixOS, add the following to your
+    <filename>configuration.nix</filename>:
+    <programlisting>
+      security.grsecurity.enable = true;
+    </programlisting>
+    followed by
+    <programlisting>
+      # nixos-rebuild boot
+      # reboot
+    </programlisting>
+    For most users, further configuration should be unnecessary.  All users
+    are encouraged to look over <xref linkend="sec-grsec-security" /> before
+    using the system, however.  If you experience problems, please refer to
+    <xref linkend="sec-grsec-issues" />.
+  </para>
+
+  <para>
+    Once booted into the new system, you can optionally use
+    <command>paxtest</command> to exercise various PaX features:
+    <screen><![CDATA[
+    # nix-shell -p paxtest --command 'paxtest blackhat'
+    Executable anonymous mapping             : Killed
+    Executable bss                           : Killed
+    # ... remaining output truncated for brevity
+    ]]></screen>
+  </para>
+
+  </sect1>
+
+  <sect1 xml:id="sec-grsec-declarative-tuning"><title>Declarative tuning</title>
+
+  <para>
+    The default configuration mode is strictly declarative.  Some features
+    simply cannot be changed at all after boot, while others are locked once the
+    system is up and running.  Moreover, changes to the configuration enter
+    into effect only upon booting into the new system.
+  </para>
+
+  <para>
+    The NixOS module exposes a limited number of options for tuning the behavior
+    of grsecurity/PaX.  These are options thought to be of particular interest
+    to most users.  For experts, further tuning is possible via
+    <option>boot.kernelParams</option> (see
+    <xref linkend="sec-grsec-kernel-params" />) and
+    <option>boot.kernel.sysctl."kernel.grsecurity.*"</option> (the wikibook
+    contains an <link xlink:href="https://en.wikibooks.org/wiki/Grsecurity/Appendix/Sysctl_Options">
+    exhaustive listing of grsecurity sysctl tunables</link>).
+  </para>
+
+  </sect1>
+
+  <sect1 xml:id="sec-grsec-manual-tuning"><title>Manual tuning</title>
+
+  <para>
+    To permit manual tuning of grsecurity runtime parameters, set:
+    <programlisting>
+      security.grsecurity.lockTunables = false;
+    </programlisting>
+    Once booted into this system, grsecurity features that have a corresponding
+    sysctl tunable can be changed without rebooting, either by switching into
+    a new system profile or via the <command>sysctl</command> utility.
+  </para>
+
+  <para>
+    To lock all grsecurity tunables until the next boot, do:
+    <screen>
+      # systemctl start grsec-lock
+    </screen>
+  </para>
+
+  </sect1>
+
+  <sect1 xml:id="sec-grsec-security"><title>Security considerations</title>
+
+  <para>
+    The NixOS kernel is built using upstream's recommended settings for a
+    desktop deployment that generally favours security over performance.  This
+    section details deviations from upstream's recommendations that may
+    compromise operational security.
+
+    <warning><para>There may be additional problems not covered here!</para>
+    </warning>.
+  </para>
+
+  <itemizedlist>
+
+    <listitem><para>
+      The following hardening features are disabled in the NixOS kernel:
+      <itemizedlist>
+        <listitem><para>Kernel symbol hiding: rendered useless by redistributing
+        kernel objects.</para></listitem>
+
+        <listitem><para>Randomization of kernel structures: rendered useless by
+        redistributing kernel objects.</para></listitem>
+
+        <listitem><para>TCP simultaneous OPEN connection is permitted: breaking
+        strict TCP conformance is inappropriate for a general purpose kernel.
+        The trade-off is that an attacker may be able to deny outgoing
+        connections if they are able to guess the source port allocated by your
+        OS for that connection <emphasis>and</emphasis> also manage to initiate
+        a TCP simultaneous OPEN on that port before the connection is actually
+        established.</para></listitem>
+
+        <listitem><para><filename class="directory">/sys</filename> hardening:
+        breaks systemd.</para></listitem>
+
+        <listitem><para>Trusted path execution: a desirable feature, but
+        requires some more work to operate smoothly on NixOS.</para></listitem>
+      </itemizedlist>
+    </para></listitem>
+
+    <listitem><para>
+      The NixOS module conditionally weakens <command>chroot</command>
+      restrictions to accommodate NixOS lightweight containers and sandboxed Nix
+      builds.  This is problematic if the deployment also runs a privileged
+      network facing process that <emphasis>relies</emphasis> on
+      <command>chroot</command> for isolation.
+    </para></listitem>
+
+    <listitem><para>
+      The NixOS kernel is patched to allow usermode helpers from anywhere in the
+      Nix store.  A usermode helper is an executable called by the kernel in
+      certain circumstances, e.g., <command>modprobe</command>.  Vanilla
+      grsecurity only allows usermode helpers from paths typically owned by the
+      super user.  The NixOS kernel allows an attacker to inject malicious code
+      into the Nix store which could then be executed by the kernel as a
+      usermode helper.
+    </para></listitem>
+
+    <listitem><para>
+      The following features are disabled because they overlap with
+      vanilla kernel mechanisms:
+
+      <itemizedlist>
+        <listitem><para><filename class="directory">/proc</filename> hardening:
+        use <option>security.hideProcessInformation</option> instead.  This
+        trades weaker protection for greater compatibility.
+        </para></listitem>
+
+        <listitem><para><command>dmesg</command> restrictions:
+        use <option>boot.kernel.sysctl."kernel.dmesg_restrict"</option> instead
+        </para></listitem>
+      </itemizedlist>
+    </para></listitem>
+
+  </itemizedlist>
+
+  </sect1>
+
+  <sect1 xml:id="sec-grsec-custom-kernel"><title>Using a custom grsecurity/PaX kernel</title>
+
+  <para>
+    The NixOS kernel is likely to be either too permissive or too restrictive
+    for many deployment scenarios.  In addition to producing a kernel more
+    suitable for a particular deployment, a custom kernel may improve security
+    by depriving an attacker the ability to study the kernel object code, adding
+    yet more guesswork to successfully carry out certain exploits.
+  </para>
+
+  <para>
+    To use a custom kernel with upstream's recommended settings for server
+    deployments:
+    <programlisting>
+      boot.kernelPackages =
+        let
+          kernel = pkgs.linux_grsec_nixos.override {
+            extraConfig = ''
+              GRKERNSEC y
+              PAX y
+              GRKERNSEC_CONFIG_AUTO y
+              GRKERNSEC_CONFIG_SERVER y
+              GRKERNSEC_CONFIG_SECURITY y
+            '';
+          };
+          self = pkgs.linuxPackagesFor kernel self;
+        in self;
+    </programlisting>
+    The wikibook provides an exhaustive listing of
+    <link xlink:href="https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options">kernel configuration options</link>.
+  </para>
+
+  <para>
+    The NixOS module makes several assumptions about the kernel and so may be
+    incompatible with your customised kernel.  Most of these assumptions are
+    encoded as assertions &#x2014; mismatches should ideally result in a build
+    failure.  Currently, the only way to work around incompatibilities is to
+    eschew the NixOS module and do all configuration yourself.
+  </para>
+
+  </sect1>
+
+  <sect1 xml:id="sec-grsec-pax-flags"><title>Per-executable PaX flags</title>
+
+  <para>
+    Manual tuning of per-file PaX flags for executables in the Nix store is
+    impossible on a properly configured system.  If a package in Nixpkgs fails
+    due to PaX, that is a bug in the package recipe and should be reported to
+    the maintainer (including relevant <command>dmesg</command> output).
+  </para>
+
+  <para>
+    For executables installed outside of the Nix store, PaX flags can be set
+    using the <command>paxctl</command> utility:
+    <programlisting>
+      paxctl -czem <replaceable>foo</replaceable>
+    </programlisting>
+
+    <warning>
+      <para><command>paxctl</command> overwrites files in-place.</para>
+    </warning>
+
+    Equivalently, on file systems that support extended attributes:
+    <programlisting>
+      setfattr -n user.pax.flags -v em <replaceable>foo</replaceable>
+    </programlisting>
+
+    <!-- TODO: PaX flags via RBAC policy -->
+  </para>
+
+  </sect1>
+
+  <sect1 xml:id="sec-grsec-issues"><title>Issues and work-arounds</title>
+
+  <itemizedlist>
+    <listitem><para>User namespaces require <literal>CAP_SYS_ADMIN</literal>:
+    consequently, unprivileged namespaces are unsupported. Applications that
+    rely on namespaces for sandboxing must use a privileged helper. For chromium
+    there is <option>security.chromiumSuidSandbox.enable</option>.</para></listitem>
+
+    <listitem><para>Access to EFI runtime services is disabled by default:
+    this plugs a potential code injection attack vector; use
+    <option>security.grsecurity.disableEfiRuntimeServices</option> to override
+    this behavior.</para></listitem>
+
+    <listitem><para>Virtualization: KVM is the preferred virtualization
+    solution. Xen, Virtualbox, and VMWare are
+    <emphasis>unsupported</emphasis> and most likely require a custom kernel.
+    </para></listitem>
+
+    <listitem><para>
+      Attaching <command>gdb</command> to a running process is disallowed by
+      default: unprivileged users can only ptrace processes that are children of
+      the ptracing process.  To relax this restriction, set
+      <programlisting>
+        boot.kernel.sysctl."kernel.grsecurity.harden_ptrace" = 0;
+      </programlisting>
+    </para></listitem>
+
+    <listitem><para>
+      Overflows in boot critical code (e.g., the root filesystem module) can
+      render the system unbootable.  Work around by setting
+      <programlisting>
+        boot.kernel.kernelParams = [ "pax_size_overflow_report_only" ];
+      </programlisting>
+    </para></listitem>
+
+    <listitem><para>
+      The <citerefentry><refentrytitle>modify_ldt
+      </refentrytitle><manvolnum>2</manvolnum></citerefentry> syscall is disabled
+      by default.  This restriction can interfere with programs designed to run
+      legacy 16-bit or segmented 32-bit code.  To support applications that rely
+      on this syscall, set
+      <programlisting>
+        boot.kernel.sysctl."kernel.modify_ldt" = 1;
+      </programlisting>
+    </para></listitem>
+
+  </itemizedlist>
+
+  </sect1>
+
+  <sect1 xml:id="sec-grsec-kernel-params"><title>Grsecurity/PaX kernel parameters</title>
+
+  <para>
+    The NixOS kernel supports the following kernel command line parameters:
+    <itemizedlist>
+      <listitem><para>
+        <literal>pax_nouderef</literal>: disable UDEREF (separate kernel and
+        user address spaces).
+      </para></listitem>
+
+      <listitem><para>
+        <literal>pax_weakuderef</literal>: enable a faster but
+        weaker variant of UDEREF on 64-bit processors with PCID support
+        (check <code>grep pcid /proc/cpuinfo</code>).
+      </para></listitem>
+
+      <listitem><para>
+        <literal>pax_sanitize_slab={off|fast|full}</literal>: control kernel
+        slab object sanitization
+      </para></listitem>
+
+      <listitem><para>
+        <literal>pax_size_overflow_report_only</literal>: log size overflow
+        violations but leave the violating task running
+      </para></listitem>
+    </itemizedlist>
+  </para>
+
+  </sect1>
+
+</chapter>
diff --git a/nixos/modules/security/hidepid.nix b/nixos/modules/security/hidepid.nix
index 8271578c55d6..ee351eb84473 100644
--- a/nixos/modules/security/hidepid.nix
+++ b/nixos/modules/security/hidepid.nix
@@ -2,41 +2,24 @@
 with lib;
 
 {
-  options = {
-    security.hideProcessInformation = mkEnableOption "" // { description = ''
-      Restrict access to process information to the owning user.  Enabling
-      this option implies, among other things, that command-line arguments
-      remain private.  This option is recommended for most systems, unless
-      there's a legitimate reason for allowing unprivileged users to inspect
-      the process information of other users.
+  meta = {
+    maintainers = [ maintainers.joachifm ];
+    doc = ./hidepid.xml;
+  };
 
-      Members of the group "proc" are exempt from process information hiding.
-      To allow a service to run without process information hiding, add "proc"
-      to its supplementary groups via
-      <option>systemd.services.&lt;name?&gt;.serviceConfig.SupplementaryGroups</option>.
-    ''; };
+  options = {
+    security.hideProcessInformation = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Restrict process information to the owning user.
+      '';
+    };
   };
 
   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/hidepid.xml b/nixos/modules/security/hidepid.xml
new file mode 100644
index 000000000000..5715ee7ac165
--- /dev/null
+++ b/nixos/modules/security/hidepid.xml
@@ -0,0 +1,33 @@
+<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-hidepid">
+
+  <title>Hiding process information</title>
+
+  <para>
+    Setting
+    <programlisting>
+      security.hideProcessInformation = true;
+    </programlisting>
+    ensures that access to process information is restricted to the
+    owning user.  This implies, among other things, that command-line
+    arguments remain private.  Unless your deployment relies on unprivileged
+    users being able to inspect the process information of other users, this
+    option should be safe to enable.
+  </para>
+
+  <para>
+    Members of the <literal>proc</literal> group are exempt from process
+    information hiding.
+  </para>
+
+  <para>
+    To allow a service <replaceable>foo</replaceable> to run without process information hiding, set
+    <programlisting>
+      systemd.services.<replaceable>foo</replaceable>.serviceConfig.SupplementaryGroups = [ "proc" ];
+    </programlisting>
+  </para>
+
+</chapter>
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 77815cd6dcc1..814dd21b53de 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -105,6 +105,16 @@ let
         '';
       };
 
+      setEnvironment = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether the service should set the environment variables
+          listed in <option>environment.sessionVariables</option>
+          using <literal>pam_env.so</literal>.
+        '';
+      };
+
       setLoginUid = mkOption {
         type = types.bool;
         description = ''
@@ -284,7 +294,9 @@ let
               "password optional ${pkgs.samba}/lib/security/pam_smbpass.so nullok use_authtok try_first_pass"}
 
           # Session management.
-          session required pam_env.so envfile=${config.system.build.pamEnvironment}
+          ${optionalString cfg.setEnvironment ''
+            session required pam_env.so envfile=${config.system.build.pamEnvironment}
+          ''}
           session required pam_unix.so
           ${optionalString cfg.setLoginUid
               "session ${
@@ -477,6 +489,13 @@ in
         vlock = {};
         xlock = {};
         xscreensaver = {};
+
+        runuser = { rootOK = true; unixAuth = false; setEnvironment = false; };
+
+        /* FIXME: should runuser -l start a systemd session? Currently
+           it complains "Cannot create session: Already running in a
+           session". */
+        runuser-l = { rootOK = true; unixAuth = false; };
       };
 
   };
diff --git a/nixos/modules/security/rngd.nix b/nixos/modules/security/rngd.nix
index b14ea7a5f276..3a1ffc55e5fe 100644
--- a/nixos/modules/security/rngd.nix
+++ b/nixos/modules/security/rngd.nix
@@ -18,7 +18,7 @@ with lib;
   config = mkIf config.security.rngd.enable {
     services.udev.extraRules = ''
       KERNEL=="random", TAG+="systemd"
-      SUBSYSTEM=="cpu", ENV{MODALIAS}=="x86cpu:*feature:*009E*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
+      SUBSYSTEM=="cpu", ENV{MODALIAS}=="cpu:type:x86,*feature:*009E*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
       KERNEL=="hw_random", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
       ${if config.services.tcsd.enable then "" else ''KERNEL=="tpm0", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"''}
     '';
diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix
index 99dd514feea3..fe220c94313f 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
+            ${pkgs.utillinux}/bin/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/security/sudo.nix b/nixos/modules/security/sudo.nix
index bced2a6ed757..f5612e1b0c5d 100644
--- a/nixos/modules/security/sudo.nix
+++ b/nixos/modules/security/sudo.nix
@@ -74,7 +74,7 @@ in
         Defaults env_keep+=SSH_AUTH_SOCK
 
         # "root" is allowed to do anything.
-        root        ALL=(ALL) SETENV: ALL
+        root        ALL=(ALL:ALL) SETENV: ALL
 
         # Users in the "wheel" group can do anything.
         %wheel      ALL=(ALL:ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL
diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix
index 029b14ab4726..c0a0f0374294 100644
--- a/nixos/modules/services/audio/mopidy.nix
+++ b/nixos/modules/services/audio/mopidy.nix
@@ -21,13 +21,7 @@ in {
 
     services.mopidy = {
 
-      enable = mkOption {
-        default = false;
-        type = types.bool;
-        description = ''
-          Whether to enable Mopidy, a music player daemon.
-        '';
-      };
+      enable = mkEnableOption "Mopidy, a music player daemon";
 
       dataDir = mkOption {
         default = "/var/lib/mopidy";
diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix
index 5d5fef667941..85e0a7d2ac4e 100644
--- a/nixos/modules/services/audio/mpd.nix
+++ b/nixos/modules/services/audio/mpd.nix
@@ -33,6 +33,7 @@ in {
     services.mpd = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = ''
           Whether to enable MPD, the music player daemon.
@@ -40,6 +41,7 @@ in {
       };
 
       musicDirectory = mkOption {
+        type = types.path;
         default = "${cfg.dataDir}/music";
         description = ''
           The directory where mpd reads music from.
@@ -47,6 +49,7 @@ in {
       };
 
       extraConfig = mkOption {
+        type = types.str;
         default = "";
         description = ''
           Extra directives added to to the end of MPD's configuration file,
@@ -56,6 +59,7 @@ in {
       };
 
       dataDir = mkOption {
+        type = types.path;
         default = "/var/lib/mpd";
         description = ''
           The directory where MPD stores its state, tag cache,
@@ -64,11 +68,13 @@ in {
       };
 
       user = mkOption {
+        type = types.str;
         default = "mpd";
         description = "User account under which MPD runs.";
       };
 
       group = mkOption {
+        type = types.str;
         default = "mpd";
         description = "Group account under which MPD runs.";
       };
@@ -76,6 +82,7 @@ in {
       network = {
 
         listenAddress = mkOption {
+          type = types.str;
           default = "any";
           description = ''
             This setting sets the address for the daemon to listen on. Careful attention
@@ -85,6 +92,7 @@ in {
         };
 
         port = mkOption {
+          type = types.int;
           default = 6600;
           description = ''
             This setting is the TCP port that is desired for the daemon to get assigned
@@ -114,12 +122,12 @@ in {
       after = [ "network.target" "sound.target" ];
       description = "Music Player Daemon";
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.mpd ];
+
       preStart = "mkdir -p ${cfg.dataDir} && chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}";
-      script = "exec mpd --no-daemon ${mpdConf}";
       serviceConfig = {
         User = "${cfg.user}";
         PermissionsStartOnly = true;
+        ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon ${mpdConf}";
       };
     };
 
diff --git a/nixos/modules/services/audio/ympd.nix b/nixos/modules/services/audio/ympd.nix
new file mode 100644
index 000000000000..d34c1c9d83cc
--- /dev/null
+++ b/nixos/modules/services/audio/ympd.nix
@@ -0,0 +1,57 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.ympd;
+in {
+
+  ###### interface
+
+  options = {
+
+    services.ympd = {
+
+      enable = mkEnableOption "ympd, the MPD Web GUI";
+
+      webPort = mkOption {
+        type = types.string;
+        default = "8080";
+        description = "The port where ympd's web interface will be available.";
+        example = "ssl://8080:/path/to/ssl-private-key.pem";
+      };
+
+      mpd = {
+        host = mkOption {
+          type = types.string;
+          default = "localhost";
+          description = "The host where MPD is listening.";
+          example = "localhost";
+        };
+
+        port = mkOption {
+          type = types.int;
+          default = config.services.mpd.network.port;
+          description = "The port where MPD is listening.";
+          example = 6600;
+        };
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.ympd = {
+      description = "Standalone MPD Web GUI written in C";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig.ExecStart = "${pkgs.ympd}/bin/ympd --host ${cfg.mpd.host} --port ${toString cfg.mpd.port} --webport ${cfg.webPort} --user nobody";
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/backup/rsnapshot.nix b/nixos/modules/services/backup/rsnapshot.nix
index ce628a720363..16815bcc8605 100644
--- a/nixos/modules/services/backup/rsnapshot.nix
+++ b/nixos/modules/services/backup/rsnapshot.nix
@@ -7,11 +7,14 @@ let
   cfgfile = pkgs.writeText "rsnapshot.conf" ''
     config_version	1.2
     cmd_cp	${pkgs.coreutils}/bin/cp
+    cmd_rm	${pkgs.coreutils}/bin/rm
     cmd_rsync	${pkgs.rsync}/bin/rsync
     cmd_ssh	${pkgs.openssh}/bin/ssh
     cmd_logger	${pkgs.inetutils}/bin/logger
     cmd_du	${pkgs.coreutils}/bin/du
+    cmd_rsnapshot_diff	${pkgs.rsnapshot}/bin/rsnapshot-diff
     lockfile	/run/rsnapshot.pid
+    link_dest	1
 
     ${cfg.extraConfig}
   '';
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
new file mode 100644
index 000000000000..1fe4d28f9f35
--- /dev/null
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -0,0 +1,51 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.gitlab-runner;
+  configFile = pkgs.writeText "config.toml" cfg.configText;
+in
+{
+  options.services.gitlab-runner = {
+    enable = mkEnableOption "Gitlab Runner";
+
+    configText = mkOption {
+      description = "Verbatim config.toml to use";
+    };
+
+    workDir = mkOption {
+      default = "/var/lib/gitlab-runner";
+      type = types.path;
+      description = "The working directory used";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.gitlab-runner = {
+      description = "Gitlab Runner";
+      after = [ "network.target" "docker.service" ];
+      requires = [ "docker.service" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = ''${pkgs.gitlab-runner.bin}/bin/gitlab-runner run \
+          --working-directory ${cfg.workDir} \
+          --config ${configFile} \
+          --service gitlab-runner \
+          --user gitlab-runner \
+        '';
+      };
+    };
+
+    users.extraUsers.gitlab-runner = {
+      group = "gitlab-runner";
+      extraGroups = [ "docker" ];
+      uid = config.ids.uids.gitlab-runner;
+      home = cfg.workDir;
+      createHome = true;
+    };
+
+    users.extraGroups.gitlab-runner.gid = config.ids.gids.gitlab-runner;
+  };
+}
diff --git a/nixos/modules/services/continuous-integration/gocd-agent/default.nix b/nixos/modules/services/continuous-integration/gocd-agent/default.nix
index 21f319f7fcf6..d60b55e83d11 100644
--- a/nixos/modules/services/continuous-integration/gocd-agent/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-agent/default.nix
@@ -98,7 +98,7 @@ in {
         ];
         description = ''
           Specifies startup command line arguments to pass to Go.CD agent
-          java process.  Example contains debug and gcLog arguments.
+          java process.
         '';
       };
 
diff --git a/nixos/modules/services/continuous-integration/gocd-server/default.nix b/nixos/modules/services/continuous-integration/gocd-server/default.nix
index 2d1986301216..4bb792055d25 100644
--- a/nixos/modules/services/continuous-integration/gocd-server/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-server/default.nix
@@ -90,7 +90,7 @@ in {
         '';
       };
 
-      extraOptions = mkOption {
+      startupOptions = mkOption {
         default = [
           "-Xms${cfg.initialJavaHeapSize}"
           "-Xmx${cfg.maxJavaHeapMemory}"
@@ -103,6 +103,15 @@ in {
           "-Dcruise.server.port=${toString cfg.port}"
           "-Dcruise.server.ssl.port=${toString cfg.sslPort}"
         ];
+
+        description = ''
+          Specifies startup command line arguments to pass to Go.CD server
+          java process.
+        '';
+      };
+
+      extraOptions = mkOption {
+        default = [ ];
         example = [ 
           "-X debug" 
           "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
@@ -169,7 +178,8 @@ in {
 
       script = ''
         ${pkgs.git}/bin/git config --global --add http.sslCAinfo /etc/ssl/certs/ca-certificates.crt
-        ${pkgs.jre}/bin/java -server ${concatStringsSep " " cfg.extraOptions} \
+        ${pkgs.jre}/bin/java -server ${concatStringsSep " " cfg.startupOptions} \
+                               ${concatStringsSep " " cfg.extraOptions}  \
                               -jar ${pkgs.gocd-server}/go-server/go.jar
       '';
 
diff --git a/nixos/modules/services/databases/4store-endpoint.nix b/nixos/modules/services/databases/4store-endpoint.nix
index 5c55ef406d57..906cb320df98 100644
--- a/nixos/modules/services/databases/4store-endpoint.nix
+++ b/nixos/modules/services/databases/4store-endpoint.nix
@@ -61,7 +61,9 @@ with lib;
     services.avahi.enable = true;
 
     systemd.services."4store-endpoint" = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
       script = ''
         ${run} '${pkgs.rdf4store}/bin/4s-httpd -D ${cfg.options} ${if cfg.listenAddress!=null then "-H ${cfg.listenAddress}" else "" } -p ${toString cfg.port} ${cfg.database}'
       '';
diff --git a/nixos/modules/services/databases/4store.nix b/nixos/modules/services/databases/4store.nix
index 33e731e96816..62856822f906 100644
--- a/nixos/modules/services/databases/4store.nix
+++ b/nixos/modules/services/databases/4store.nix
@@ -53,7 +53,8 @@ with lib;
     services.avahi.enable = true;
 
     systemd.services."4store" = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
 
       preStart = ''
         mkdir -p ${stateDir}/
diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix
index e2268bd556ef..11ea0e1b6b41 100644
--- a/nixos/modules/services/databases/influxdb.nix
+++ b/nixos/modules/services/databases/influxdb.nix
@@ -66,16 +66,16 @@ let
       enabled = false;
     }];
 
-    collectd = {
+    collectd = [{
       enabled = false;
       typesdb = "${pkgs.collectd}/share/collectd/types.db";
       database = "collectd_db";
       port = 25826;
-    };
+    }];
 
-    opentsdb = {
+    opentsdb = [{
       enabled = false;
-    };
+    }];
 
     continuous_queries = {
       enabled = true;
@@ -171,6 +171,11 @@ in
         mkdir -m 0770 -p ${cfg.dataDir}
         if [ "$(id -u)" = 0 ]; then chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}; fi
       '';
+      postStart = mkBefore ''
+        until ${pkgs.curl.bin}/bin/curl -s -o /dev/null 'http://127.0.0.1${toString configOptions.http.bind-address}'/ping; do
+          sleep 1;
+        done
+      '';
     };
 
     users.extraUsers = optional (cfg.user == "influxdb") {
diff --git a/nixos/modules/services/databases/monetdb.nix b/nixos/modules/services/databases/monetdb.nix
deleted file mode 100644
index 9f09c71e005a..000000000000
--- a/nixos/modules/services/databases/monetdb.nix
+++ /dev/null
@@ -1,88 +0,0 @@
-{ config, lib, pkgs, ... }:
-let
-  cfg = config.services.monetdb;
-  monetdbUser = "monetdb";
-in
-with lib;
-{
-
-  ###### interface
-
-  options = {
-
-    services.monetdb = {
-
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable MonetDB database server.";
-      };
-
-      package = mkOption {
-        type = types.path;
-        description = "MonetDB package to use.";
-      };
-
-      dbfarmDir = mkOption {
-        type = types.path;
-        default = "/var/lib/monetdb";
-        description = ''
-          Specifies location of Monetdb dbfarm (keeps database and auxiliary files).
-        '';
-      };
-
-      port = mkOption {
-        default = "50000";
-        example = "50000";
-        description = "Port to listen on.";
-      };
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    users.extraUsers.monetdb = 
-      { name = monetdbUser;
-        uid = config.ids.uids.monetdb;
-        description = "monetdb user";
-        home = cfg.dbfarmDir;
-      };
-
-    users.extraGroups.monetdb.gid = config.ids.gids.monetdb;
-
-    environment.systemPackages = [ cfg.package ];
-
-    systemd.services.monetdb =
-      { description = "MonetDB Server";
-
-        wantedBy = [ "multi-user.target" ];
-
-        after = [ "network.target" ];
-
-        path = [ cfg.package ];
-
-        preStart =
-          ''
-            # Initialise the database.
-            if ! test -e ${cfg.dbfarmDir}/.merovingian_properties; then
-                mkdir -m 0700 -p ${cfg.dbfarmDir}
-                chown -R ${monetdbUser} ${cfg.dbfarmDir}
-                ${cfg.package}/bin/monetdbd create ${cfg.dbfarmDir}
-                ${cfg.package}/bin/monetdbd set port=${cfg.port} ${cfg.dbfarmDir}
-            fi
-          '';
-
-        serviceConfig.ExecStart = "${cfg.package}/bin/monetdbd start -n ${cfg.dbfarmDir}";
-
-        serviceConfig.ExecStop = "${cfg.package}/bin/monetdbd stop ${cfg.dbfarmDir}";
-
-        unitConfig.RequiresMountsFor = "${cfg.dbfarmDir}";
-      };
-
-  };
-
-}
diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix
index ef9bc46e4a0e..38e46a0c6ef9 100644
--- a/nixos/modules/services/databases/mongodb.nix
+++ b/nixos/modules/services/databases/mongodb.nix
@@ -12,13 +12,11 @@ let
 
   mongoCnf = pkgs.writeText "mongodb.conf"
   ''
-    bind_ip = ${cfg.bind_ip}
-    ${optionalString cfg.quiet "quiet = true"}
-    dbpath = ${cfg.dbpath}
-    syslog = true
-    fork = true
-    pidfilepath = ${cfg.pidFile}
-    ${optionalString (cfg.replSetName != "") "replSet = ${cfg.replSetName}"}
+    net.bindIp: ${cfg.bind_ip}
+    ${optionalString cfg.quiet "systemLog.quiet: true"}
+    systemLog.destination: syslog
+    storage.dbPath: ${cfg.dbpath}
+    ${optionalString (cfg.replSetName != "") "replication.replSetName: ${cfg.replSetName}"}
     ${cfg.extraConfig}
   '';
 
@@ -84,9 +82,9 @@ in
       extraConfig = mkOption {
         default = "";
         example = ''
-          nojournal = true
+          storage.journal.enabled: false
         '';
-        description = "MongoDB extra configuration";
+        description = "MongoDB extra configuration in YAML format";
       };
     };
 
@@ -112,7 +110,7 @@ in
         after = [ "network.target" ];
 
         serviceConfig = {
-          ExecStart = "${mongodb}/bin/mongod --quiet --config ${mongoCnf}";
+          ExecStart = "${mongodb}/bin/mongod --quiet --config ${mongoCnf} --fork --pidfilepath ${cfg.pidFile}";
           User = cfg.user;
           PIDFile = cfg.pidFile;
           Type = "forking";
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/databases/riak.nix b/nixos/modules/services/databases/riak.nix
index bee768fa42ae..4477904f78c6 100644
--- a/nixos/modules/services/databases/riak.nix
+++ b/nixos/modules/services/databases/riak.nix
@@ -20,7 +20,7 @@ in
 
       package = mkOption {
         type = types.package;
-        example = literalExample "pkgs.riak2";
+        example = literalExample "pkgs.riak";
         description = ''
           Riak package to use.
         '';
@@ -108,6 +108,7 @@ in
         pkgs.bash
       ];
 
+      environment.HOME = "${cfg.dataDir}";
       environment.RIAK_DATA_DIR = "${cfg.dataDir}";
       environment.RIAK_LOG_DIR = "${cfg.logDir}";
       environment.RIAK_ETC_DIR = "/etc/riak";
diff --git a/nixos/modules/services/databases/virtuoso.nix b/nixos/modules/services/databases/virtuoso.nix
index bdd210a2550e..3231fede08fa 100644
--- a/nixos/modules/services/databases/virtuoso.nix
+++ b/nixos/modules/services/databases/virtuoso.nix
@@ -62,7 +62,8 @@ with lib;
       };
 
     systemd.services.virtuoso = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
 
       preStart = ''
         mkdir -p ${stateDir}
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..08fa6de6374c 100644
--- a/nixos/modules/services/editors/emacs.nix
+++ b/nixos/modules/services/editors/emacs.nix
@@ -79,8 +79,14 @@ in {
 
     environment.systemPackages = [ cfg.package editorScript ];
 
-    environment.variables = if cfg.defaultEditor then {
-      EDITOR = mkOverride 900 "${editorScript}/bin/emacseditor";
-    } else {};
+    environment.variables = {
+      # This is required so that GTK applications launched from Emacs
+      # get properly themed:
+      GTK_DATA_PREFIX = "${config.system.path}";
+    } // (if cfg.defaultEditor then {
+        EDITOR = mkOverride 900 "${editorScript}/bin/emacseditor";
+      } else {});
   };
+
+  meta.doc = ./emacs.xml;
 }
diff --git a/nixos/modules/services/editors/emacs.xml b/nixos/modules/services/editors/emacs.xml
index ee8ef512bc70..618460953a17 100644
--- a/nixos/modules/services/editors/emacs.xml
+++ b/nixos/modules/services/editors/emacs.xml
@@ -59,17 +59,17 @@
         <variablelist>
           <varlistentry>
             <term><varname>emacs</varname></term>
-            <term><varname>emacs24</varname></term>
+            <term><varname>emacs25</varname></term>
             <listitem>
               <para>
-                The latest stable version of Emacs 24 using the <link
+                The latest stable version of Emacs 25 using the <link
                 xlink:href="http://www.gtk.org">GTK+ 2</link> widget
                 toolkit.
               </para>
             </listitem>
           </varlistentry>
           <varlistentry>
-            <term><varname>emacs24-nox</varname></term>
+            <term><varname>emacs25-nox</varname></term>
             <listitem>
               <para>
                 Emacs 24 built without any dependency on X11
@@ -86,15 +86,6 @@
               </para>
             </listitem>
           </varlistentry>
-          <varlistentry>
-            <term><varname>emacs25pre</varname></term>
-            <listitem>
-              <para>
-                A pretest version of what will become the first
-                version of Emacs 25.
-              </para>
-            </listitem>
-          </varlistentry>
         </variablelist>
       </para>
 
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 7c4c93d0fcb3..14d65978c320 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -32,13 +32,11 @@ let
   '';
 
   # Perform substitutions in all udev rules files.
-  udevRules = stdenv.mkDerivation {
-    name = "udev-rules";
-
-    preferLocalBuild = true;
-    allowSubstitutes = false;
-
-    buildCommand = ''
+  udevRules = pkgs.runCommand "udev-rules"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
+    ''
       mkdir -p $out
       shopt -s nullglob
       set +o pipefail
@@ -130,15 +128,12 @@ let
         ln -s /dev/null $out/80-drivers.rules
       ''}
     ''; # */
-  };
 
-  hwdbBin = stdenv.mkDerivation {
-    name = "hwdb.bin";
-
-    preferLocalBuild = true;
-    allowSubstitutes = false;
-
-    buildCommand = ''
+  hwdbBin = pkgs.runCommand "hwdb.bin"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
+    ''
       mkdir -p etc/udev/hwdb.d
       for i in ${toString ([udev] ++ cfg.packages)}; do
         echo "Adding hwdb files for package $i"
@@ -151,7 +146,6 @@ let
       ${udev}/bin/udevadm hwdb --update --root=$(pwd)
       mv etc/udev/hwdb.bin $out
     '';
-  };
 
   # Udev has a 512-character limit for ENV{PATH}, so create a symlink
   # tree to work around this.
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index f239dda564a2..e79d5dadd828 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -271,6 +271,9 @@ in
       { assertion = cfg.showPAMFailure -> cfg.enablePAM;
         message = "dovecot is configured with showPAMFailure while enablePAM is disabled";
       }
+      { assertion = (cfg.sieveScripts != {}) -> ((cfg.mailUser != null) && (cfg.mailGroup != null));
+        message = "dovecot requires mailUser and mailGroup to be set when sieveScripts is set";
+      }
     ];
 
   };
diff --git a/nixos/modules/services/mail/freepops.nix b/nixos/modules/services/mail/freepops.nix
index e8c30a36923f..5b729ca50a5e 100644
--- a/nixos/modules/services/mail/freepops.nix
+++ b/nixos/modules/services/mail/freepops.nix
@@ -74,7 +74,8 @@ in
   config = mkIf cfg.enable {
     systemd.services.freepopsd = {
       description = "Freepopsd (webmail over POP3)";
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
       script = ''
         ${pkgs.freepops}/bin/freepopsd \
           -p ${toString cfg.port} \
diff --git a/nixos/modules/services/networking/offlineimap.nix b/nixos/modules/services/mail/offlineimap.nix
index daf6196d3706..85ece020905b 100644
--- a/nixos/modules/services/networking/offlineimap.nix
+++ b/nixos/modules/services/mail/offlineimap.nix
@@ -59,7 +59,7 @@ in {
       };
       path = cfg.path;
     };
-    environment.systemPackages = [ "${cfg.package}" ];
+    environment.systemPackages = [ cfg.package ];
     systemd.user.timers.offlineimap = {
       description = "offlineimap timer";
       timerConfig               = {
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/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix
new file mode 100644
index 000000000000..0db631868cc7
--- /dev/null
+++ b/nixos/modules/services/mail/postgrey.nix
@@ -0,0 +1,79 @@
+{ config, lib, pkgs, ... }:
+
+with lib; let
+
+  cfg = config.services.postgrey;
+
+in {
+
+  options = {
+    services.postgrey = with types; {
+      enable = mkOption {
+        type = bool;
+        default = false;
+        description = "Whether to run the Postgrey daemon";
+      };
+      inetAddr = mkOption {
+        type = nullOr string;
+        default = null;
+        example = "127.0.0.1";
+        description = "The inet address to bind to. If none given, bind to /var/run/postgrey.sock";
+      };
+      inetPort = mkOption {
+        type = int;
+        default = 10030;
+        description = "The tcp port to bind to";
+      };
+      greylistText = mkOption {
+        type = string;
+        default = "Greylisted for %%s seconds";
+        description = "Response status text for greylisted messages";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.postgrey ];
+
+    users = {
+      extraUsers = {
+        postgrey = {
+          description = "Postgrey Daemon";
+          uid = config.ids.uids.postgrey;
+          group = "postgrey";
+        };
+      };
+      extraGroups = {
+        postgrey = {
+          gid = config.ids.gids.postgrey;
+        };
+      };
+    };
+
+    systemd.services.postgrey = let
+      bind-flag = if isNull cfg.inetAddr then
+        "--unix=/var/run/postgrey.sock"
+      else
+        "--inet=${cfg.inetAddr}:${cfg.inetPort}";
+    in {
+      description = "Postfix Greylisting Service";
+      wantedBy = [ "multi-user.target" ];
+      before = [ "postfix.service" ];
+      preStart = ''
+        mkdir -p /var/postgrey
+        chown postgrey:postgrey /var/postgrey
+        chmod 0770 /var/postgrey
+      '';
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --pidfile=/var/run/postgrey.pid --group=postgrey --user=postgrey --dbdir=/var/postgrey --greylist-text="${cfg.greylistText}"'';
+        Restart = "always";
+        RestartSec = 5;
+        TimeoutSec = 10;
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/misc/autofs.nix b/nixos/modules/services/misc/autofs.nix
index 18f0c3eb83d5..40b48f70f7ed 100644
--- a/nixos/modules/services/misc/autofs.nix
+++ b/nixos/modules/services/misc/autofs.nix
@@ -22,7 +22,7 @@ in
         default = false;
         description = "
           Mount filesystems on demand. Unmount them automatically.
-          You may also be interested in afuese.
+          You may also be interested in afuse.
         ";
       };
 
diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix
index 72ec68dee6b3..fe13013286b8 100644..100755
--- a/nixos/modules/services/misc/confd.nix
+++ b/nixos/modules/services/misc/confd.nix
@@ -33,7 +33,7 @@ in {
 
     nodes = mkOption {
       description = "Confd list of nodes to connect to.";
-      default = [ "http://127.0.0.1:4001" ];
+      default = [ "http://127.0.0.1:2379" ];
       type = types.listOf types.str;
     };
 
diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix
deleted file mode 100644
index add339f9bdfe..000000000000
--- a/nixos/modules/services/misc/docker-registry.nix
+++ /dev/null
@@ -1,81 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.services.dockerRegistry;
-
-in {
-  ###### interface
-
-  options.services.dockerRegistry = {
-    enable = mkOption {
-      description = "Whether to enable docker registry server.";
-      default = false;
-      type = types.bool;
-    };
-
-    listenAddress = mkOption {
-      description = "Docker registry host or ip to bind to.";
-      default = "127.0.0.1";
-      type = types.str;
-    };
-
-    port = mkOption {
-      description = "Docker registry port to bind to.";
-      default = 5000;
-      type = types.int;
-    };
-
-    storagePath = mkOption {
-      type = types.path;
-      default = "/var/lib/docker-registry";
-      description = "Docker registry storage path.";
-    };
-
-    extraConfig = mkOption {
-      description = ''
-        Docker extra registry configuration. See
-        <link xlink:href="https://github.com/docker/docker-registry/blob/master/config/config_sample.yml"/>
-      '';
-      default = {};
-      type = types.attrsOf types.str;
-    };
-  };
-
-  config = mkIf cfg.enable {
-    systemd.services.docker-registry = {
-      description = "Docker Container Registry";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-
-      environment = {
-        REGISTRY_HOST = cfg.listenAddress;
-        REGISTRY_PORT = toString cfg.port;
-        GUNICORN_OPTS = "[--preload]"; # see https://github.com/docker/docker-registry#sqlalchemy
-        STORAGE_PATH = cfg.storagePath;
-      } // cfg.extraConfig;
-
-      serviceConfig = {
-        ExecStart = "${pkgs.pythonPackages.docker_registry}/bin/docker-registry";
-        User = "docker-registry";
-        Group = "docker";
-        PermissionsStartOnly = true;
-        WorkingDirectory = cfg.storagePath;
-      };
-
-      postStart = ''
-        until ${pkgs.curl.bin}/bin/curl -s -o /dev/null 'http://${cfg.listenAddress}:${toString cfg.port}/'; do
-          sleep 1;
-        done
-      '';
-    };
-
-    users.extraGroups.docker.gid = mkDefault config.ids.gids.docker;
-    users.extraUsers.docker-registry = {
-      createHome = true;
-      home = cfg.storagePath;
-      uid = config.ids.uids.docker-registry;
-    };
-  };
-}
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix
index 0d6ed8eb9043..d30cc5fd7e89 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -28,13 +28,13 @@ in {
 
     listenClientUrls = mkOption {
       description = "Etcd list of URLs to listen on for client traffic.";
-      default = ["http://localhost:4001"];
+      default = ["http://127.0.0.1:2379"];
       type = types.listOf types.str;
     };
 
     listenPeerUrls = mkOption {
       description = "Etcd list of URLs to listen on for peer traffic.";
-      default = ["http://localhost:7001"];
+      default = ["http://127.0.0.1:2380"];
       type = types.listOf types.str;
     };
 
@@ -46,7 +46,7 @@ in {
 
     initialCluster = mkOption {
       description = "Etcd initial cluster configuration for bootstrapping.";
-      default = ["${cfg.name}=http://localhost:7001"];
+      default = ["${cfg.name}=http://127.0.0.1:2380"];
       type = types.listOf types.str;
     };
 
@@ -68,6 +68,54 @@ in {
       type = types.str;
     };
 
+    clientCertAuth = mkOption {
+      description = "Whether to use certs for client authentication";
+      default = false;
+      type = types.bool;
+    };
+
+    trustedCaFile = mkOption {
+      description = "Certificate authority file to use for clients";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    certFile = mkOption {
+      description = "Cert file to use for clients";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    keyFile = mkOption {
+      description = "Key file to use for clients";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    peerCertFile = mkOption {
+      description = "Cert file to use for peer to peer communication";
+      default = cfg.certFile;
+      type = types.nullOr types.path;
+    };
+
+    peerKeyFile = mkOption {
+      description = "Key file to use for peer to peer communication";
+      default = cfg.keyFile;
+      type = types.nullOr types.path;
+    };
+
+    peerTrustedCaFile = mkOption {
+      description = "Certificate authority file to use for peer to peer communication";
+      default = cfg.trustedCaFile;
+      type = types.nullOr types.path;
+    };
+
+    peerClientCertAuth = mkOption {
+      description = "Whether to check all incoming peer requests from the cluster for valid client certificates signed by the supplied CA";
+      default = false;
+      type = types.bool;
+    };
+
     extraConf = mkOption {
       description = ''
         Etcd extra configuration. See
@@ -99,7 +147,7 @@ in {
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" ];
 
-      environment = {
+      environment = (filterAttrs (n: v: v != null) {
         ETCD_NAME = cfg.name;
         ETCD_DISCOVERY = cfg.discovery;
         ETCD_DATA_DIR = cfg.dataDir;
@@ -107,7 +155,14 @@ in {
         ETCD_LISTEN_CLIENT_URLS = concatStringsSep "," cfg.listenClientUrls;
         ETCD_LISTEN_PEER_URLS = concatStringsSep "," cfg.listenPeerUrls;
         ETCD_INITIAL_ADVERTISE_PEER_URLS = concatStringsSep "," cfg.initialAdvertisePeerUrls;
-      } // (optionalAttrs (cfg.discovery == ""){
+        ETCD_PEER_TRUSTED_CA_FILE = cfg.peerTrustedCaFile;
+        ETCD_PEER_CERT_FILE = cfg.peerCertFile;
+        ETCD_PEER_KEY_FILE = cfg.peerKeyFile;
+        ETCD_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth;
+        ETCD_TRUSTED_CA_FILE = cfg.trustedCaFile;
+        ETCD_CERT_FILE = cfg.certFile;
+        ETCD_KEY_FILE = cfg.keyFile;
+      }) // (optionalAttrs (cfg.discovery == ""){
         ETCD_INITIAL_CLUSTER = concatStringsSep "," cfg.initialCluster;
         ETCD_INITIAL_CLUSTER_STATE = cfg.initialClusterState;
         ETCD_INITIAL_CLUSTER_TOKEN = cfg.initialClusterToken;
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..f8881233dceb 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 = {};
@@ -424,13 +449,15 @@ in {
         Group = cfg.group;
         TimeoutSec = "300";
         Restart = "on-failure";
+        WorkingDirectory = gitlabEnv.HOME;
         ExecStart =
           "${cfg.packages.gitlab-workhorse}/bin/gitlab-workhorse "
           + "-listenUmask 0 "
           + "-listenNetwork unix "
           + "-listenAddr /run/gitlab/gitlab-workhorse.socket "
           + "-authSocket ${gitlabSocket} "
-          + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public";
+          + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public "
+          + "-secretPath ${cfg.packages.gitlab}/share/gitlab/.gitlab_workhorse_secret";
       };
     };
 
@@ -458,8 +485,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
@@ -501,17 +527,23 @@ in {
             psql postgres -c "CREATE ROLE gitlab WITH LOGIN NOCREATEDB NOCREATEROLE NOCREATEUSER ENCRYPTED PASSWORD '${cfg.databasePassword}'"
             ${config.services.postgresql.package}/bin/createdb --owner gitlab gitlab || true
             touch "${cfg.statePath}/db-created"
-
-            # The gitlab:setup task is horribly broken somehow, these two tasks will do the same for setting up the initial database
-            ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production
-            ${gitlab-rake}/bin/gitlab-rake db:seed_fu RAILS_ENV=production \
-              GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}";
           fi
         fi
 
+        # enable required pg_trgm extension for gitlab
+        psql gitlab -c "CREATE EXTENSION IF NOT EXISTS pg_trgm"
         # Always do the db migrations just to be sure the database is up-to-date
         ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production
 
+        # The gitlab:setup task is horribly broken somehow, the db:migrate
+        # task above and the db:seed_fu below will do the same for setting
+        # up the initial database
+        if ! test -e "${cfg.statePath}/db-seeded"; then
+          ${gitlab-rake}/bin/gitlab-rake db:seed_fu RAILS_ENV=production \
+            GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}"
+          touch "${cfg.statePath}/db-seeded"
+        fi
+
         # Change permissions in the last step because some of the
         # intermediary scripts like to create directories as root.
         chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}
@@ -532,4 +564,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/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
index bb8dc640f981..4145f8fa957a 100644
--- a/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixos/modules/services/misc/matrix-synapse.nix
@@ -5,15 +5,16 @@ with lib;
 let
   cfg = config.services.matrix-synapse;
   logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig;
-  mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${if r.compress then "true" else "false"}}'';
-  mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${if l.tls then "true" else "false"}, x_forwarded: ${if l.x_forwarded then "true" else "false"}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}'';
+  mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${fromBool r.compress}}'';
+  mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${fromBool l.tls}, x_forwarded: ${fromBool l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}'';
+  fromBool = x: if x then "true" else "false";
   configFile = pkgs.writeText "homeserver.yaml" ''
 tls_certificate_path: "${cfg.tls_certificate_path}"
 ${optionalString (cfg.tls_private_key_path != null) ''
 tls_private_key_path: "${cfg.tls_private_key_path}"
 ''}
 tls_dh_params_path: "${cfg.tls_dh_params_path}"
-no_tls: ${if cfg.no_tls then "true" else "false"}
+no_tls: ${fromBool cfg.no_tls}
 ${optionalString (cfg.bind_port != null) ''
 bind_port: ${toString cfg.bind_port}
 ''}
@@ -25,7 +26,7 @@ bind_host: "${cfg.bind_host}"
 ''}
 server_name: "${cfg.server_name}"
 pid_file: "/var/run/matrix-synapse.pid"
-web_client: ${if cfg.web_client then "true" else "false"}
+web_client: ${fromBool cfg.web_client}
 ${optionalString (cfg.public_baseurl != null) ''
 public_baseurl: "${cfg.public_baseurl}"
 ''}
@@ -53,14 +54,14 @@ media_store_path: "/var/lib/matrix-synapse/media"
 uploads_path: "/var/lib/matrix-synapse/uploads"
 max_upload_size: "${cfg.max_upload_size}"
 max_image_pixels: "${cfg.max_image_pixels}"
-dynamic_thumbnails: ${if cfg.dynamic_thumbnails then "true" else "false"}
+dynamic_thumbnails: ${fromBool cfg.dynamic_thumbnails}
 url_preview_enabled: False
 recaptcha_private_key: "${cfg.recaptcha_private_key}"
 recaptcha_public_key: "${cfg.recaptcha_public_key}"
-enable_registration_captcha: ${if cfg.enable_registration_captcha then "true" else "false"}
+enable_registration_captcha: ${fromBool cfg.enable_registration_captcha}
 turn_uris: ${builtins.toJSON cfg.turn_uris}
 turn_shared_secret: "${cfg.turn_shared_secret}"
-enable_registration: ${if cfg.enable_registration then "true" else "false"}
+enable_registration: ${fromBool cfg.enable_registration}
 ${optionalString (cfg.registration_shared_secret != null) ''
 registration_shared_secret: "${cfg.registration_shared_secret}"
 ''}
@@ -68,9 +69,15 @@ recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify"
 turn_user_lifetime: "${cfg.turn_user_lifetime}"
 user_creation_max_duration: ${cfg.user_creation_max_duration}
 bcrypt_rounds: ${cfg.bcrypt_rounds}
-allow_guest_access: {if cfg.allow_guest_access then "true" else "false"}
-enable_metrics: ${if cfg.enable_metrics then "true" else "false"}
-report_stats: ${if cfg.report_stats then "true" else "false"}
+allow_guest_access: ${fromBool cfg.allow_guest_access}
+trusted_third_party_id_servers: ${builtins.toJSON cfg.trusted_third_party_id_servers}
+room_invite_state_types: ${builtins.toJSON cfg.room_invite_state_types}
+${optionalString (cfg.macaroon_secret_key != null) ''
+  macaroon_secret_key: "${cfg.macaroon_secret_key}"
+''}
+expire_access_token: ${fromBool cfg.expire_access_token}
+enable_metrics: ${fromBool cfg.enable_metrics}
+report_stats: ${fromBool cfg.report_stats}
 signing_key_path: "/var/lib/matrix-synapse/homeserver.signing.key"
 key_refresh_interval: "${cfg.key_refresh_interval}"
 perspectives:
@@ -469,6 +476,34 @@ in {
           accessible to anonymous users.
         '';
       };
+      trusted_third_party_id_servers = mkOption {
+        type = types.listOf types.str;
+        default = ["matrix.org"];
+        description = ''
+          The list of identity servers trusted to verify third party identifiers by this server.
+        '';
+      };
+      room_invite_state_types = mkOption {
+        type = types.listOf types.str;
+        default = ["m.room.join_rules" "m.room.canonical_alias" "m.room.avatar" "m.room.name"];
+        description = ''
+          A list of event types that will be included in the room_invite_state
+        '';
+      };
+      macaroon_secret_key = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Secret key for authentication tokens
+        '';
+      };
+      expire_access_token = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable access token expiration.
+        '';
+      };
       key_refresh_interval = mkOption {
         type = types.str;
         default = "1d";
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/nix-optimise.nix b/nixos/modules/services/misc/nix-optimise.nix
new file mode 100644
index 000000000000..fea322a68f8e
--- /dev/null
+++ b/nixos/modules/services/misc/nix-optimise.nix
@@ -0,0 +1,49 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.nix.optimise;
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    nix.optimise = {
+
+      automatic = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Automatically run the nix store optimiser at a specific time.";
+      };
+
+      dates = mkOption {
+        default = "03:45";
+        type = types.listOf types.str;
+        description = ''
+          Specification (in the format described by
+          <citerefentry><refentrytitle>systemd.time</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry>) of the time at
+          which the optimiser will run.
+        '';
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    systemd.services.nix-optimise =
+      { description = "Nix Store Optimiser";
+        serviceConfig.ExecStart = "${config.nix.package}/bin/nix-store --optimise";
+        startAt = optional cfg.automatic cfg.dates;
+      };
+
+  };
+
+}
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/monitoring/cadvisor.nix b/nixos/modules/services/monitoring/cadvisor.nix
index a67df158be47..8ae8b12056ce 100644
--- a/nixos/modules/services/monitoring/cadvisor.nix
+++ b/nixos/modules/services/monitoring/cadvisor.nix
@@ -90,6 +90,7 @@ in {
             ${optionalString cfg.storageDriverSecure "-storage_driver_secure"}
           ''}
         '';
+        TimeoutStartSec=300;
       };
     };
 
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
new file mode 100644
index 000000000000..a9c0ce4ed6cb
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -0,0 +1,116 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.alertmanager;
+  mkConfigFile = pkgs.writeText "alertmanager.yml" (builtins.toJSON cfg.configuration);
+in {
+  options = {
+    services.prometheus.alertmanager = {
+      enable = mkEnableOption "Prometheus Alertmanager";
+
+      user = mkOption {
+        type = types.str;
+        default = "nobody";
+        description = ''
+          User name under which Alertmanager shall be run.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "nogroup";
+        description = ''
+          Group under which Alertmanager shall be run.
+        '';
+      };
+
+      configuration = mkOption {
+        type = types.attrs;
+        default = {};
+        description = ''
+          Alertmanager configuration as nix attribute set.
+        '';
+      };
+
+      logFormat = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          If set use a syslog logger or JSON logging.
+        '';
+      };
+
+      logLevel = mkOption {
+        type = types.enum ["debug" "info" "warn" "error" "fatal"];
+        default = "warn";
+        description = ''
+          Only log messages with the given severity or above.
+        '';
+      };
+
+      webExternalUrl = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          The URL under which Alertmanager is externally reachable (for example, if Alertmanager is served via a reverse proxy).
+          Used for generating relative and absolute links back to Alertmanager itself.
+          If the URL has a path portion, it will be used to prefix all HTTP endoints served by Alertmanager.
+          If omitted, relevant URL components will be derived automatically.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Address to listen on for the web interface and API.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 9093;
+        description = ''
+          Port to listen on for the web interface and API.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.alertmanager = {
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+      script = ''
+        ${pkgs.prometheus-alertmanager.bin}/bin/alertmanager \
+        -config.file ${mkConfigFile} \
+        -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+        -log.level ${cfg.logLevel} \
+        ${optionalString (cfg.webExternalUrl != null) ''-web.external-url ${cfg.webExternalUrl} \''}
+        ${optionalString (cfg.logFormat != null) "-log.format ${cfg.logFormat}"}
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = "/tmp";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix
new file mode 100644
index 000000000000..e6817ee227ab
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/default.nix
@@ -0,0 +1,445 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus;
+  promUser = "prometheus";
+  promGroup = "prometheus";
+
+  # Get a submodule without any embedded metadata:
+  _filter = x: filterAttrs (k: v: k != "_module") x;
+
+  # Pretty-print JSON to a file
+  writePrettyJSON = name: x:
+    pkgs.runCommand name { } ''
+      echo '${builtins.toJSON x}' | ${pkgs.jq}/bin/jq . > $out
+    '';
+
+  # This becomes the main config file
+  promConfig = {
+    global = cfg.globalConfig;
+    rule_files = cfg.ruleFiles ++ [
+      (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules))
+    ];
+    scrape_configs = cfg.scrapeConfigs;
+  };
+
+  cmdlineArgs = cfg.extraFlags ++ [
+    "-storage.local.path=${cfg.dataDir}/metrics"
+    "-config.file=${writePrettyJSON "prometheus.yml" promConfig}"
+    "-web.listen-address=${cfg.listenAddress}"
+    "-alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}"
+    "-alertmanager.timeout=${toString cfg.alertmanagerTimeout}s"
+    (optionalString (cfg.alertmanagerURL != []) "-alertmanager.url=${concatStringsSep "," cfg.alertmanagerURL}")
+  ];
+
+  promTypes.globalConfig = types.submodule {
+    options = {
+      scrape_interval = mkOption {
+        type = types.str;
+        default = "1m";
+        description = ''
+          How frequently to scrape targets by default.
+        '';
+      };
+
+      scrape_timeout = mkOption {
+        type = types.str;
+        default = "10s";
+        description = ''
+          How long until a scrape request times out.
+        '';
+      };
+
+      evaluation_interval = mkOption {
+        type = types.str;
+        default = "1m";
+        description = ''
+          How frequently to evaluate rules by default.
+        '';
+      };
+
+      labels = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        description = ''
+          The labels to add to any timeseries that this Prometheus instance
+          scrapes.
+        '';
+      };
+    };
+  };
+
+  promTypes.scrape_config = types.submodule {
+    options = {
+      job_name = mkOption {
+        type = types.str;
+        description = ''
+          The job name assigned to scraped metrics by default.
+        '';
+      };
+      scrape_interval = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          How frequently to scrape targets from this job. Defaults to the
+          globally configured default.
+        '';
+      };
+      scrape_timeout = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Per-target timeout when scraping this job. Defaults to the
+          globally configured default.
+        '';
+      };
+      metrics_path = mkOption {
+        type = types.str;
+        default = "/metrics";
+        description = ''
+          The HTTP resource path on which to fetch metrics from targets.
+        '';
+      };
+      scheme = mkOption {
+        type = types.enum ["http" "https"];
+        default = "http";
+        description = ''
+          The URL scheme with which to fetch metrics from targets.
+        '';
+      };
+      basic_auth = mkOption {
+        type = types.nullOr (types.submodule {
+          options = {
+            username = mkOption {
+              type = types.str;
+              description = ''
+                HTTP username
+              '';
+            };
+            password = mkOption {
+              type = types.str;
+              description = ''
+                HTTP password
+              '';
+            };
+          };
+        });
+        default = null;
+        description = ''
+          Optional http login credentials for metrics scraping.
+        '';
+      };
+      dns_sd_configs = mkOption {
+        type = types.listOf promTypes.dns_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of DNS service discovery configurations.
+        '';
+      };
+      consul_sd_configs = mkOption {
+        type = types.listOf promTypes.consul_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of Consul service discovery configurations.
+        '';
+      };
+      file_sd_configs = mkOption {
+        type = types.listOf promTypes.file_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of file service discovery configurations.
+        '';
+      };
+      static_configs = mkOption {
+        type = types.listOf promTypes.static_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of labeled target groups for this job.
+        '';
+      };
+      relabel_configs = mkOption {
+        type = types.listOf promTypes.relabel_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of relabel configurations.
+        '';
+      };
+    };
+  };
+
+  promTypes.static_config = types.submodule {
+    options = {
+      targets = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          The targets specified by the target group.
+        '';
+      };
+      labels = mkOption {
+        type = types.attrsOf types.str;
+        description = ''
+          Labels assigned to all metrics scraped from the targets.
+        '';
+      };
+    };
+  };
+
+  promTypes.dns_sd_config = types.submodule {
+    options = {
+      names = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          A list of DNS SRV record names to be queried.
+        '';
+      };
+      refresh_interval = mkOption {
+        type = types.str;
+        default = "30s";
+        description = ''
+          The time after which the provided names are refreshed.
+        '';
+      };
+    };
+  };
+
+  promTypes.consul_sd_config = types.submodule {
+    options = {
+      server = mkOption {
+        type = types.str;
+        description = "Consul server to query.";
+      };
+      token = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul token";
+      };
+      datacenter = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul datacenter";
+      };
+      scheme = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul scheme";
+      };
+      username = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul username";
+      };
+      password = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul password";
+      };
+
+      services = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          A list of services for which targets are retrieved.
+        '';
+      };
+      tag_separator = mkOption {
+        type = types.str;
+        default = ",";
+        description = ''
+          The string by which Consul tags are joined into the tag label.
+        '';
+      };
+    };
+  };
+
+  promTypes.file_sd_config = types.submodule {
+    options = {
+      files = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          Patterns for files from which target groups are extracted. Refer
+          to the Prometheus documentation for permitted filename patterns
+          and formats.
+
+        '';
+      };
+      refresh_interval = mkOption {
+        type = types.str;
+        default = "30s";
+        description = ''
+          Refresh interval to re-read the files.
+        '';
+      };
+    };
+  };
+
+  promTypes.relabel_config = types.submodule {
+    options = {
+      source_labels = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          The source labels select values from existing labels. Their content
+          is concatenated using the configured separator and matched against
+          the configured regular expression.
+        '';
+      };
+      separator = mkOption {
+        type = types.str;
+        default = ";";
+        description = ''
+          Separator placed between concatenated source label values.
+        '';
+      };
+      target_label = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Label to which the resulting value is written in a replace action.
+          It is mandatory for replace actions.
+        '';
+      };
+      regex = mkOption {
+        type = types.str;
+        description = ''
+          Regular expression against which the extracted value is matched.
+        '';
+      };
+      replacement = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Replacement value against which a regex replace is performed if the
+          regular expression matches.
+        '';
+      };
+      action = mkOption {
+        type = types.enum ["replace" "keep" "drop"];
+        description = ''
+          Action to perform based on regex matching.
+        '';
+      };
+    };
+  };
+
+in {
+  options = {
+    services.prometheus = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the Prometheus monitoring daemon.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "0.0.0.0:9090";
+        description = ''
+          Address to listen on for the web interface, API, and telemetry.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/prometheus";
+        description = ''
+          Directory to store Prometheus metrics data.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching Prometheus.
+        '';
+      };
+
+      globalConfig = mkOption {
+        type = promTypes.globalConfig;
+        default = {};
+        apply = _filter;
+        description = ''
+          Parameters that are valid in all  configuration contexts. They
+          also serve as defaults for other configuration sections
+        '';
+      };
+
+      rules = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Alerting and/or Recording rules to evaluate at runtime.
+        '';
+      };
+
+      ruleFiles = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          Any additional rules files to include in this configuration.
+        '';
+      };
+
+      scrapeConfigs = mkOption {
+        type = types.listOf promTypes.scrape_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          A list of scrape configurations.
+        '';
+      };
+
+      alertmanagerURL = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          List of Alertmanager URLs to send notifications to.
+        '';
+      };
+
+      alertmanagerNotificationQueueCapacity = mkOption {
+        type = types.int;
+        default = 10000;
+        description = ''
+          The capacity of the queue for pending alert manager notifications.
+        '';
+      };
+
+      alertmanagerTimeout = mkOption {
+        type = types.int;
+        default = 10;
+        description = ''
+          Alert manager HTTP API timeout (in seconds).
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraGroups.${promGroup}.gid = config.ids.gids.prometheus;
+    users.extraUsers.${promUser} = {
+      description = "Prometheus daemon user";
+      uid = config.ids.uids.prometheus;
+      group = promGroup;
+      home = cfg.dataDir;
+      createHome = true;
+    };
+    systemd.services.prometheus = {
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+      script = ''
+        #!/bin/sh
+        exec ${pkgs.prometheus}/bin/prometheus \
+          ${concatStringsSep " \\\n  " cmdlineArgs}
+      '';
+      serviceConfig = {
+        User = promUser;
+        Restart  = "always";
+        WorkingDirectory = cfg.dataDir;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/node-exporter.nix b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
new file mode 100644
index 000000000000..52dc14effc45
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
@@ -0,0 +1,71 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.nodeExporter;
+  cmdlineArgs = cfg.extraFlags ++ [
+    "-web.listen-address=${cfg.listenAddress}"
+  ];
+in {
+  options = {
+    services.prometheus.nodeExporter = {
+      enable = mkEnableOption "prometheus node exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9100;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.string;
+        default = "0.0.0.0";
+        description = ''
+          Address to listen on.
+        '';
+      };
+
+      enabledCollectors = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        example = ''[ "systemd" ]'';
+        description = ''
+          Collectors to enable, additionally to the defaults.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the node exporter.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.prometheus-node-exporter = {
+      description = "Prometheus exporter for machine metrics";
+      unitConfig.Documentation = "https://github.com/prometheus/node_exporter";
+      wantedBy = [ "multi-user.target" ];
+      script = ''
+        exec ${pkgs.prometheus-node-exporter}/bin/node_exporter \
+          ${optionalString (cfg.enabledCollectors != [])
+            ''-collectors.enabled ${concatStringsSep "," cfg.enabledCollectors}''} \
+          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+      serviceConfig = {
+        User = "nobody";
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/telegraf.nix b/nixos/modules/services/monitoring/telegraf.nix
new file mode 100644
index 000000000000..49dc9d8143e6
--- /dev/null
+++ b/nixos/modules/services/monitoring/telegraf.nix
@@ -0,0 +1,71 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.telegraf;
+
+  configFile = pkgs.runCommand "config.toml" {
+    buildInputs = [ pkgs.remarshal ];
+  } ''
+    remarshal -if json -of toml \
+      < ${pkgs.writeText "config.json" (builtins.toJSON cfg.extraConfig)} \
+      > $out
+  '';
+in {
+  ###### interface
+  options = {
+    services.telegraf = {
+      enable = mkEnableOption "telegraf server";
+
+      package = mkOption {
+        default = pkgs.telegraf;
+        defaultText = "pkgs.telegraf";
+        description = "Which telegraf derivation to use";
+        type = types.package;
+      };
+
+      extraConfig = mkOption {
+        default = {};
+        description = "Extra configuration options for telegraf";
+        type = types.attrs;
+        example = {
+          outputs = {
+            influxdb = {
+              urls = ["http://localhost:8086"];
+              database = "telegraf";
+            };
+          };
+          inputs = {
+            statsd = {
+              service_address = ":8125";
+              delete_timings = true;
+            };
+          };
+        };
+      };
+    };
+  };
+
+
+  ###### implementation
+  config = mkIf config.services.telegraf.enable {
+    systemd.services.telegraf = {
+      description = "Telegraf Agent";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      serviceConfig = {
+        ExecStart=''${cfg.package}/bin/telegraf -config "${configFile}"'';
+        ExecReload="${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        User = "telegraf";
+        Restart = "on-failure";
+      };
+    };
+
+    users.extraUsers = [{
+      name = "telegraf";
+      uid = config.ids.uids.telegraf;
+      description = "telegraf daemon user";
+    }];
+  };
+}
diff --git a/nixos/modules/services/monitoring/ups.nix b/nixos/modules/services/monitoring/ups.nix
index 5f80d547dbcb..febf0c95f5bd 100644
--- a/nixos/modules/services/monitoring/ups.nix
+++ b/nixos/modules/services/monitoring/ups.nix
@@ -182,7 +182,8 @@ in
 
     systemd.services.upsmon = {
       description = "Uninterruptible Power Supplies (Monitor)";
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
       serviceConfig.Type = "forking";
       script = "${pkgs.nut}/sbin/upsmon";
       environment.NUT_CONFPATH = "/etc/nut/";
@@ -191,8 +192,8 @@ in
 
     systemd.services.upsd = {
       description = "Uninterruptible Power Supplies (Daemon)";
+      after = [ "network.target" "upsmon.service" ];
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" "upsmon.service" ];
       serviceConfig.Type = "forking";
       # TODO: replace 'root' by another username.
       script = "${pkgs.nut}/sbin/upsd -u root";
@@ -202,8 +203,8 @@ in
 
     systemd.services.upsdrv = {
       description = "Uninterruptible Power Supplies (Register all UPS)";
-      wantedBy = [ "multi-user.target" ];
       after = [ "upsd.service" ];
+      wantedBy = [ "multi-user.target" ];
       # TODO: replace 'root' by another username.
       script = ''${pkgs.nut}/bin/upsdrvctl -u root start'';
       serviceConfig = {
diff --git a/nixos/modules/services/network-filesystems/drbd.nix b/nixos/modules/services/network-filesystems/drbd.nix
index 9896a93b1894..57b1fbb597c7 100644
--- a/nixos/modules/services/network-filesystems/drbd.nix
+++ b/nixos/modules/services/network-filesystems/drbd.nix
@@ -53,9 +53,9 @@ let cfg = config.services.drbd; in
       };
 
     systemd.services.drbd = {
-      after = [ "systemd-udev.settle.service" ];
+      after = [ "systemd-udev.settle.service" "network.target" ];
       wants = [ "systemd-udev.settle.service" ];
-      wantedBy = [ "ip-up.target" ];
+      wantedBy = [ "multi-user.target" ];
       script = ''
         ${pkgs.drbd}/sbin/drbdadm up all
       '';
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index a186982ec9c0..7de85b59e2af 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -56,6 +56,7 @@ let
       serviceConfig = {
         ExecStart = "${samba}/sbin/${appName} ${args}";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        Type = "notify";
       };
 
       restartTriggers = [ configFile ];
@@ -167,12 +168,12 @@ in
         type = types.attrsOf (types.attrsOf types.unspecified);
         example =
           { public =
-             { path = "/srv/public";
-               "read only" = true;
-               browseable = "yes";
-               "guest ok" = "yes";
-                comment = "Public samba share.";
-             };
+            { path = "/srv/public";
+              "read only" = true;
+              browseable = "yes";
+              "guest ok" = "yes";
+              comment = "Public samba share.";
+            };
           };
       };
 
diff --git a/nixos/modules/services/networking/amuled.nix b/nixos/modules/services/networking/amuled.nix
index bc488d0e9100..fc7d56a24fa7 100644
--- a/nixos/modules/services/networking/amuled.nix
+++ b/nixos/modules/services/networking/amuled.nix
@@ -59,7 +59,8 @@ in
 
     systemd.services.amuled = {
       description = "AMule daemon";
-      wantedBy = [ "ip-up.target" ];
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
 
       preStart = ''
         mkdir -p ${cfg.dataDir}
diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix
index 7650f45c5570..ecc091d1d03d 100644
--- a/nixos/modules/services/networking/avahi-daemon.nix
+++ b/nixos/modules/services/networking/avahi-daemon.nix
@@ -7,10 +7,6 @@ let
 
   cfg = config.services.avahi;
 
-  # We must escape interfaces due to the systemd interpretation
-  subsystemDevice = interface:
-    "sys-subsystem-net-devices-${utils.escapeSystemdPath interface}.device";
-
   avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" ''
     [server]
     ${# Users can set `networking.hostName' to the empty string, when getting
@@ -75,7 +71,8 @@ in
       };
 
       browseDomains = mkOption {
-        default = [ "0pointer.de" "zeroconf.org" ];
+        default = [ ];
+        example = [ "0pointer.de" "zeroconf.org" ];
         description = ''
           List of non-local DNS domains to be browsed.
         '';
@@ -179,14 +176,8 @@ in
     environment.systemPackages = [ pkgs.avahi ];
 
     systemd.services.avahi-daemon =
-      let
-        deps = optionals (cfg.interfaces!=null) (map subsystemDevice cfg.interfaces);
-      in
       { description = "Avahi daemon";
-        wantedBy = [ "ip-up.target" ];
-        bindsTo = deps;
-        after = deps;
-        before = [ "ip-up.target" ];
+        wantedBy = [ "multi-user.target" ];
         # Receive restart event after resume
         partOf = [ "post-resume.target" ];
 
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/connman.nix b/nixos/modules/services/networking/connman.nix
index 3fecfbb13a04..d0683b877801 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -27,6 +27,14 @@ in {
         '';
       };
 
+      enableVPN = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to enable ConnMan VPN service.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = ''
@@ -78,7 +86,7 @@ in {
       };
     };
 
-    systemd.services."connman-vpn" = {
+    systemd.services."connman-vpn" = mkIf cfg.enableVPN {
       description = "ConnMan VPN service";
       wantedBy = [ "multi-user.target" ];
       after = [ "syslog.target" ];
@@ -91,7 +99,7 @@ in {
       };
     };
 
-    systemd.services."net-connman-vpn" = {
+    systemd.services."net-connman-vpn" = mkIf cfg.enableVPN {
       description = "D-BUS Service";
       serviceConfig = {
         Name = "net.connman.vpn";
diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix
index 005c57dce7c7..e74d68cad902 100644
--- a/nixos/modules/services/networking/ddclient.nix
+++ b/nixos/modules/services/networking/ddclient.nix
@@ -7,7 +7,7 @@ let
 
   stateDir = "/var/spool/ddclient";
   ddclientUser = "ddclient";
-  ddclientFlags = "-foreground -verbose -noquiet -file /etc/ddclient.conf";
+  ddclientFlags = "-foreground -verbose -noquiet -file ${config.services.ddclient.configFile}";
   ddclientPIDFile = "${stateDir}/ddclient.pid";
 
 in
@@ -52,6 +52,17 @@ in
         '';
       };
 
+      configFile = mkOption {
+        default = "/etc/ddclient.conf";
+        type = path;
+        description = ''
+          Path to configuration file.
+          When set to the default '/etc/ddclient.conf' it will be populated with the various other options in this module. When it is changed (for example: '/root/nixos/secrets/ddclient.conf') the file read directly to configure ddclient. This is a source of impurity.
+          The purpose of this is to avoid placing secrets into the store.
+        '';
+        example = "/root/nixos/secrets/ddclient.conf";
+      };
+
       protocol = mkOption {
         default = "dyndns2";
         type = str;
@@ -88,7 +99,7 @@ in
         default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '";
         type = str;
         description = ''
-          Method to determine the IP address to send to the dymanic DNS provider.
+          Method to determine the IP address to send to the dynamic DNS provider.
         '';
       };
     };
@@ -109,9 +120,11 @@ in
     };
 
     environment.etc."ddclient.conf" = {
+      enable = config.services.ddclient.configFile == /etc/ddclient.conf;
       uid = config.ids.uids.ddclient;
       mode = "0600";
       text = ''
+        # This file can be used as a template for configFile or is automatically generated by Nix options.
         daemon=600
         cache=${stateDir}/ddclient.cache
         pid=${ddclientPIDFile}
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index b31d479ab4fd..4b0e90886510 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -10,7 +10,8 @@ let
 
   interfaces = attrValues config.networking.interfaces;
 
-  enableDHCP = config.networking.useDHCP || any (i: i.useDHCP == true) interfaces;
+  enableDHCP = config.networking.dhcpcd.enable &&
+        (config.networking.useDHCP || any (i: i.useDHCP == true) interfaces);
 
   # Don't start dhcpcd on explicitly configured interfaces or on
   # interfaces that are part of a bridge, bond or sit device.
@@ -61,7 +62,6 @@ let
       ${cfg.extraConfig}
     '';
 
-  # Hook for emitting ip-up/ip-down events.
   exitHook = pkgs.writeText "dhcpcd.exit-hook"
     ''
       if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then
@@ -73,14 +73,8 @@ let
           # applies to openntpd.
           ${config.systemd.package}/bin/systemctl try-restart ntpd.service
           ${config.systemd.package}/bin/systemctl try-restart openntpd.service
-
-          ${config.systemd.package}/bin/systemctl start ip-up.target
       fi
 
-      #if [ "$reason" = EXPIRE -o "$reason" = RELEASE -o "$reason" = NOCARRIER ] ; then
-      #    ${config.systemd.package}/bin/systemctl start ip-down.target
-      #fi
-
       ${cfg.runHook}
     '';
 
@@ -92,6 +86,15 @@ in
 
   options = {
 
+    networking.dhcpcd.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to enable dhcpcd for device configuration. This is mainly to
+        explicitly disable dhcpcd (for example when using networkd).
+      '';
+    };
+
     networking.dhcpcd.persistent = mkOption {
       type = types.bool;
       default = false;
@@ -154,10 +157,9 @@ in
     systemd.services.dhcpcd =
       { description = "DHCP Client";
 
-        wantedBy = [ "network.target" ];
-        # Work-around to deal with problems where the kernel would remove &
-        # re-create Wifi interfaces early during boot.
-        after = [ "network-interfaces.target" ];
+        wantedBy = [ "multi-user.target" ];
+        wants = [ "network.target" ];
+        before = [ "network.target" ];
 
         # Stopping dhcpcd during a reconfiguration is undesirable
         # because it brings down the network interfaces configured by
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/docker-registry-server.nix b/nixos/modules/services/networking/docker-registry-server.nix
deleted file mode 100644
index d21bbb6a86c3..000000000000
--- a/nixos/modules/services/networking/docker-registry-server.nix
+++ /dev/null
@@ -1,98 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.services.nodeDockerRegistry;
-
-in {
-  options.services.nodeDockerRegistry = {
-    enable = mkEnableOption "docker registry service";
-
-    port = mkOption {
-      description = "Docker registry listening port.";
-      default = 8080;
-      type = types.int;
-    };
-
-    users = mkOption {
-      description = "Docker registry list of users.";
-      default = [];
-      options = [{
-        user = mkOption {
-          description = "Docker registry user username.";
-          type = types.str;
-        };
-
-        pass = mkOption {
-          description = "Docker registry user password.";
-          type = types.str;
-        };
-      }];
-      type = types.listOf types.optionSet;
-    };
-
-    onTag = mkOption {
-      description = "Docker registry hook triggered when an image is tagged.";
-      default = "";
-      type = types.str;
-    };
-
-    onImage = mkOption {
-      description = "Docker registry hook triggered when an image metadata is uploaded.";
-      default = "";
-      type = types.str;
-    };
-
-    onLayer = mkOption {
-      description = "Docker registry hook triggered when an when an image layer is uploaded.";
-      default = "";
-      type = types.str;
-    };
-
-    onVerify = mkOption {
-      description = "Docker registry hook triggered when an image layer+metadata has been verified.";
-      default = "";
-      type = types.str;
-    };
-
-    onIndex = mkOption {
-      description = "Docker registry hook triggered when an when an image file system data has been indexed.";
-      default = "";
-      type = types.str;
-    };
-
-    dataDir = mkOption {
-      description = "Docker registry data directory";
-      default = "/var/lib/docker-registry";
-      type = types.path;
-    };
-  };
-
-  config = mkIf cfg.enable {
-    systemd.services.docker-registry-server = {
-      description = "Docker Registry Service.";
-      wantedBy = ["multi-user.target"];
-      after = ["network.target"];
-      script = ''
-        ${pkgs.nodePackages.docker-registry-server}/bin/docker-registry-server \
-          --dir ${cfg.dataDir} \
-          --port ${toString cfg.port} \
-          ${concatMapStringsSep " " (u: "--user ${u.user}:${u.pass}") cfg.users} \
-          ${optionalString (cfg.onTag != "") "--on-tag '${cfg.onTag}'"} \
-          ${optionalString (cfg.onImage != "") "--on-image '${cfg.onImage}'"} \
-          ${optionalString (cfg.onVerify != "") "--on-verify '${cfg.onVerify}'"} \
-          ${optionalString (cfg.onIndex != "") "--on-index '${cfg.onIndex}'"}
-      '';
-
-      serviceConfig.User = "docker-registry";
-    };
-
-    users.extraUsers.docker-registry = {
-      uid = config.ids.uids.docker-registry;
-      description = "Docker registry user";
-      createHome = true;
-      home = cfg.dataDir;
-    };
-  };
-}
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/firewall.nix b/nixos/modules/services/networking/firewall.nix
index 138153306dd8..942fcc03f59b 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -490,7 +490,8 @@ in
 
     systemd.services.firewall = {
       description = "Firewall";
-      wantedBy = [ "network-pre.target" ];
+      wantedBy = [ "sysinit.target" ];
+      wants = [ "network-pre.target" ];
       before = [ "network-pre.target" ];
       after = [ "systemd-modules-load.service" ];
 
@@ -500,6 +501,7 @@ in
       # containers don't have CAP_SYS_MODULE. So the host system had
       # better have all necessary modules already loaded.
       unitConfig.ConditionCapability = "CAP_NET_ADMIN";
+      unitConfig.DefaultDependencies = false;
 
       reloadIfChanged = true;
 
diff --git a/nixos/modules/services/networking/flannel.nix b/nixos/modules/services/networking/flannel.nix
new file mode 100644
index 000000000000..28b6c4f657dd
--- /dev/null
+++ b/nixos/modules/services/networking/flannel.nix
@@ -0,0 +1,153 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.flannel;
+
+  networkConfig = filterAttrs (n: v: v != null) {
+    Network = cfg.network;
+    SubnetLen = cfg.subnetLen;
+    SubnetMin = cfg.subnetMin;
+    SubnetMax = cfg.subnetMax;
+    Backend = cfg.backend;
+  };
+in {
+  options.services.flannel = {
+    enable = mkEnableOption "flannel";
+
+    package = mkOption {
+      description = "Package to use for flannel";
+      type = types.package;
+      default = pkgs.flannel.bin;
+    };
+
+    publicIp = mkOption {
+      description = ''
+        IP accessible by other nodes for inter-host communication.
+        Defaults to the IP of the interface being used for communication.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    iface = mkOption {
+      description = ''
+        Interface to use (IP or name) for inter-host communication.
+        Defaults to the interface for the default route on the machine.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    etcd = {
+      endpoints = mkOption {
+        description = "Etcd endpoints";
+        type = types.listOf types.str;
+        default = ["http://127.0.0.1:2379"];
+      };
+
+      prefix = mkOption {
+        description = "Etcd key prefix";
+        type = types.str;
+        default = "/coreos.com/network";
+      };
+
+      caFile = mkOption {
+        description = "Etcd certificate authority file";
+        type = types.nullOr types.path;
+        default = null;
+      };
+
+      certFile = mkOption {
+        description = "Etcd cert file";
+        type = types.nullOr types.path;
+        default = null;
+      };
+
+      keyFile = mkOption {
+        description = "Etcd key file";
+        type = types.nullOr types.path;
+        default = null;
+      };
+    };
+
+    network = mkOption {
+      description = " IPv4 network in CIDR format to use for the entire flannel network.";
+      type = types.str;
+    };
+
+    subnetLen = mkOption {
+      description = ''
+        The size of the subnet allocated to each host. Defaults to 24 (i.e. /24)
+        unless the Network was configured to be smaller than a /24 in which case
+        it is one less than the network.
+      '';
+      type = types.int;
+      default = 24;
+    };
+
+    subnetMin = mkOption {
+      description = ''
+        The beginning of IP range which the subnet allocation should start with.
+        Defaults to the first subnet of Network.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    subnetMax = mkOption {
+      description = ''
+        The end of IP range which the subnet allocation should start with.
+        Defaults to the last subnet of Network.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    backend = mkOption {
+      description = "Type of backend to use and specific configurations for that backend.";
+      type = types.attrs;
+      default = {
+        Type = "vxlan";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.flannel = {
+      description = "Flannel Service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      environment = {
+        FLANNELD_PUBLIC_IP = cfg.publicIp;
+        FLANNELD_ETCD_ENDPOINTS = concatStringsSep "," cfg.etcd.endpoints;
+        FLANNELD_ETCD_KEYFILE = cfg.etcd.keyFile;
+        FLANNELD_ETCD_CERTFILE = cfg.etcd.certFile;
+        FLANNELD_ETCD_CAFILE = cfg.etcd.caFile;
+        FLANNELD_IFACE = cfg.iface;
+        ETCDCTL_CERT_FILE = cfg.etcd.certFile;
+        ETCDCTL_KEY_FILE = cfg.etcd.keyFile;
+        ETCDCTL_CA_FILE = cfg.etcd.caFile;
+        ETCDCTL_PEERS = concatStringsSep "," cfg.etcd.endpoints;
+      };
+      preStart = ''
+        echo "setting network configuration"
+        until ${pkgs.etcdctl.bin}/bin/etcdctl set /coreos.com/network/config '${builtins.toJSON networkConfig}'
+        do
+          echo "setting network configuration, retry"
+          sleep 1
+        done
+      '';
+      postStart = ''
+        while [ ! -f /run/flannel/subnet.env ]
+        do
+          sleep 1
+        done
+      '';
+      serviceConfig.ExecStart = "${cfg.package}/bin/flannel";
+    };
+
+    services.etcd.enable = mkDefault cfg.etcd.endpoints == ["http://127.0.0.1:2379"];
+  };
+}
diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix
index 215ffe48a563..cd3fcd0f8f66 100644
--- a/nixos/modules/services/networking/git-daemon.nix
+++ b/nixos/modules/services/networking/git-daemon.nix
@@ -116,7 +116,8 @@ in
       };
 
     systemd.services."git-daemon" = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
       script = "${pkgs.git}/bin/git daemon --reuseaddr "
         + (optionalString (cfg.basePath != "") "--base-path=${cfg.basePath} ")
         + (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ")
diff --git a/nixos/modules/services/networking/htpdate.nix b/nixos/modules/services/networking/htpdate.nix
new file mode 100644
index 000000000000..f5d512c7cd5a
--- /dev/null
+++ b/nixos/modules/services/networking/htpdate.nix
@@ -0,0 +1,80 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  inherit (pkgs) htpdate;
+
+  cfg = config.services.htpdate;
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.htpdate = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable htpdate daemon.
+        '';
+      };
+
+      extraOptions = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Additional command line arguments to pass to htpdate.
+        '';
+      };
+
+      servers = mkOption {
+        type = types.listOf types.str;
+        default = [ "www.google.com" ];
+        description = ''
+          HTTP servers to use for time synchronization.
+        '';
+      };
+
+      proxy = mkOption {
+        type = types.str;
+        default = "";
+        example = "127.0.0.1:8118";
+        description = ''
+          HTTP proxy used for requests.
+        '';
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.htpdate = {
+      description = "htpdate daemon";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "forking";
+        PIDFile = "/var/run/htpdate.pid";
+        ExecStart = concatStringsSep " " [
+          "${htpdate}/bin/htpdate"
+          "-D -u nobody"
+          "-a -s"
+          "-l"
+          "${optionalString (cfg.proxy != "") "-P ${cfg.proxy}"}"
+          "${cfg.extraOptions}"
+          "${concatStringsSep " " cfg.servers}"
+        ];
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/iodine.nix b/nixos/modules/services/networking/iodine.nix
index 1b0d2d9a517c..512dbd77ae4b 100644
--- a/nixos/modules/services/networking/iodine.nix
+++ b/nixos/modules/services/networking/iodine.nix
@@ -106,7 +106,8 @@ in
       createIodineClientService = name: cfg:
       {
         description = "iodine client - ${name}";
-        wantedBy = [ "ip-up.target" ];
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig = {
           RestartSec = "30s";
           Restart = "always";
@@ -121,7 +122,8 @@ in
     ) // {
       iodined = mkIf (cfg.server.enable) {
         description = "iodine, ip over dns server daemon";
-        wantedBy = [ "ip-up.target" ];
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig.ExecStart = "${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${cfg.server.ip} ${cfg.server.domain}";
       };
     };
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/murmur.nix b/nixos/modules/services/networking/murmur.nix
index 1cc19a2c9e09..134544cda681 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -15,7 +15,7 @@ let
     logfile=/var/log/murmur/murmurd.log
     pidfile=${cfg.pidfile}
 
-    welcome="${cfg.welcome}"
+    welcometext="${cfg.welcometext}"
     port=${toString cfg.port}
 
     ${if cfg.hostName == "" then "" else "host="+cfg.hostName}
@@ -84,7 +84,7 @@ in
         description = "Path to PID file for Murmur daemon.";
       };
 
-      welcome = mkOption {
+      welcometext = mkOption {
         type = types.str;
         default = "";
         description = "Welcome message for connected clients.";
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index d198e3bfc02c..65ffaece4772 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -52,14 +52,6 @@ let
     });
   '';
 
-  ipUpScript = writeScript "01nixos-ip-up" ''
-    #!/bin/sh
-    if test "$2" = "up"; then
-      ${config.systemd.package}/bin/systemctl start ip-up.target
-      ${config.systemd.package}/bin/systemctl start network-online.target
-    fi
-  '';
-
   ns = xs: writeText "nameservers" (
     concatStrings (map (s: "nameserver ${s}\n") xs)
   );
@@ -188,9 +180,6 @@ in {
     boot.kernelModules = [ "ppp_mppe" ]; # Needed for most (all?) PPTP VPN connections.
 
     environment.etc = with cfg.basePackages; [
-      { source = ipUpScript;
-        target = "NetworkManager/dispatcher.d/01nixos-ip-up";
-      }
       { source = configFile;
         target = "NetworkManager/NetworkManager.conf";
       }
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index 333a3378c4cc..6af1dd736431 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -71,6 +71,7 @@ let
       # interfaces
     ${forEach "  ip-address: " cfg.interfaces}
 
+      ip-freebind:         ${yesOrNo  cfg.ipFreebind}
       hide-version:        ${yesOrNo  cfg.hideVersion}
       identity:            "${cfg.identity}"
       ip-transparent:      ${yesOrNo  cfg.ipTransparent}
@@ -84,7 +85,7 @@ let
       reuseport:           ${yesOrNo  cfg.reuseport}
       round-robin:         ${yesOrNo  cfg.roundRobin}
       server-count:        ${toString cfg.serverCount}
-      ${if cfg.statistics == null then "" else "statistics:          ${toString cfg.statistics}"}
+      ${maybeToString "statistics: " cfg.statistics}
       tcp-count:           ${toString cfg.tcpCount}
       tcp-query-count:     ${toString cfg.tcpQueryCount}
       tcp-timeout:         ${toString cfg.tcpTimeout}
@@ -117,7 +118,8 @@ let
   '';
 
   yesOrNo = b: if b then "yes" else "no";
-  maybeString = pre: s: if s == null then "" else ''${pre} "${s}"'';
+  maybeString = prefix: x: if x == null then "" else ''${prefix} "${s}"'';
+  maybeToString = prefix: x: if x == null then "" else ''${prefix} ${toString s}'';
   forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
 
 
@@ -146,6 +148,11 @@ let
     ${forEach     "  rrl-whitelist: "      zone.rrlWhitelist}
       ${maybeString "zonestats: "          zone.zoneStats}
 
+      ${maybeToString "max-refresh-time: " zone.maxRefreshSecs}
+      ${maybeToString "min-refresh-time: " zone.minRefreshSecs}
+      ${maybeToString "max-retry-time:   " zone.maxRetrySecs}
+      ${maybeToString "min-retry-time:   " zone.minRetrySecs}
+
       allow-axfr-fallback: ${yesOrNo       zone.allowAXFRFallback}
     ${forEach     "  allow-notify: "       zone.allowNotify}
     ${forEach     "  request-xfr: "        zone.requestXFR}
@@ -241,6 +248,44 @@ let
         '';
       };
 
+      maxRefreshSecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit refresh time for secondary zones. This is the timer which
+          checks to see if the zone has to be refetched when it expires.
+          Normally the value from the SOA record is used, but this  option
+          restricts that value.
+        '';
+      };
+
+      minRefreshSecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit refresh time for secondary zones.
+        '';
+      };
+
+      maxRetrySecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit retry time for secondary zones. This is the timeout after
+          a failed fetch attempt for the zone. Normally the value from
+          the SOA record is used, but this option restricts that value.
+        '';
+      };
+
+      minRetrySecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit retry time for secondary zones.
+        '';
+      };
+
+
       notify = mkOption {
         type = types.listOf types.str;
         default = [];
@@ -366,6 +411,15 @@ in
       '';
     };
 
+    ipFreebind = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to bind to nonlocal addresses and interfaces that are down.
+        Similar to ip-transparent.
+      '';
+    };
+
     ipTransparent = mkOption {
       type = types.bool;
       default = false;
diff --git a/nixos/modules/services/networking/powerdns.nix b/nixos/modules/services/networking/powerdns.nix
new file mode 100644
index 000000000000..91ad63b88139
--- /dev/null
+++ b/nixos/modules/services/networking/powerdns.nix
@@ -0,0 +1,50 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.powerdns;
+  configDir = pkgs.writeTextDir "pdns.conf" "${cfg.extraConfig}";
+in {
+  options = {
+    services.powerdns = {
+      enable = mkEnableOption "Powerdns domain name server";
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "launch=bind";
+        description = ''
+          Extra lines to be added verbatim to pdns.conf.
+          Powerdns will chroot to /var/lib/powerdns.
+          So any file, powerdns is supposed to be read,
+          should be in /var/lib/powerdns and needs to specified
+          relative to the chroot.
+        '';
+      };
+    };
+  };
+
+  config = mkIf config.services.powerdns.enable {
+    systemd.services.pdns = {
+      unitConfig.Documentation = "man:pdns_server(1) man:pdns_control(1)";
+      description = "Powerdns name server";
+      wantedBy = [ "multi-user.target" ];
+      after = ["network.target" "mysql.service" "postgresql.service" "openldap.service"];
+
+      serviceConfig = {
+        Restart="on-failure";
+        RestartSec="1";
+        StartLimitInterval="0";
+        PrivateTmp=true;
+        PrivateDevices=true;
+        CapabilityBoundingSet="CAP_CHOWN CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT";
+        NoNewPrivileges=true;
+        ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/lib/powerdns";
+        ExecStart = "${pkgs.powerdns}/bin/pdns_server --setuid=nobody --setgid=nogroup --chroot=/var/lib/powerdns --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${configDir}";
+        ProtectSystem="full";
+        ProtectHome=true;
+        RestrictAddressFamilies="AF_UNIX AF_INET AF_INET6";
+      };
+    };
+  };
+}
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/radicale.nix b/nixos/modules/services/networking/radicale.nix
index 19762f4e570c..e52c90227d3d 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -33,7 +33,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.pythonPackages.radicale ];
+    environment.systemPackages = [ pkgs.radicale ];
 
     users.extraUsers = singleton
       { name = "radicale";
@@ -52,8 +52,7 @@ in
       description = "A Simple Calendar and Contact Server";
       after = [ "network-interfaces.target" ];
       wantedBy = [ "multi-user.target" ];
-      script = "${pkgs.pythonPackages.radicale}/bin/radicale -C ${confFile} -d";
-      serviceConfig.Type = "forking";
+      script = "${pkgs.radicale}/bin/radicale -C ${confFile} -f";
       serviceConfig.User = "radicale";
       serviceConfig.Group = "radicale";
     };
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index f900ef494abf..1d15a1419722 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -85,7 +85,7 @@ in
 
       forwardX11 = mkOption {
         type = types.bool;
-        default = cfgc.setXAuthLocation;
+        default = false;
         description = ''
           Whether to allow X11 connections to be forwarded.
         '';
@@ -227,6 +227,8 @@ in
 
   config = mkIf cfg.enable {
 
+    programs.ssh.setXAuthLocation = mkForce cfg.forwardX11;
+
     users.extraUsers.sshd =
       { isSystemUser = true;
         description = "SSH privilege separation user";
diff --git a/nixos/modules/services/networking/supplicant.nix b/nixos/modules/services/networking/supplicant.nix
index 16c4ee7e33bb..e3107edcd7a9 100644
--- a/nixos/modules/services/networking/supplicant.nix
+++ b/nixos/modules/services/networking/supplicant.nix
@@ -34,7 +34,7 @@ let
       '';
     in
       { description = "Supplicant ${iface}${optionalString (iface=="WLAN"||iface=="LAN") " %I"}";
-        wantedBy = [ "network.target" ];
+        wantedBy = [ "network.target" ] ++ deps;
         bindsTo = deps;
         after = deps;
         before = [ "network.target" ];
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/toxvpn.nix b/nixos/modules/services/networking/toxvpn.nix
index c38424c8e273..911836fdee42 100644
--- a/nixos/modules/services/networking/toxvpn.nix
+++ b/nixos/modules/services/networking/toxvpn.nix
@@ -25,8 +25,8 @@ with lib;
     systemd.services.toxvpn = {
       description = "toxvpn daemon";
 
-      requires = [ "network-online.target" ]; # consider replacing by NetworkManager-wait-online.service
       wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
 
       preStart = ''
         mkdir -p /run/toxvpn || true
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index 0dd24478f409..6375ebee3209 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -12,9 +12,17 @@ let
 
   interfaces = concatMapStrings (x: "  interface: ${x}\n") cfg.interfaces;
 
-  forward = optionalString (length cfg.forwardAddresses != 0)
-    "forward-zone:\n  name: .\n" +
-    concatMapStrings (x: "  forward-addr: ${x}\n") cfg.forwardAddresses;
+  isLocalAddress = x: substring 0 3 x == "::1" || substring 0 9 x == "127.0.0.1";
+
+  forward =
+    optionalString (any isLocalAddress cfg.forwardAddresses) ''
+      do-not-query-localhost: no
+    '' +
+    optionalString (cfg.forwardAddresses != []) ''
+      forward-zone:
+        name: .
+    '' +
+    concatMapStringsSep "\n" (x: "    forward-addr: ${x}") cfg.forwardAddresses;
 
   rootTrustAnchorFile = "${stateDir}/root.key";
 
@@ -43,14 +51,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.";
       };
@@ -76,7 +80,11 @@ in
       extraConfig = mkOption {
         default = "";
         type = types.str;
-        description = "Extra lines of unbound config.";
+        description = ''
+          Extra unbound config. See
+          <citerefentry><refentrytitle>unbound.conf</refentrytitle><manvolnum>8
+          </manvolnum></citerefentry>.
+        '';
       };
 
     };
@@ -88,16 +96,13 @@ in
 
     environment.systemPackages = [ pkgs.unbound ];
 
-    users.extraUsers = singleton {
-      name = "unbound";
-      uid = config.ids.uids.unbound;
+    users.users.unbound = {
       description = "unbound daemon user";
-      home = stateDir;
-      createHome = true;
+      isSystemUser = true;
     };
 
     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" ];
@@ -111,12 +116,16 @@ in
         chown unbound ${stateDir} ${rootTrustAnchorFile}
         ''}
         touch ${stateDir}/dev/random
-        ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random
+        ${pkgs.utillinux}/bin/mount --bind -n /dev/urandom ${stateDir}/dev/random
       '';
 
       serviceConfig = {
         ExecStart = "${pkgs.unbound}/bin/unbound -d -c ${stateDir}/unbound.conf";
         ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random";
+
+        ProtectSystem = true;
+        ProtectHome = true;
+        PrivateDevices = true;
       };
     };
 
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/security/haveged.nix b/nixos/modules/services/security/haveged.nix
index 2aa523bf70a4..eca529188810 100644
--- a/nixos/modules/services/security/haveged.nix
+++ b/nixos/modules/services/security/haveged.nix
@@ -48,14 +48,18 @@ in
       { description = "Entropy Harvesting Daemon";
         unitConfig.Documentation = "man:haveged(8)";
         wantedBy = [ "multi-user.target" ];
-        
+
         path = [ pkgs.haveged ];
-        
-        serviceConfig = 
-          { Type = "forking";
-            ExecStart = "${pkgs.haveged}/sbin/haveged -w ${toString cfg.refill_threshold} -v 1";
-            PIDFile = "/run/haveged.pid";
-          };
+
+        serviceConfig = {
+          ExecStart = "${pkgs.haveged}/bin/haveged -F -w ${toString cfg.refill_threshold} -v 1";
+          SuccessExitStatus = 143;
+          PrivateTmp = true;
+          PrivateDevices = true;
+          PrivateNetwork = true;
+          ProtectSystem = "full";
+          ProtectHome = true;
+        };
       };
 
   };
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index 8bcd6f01656d..a7cf74c15cc5 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -8,7 +8,7 @@ let
 
   cfg = config.services.dbus;
 
-  homeDir = "/var/run/dbus";
+  homeDir = "/run/dbus";
 
   systemExtraxml = concatStrings (flip concatMap cfg.packages (d: [
     "<servicedir>${d}/share/dbus-1/system-services</servicedir>"
@@ -20,15 +20,23 @@ let
     "<includedir>${d}/etc/dbus-1/session.d</includedir>"
   ]));
 
-  configDir = pkgs.stdenv.mkDerivation {
-    name = "dbus-conf";
+  daemonArgs = "--address=systemd: --nofork --nopidfile --systemd-activation";
 
-    preferLocalBuild = true;
-    allowSubstitutes = false;
-
-    buildCommand = ''
+  configDir = pkgs.runCommand "dbus-conf"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
+    ''
       mkdir -p $out
 
+      cp ${pkgs.dbus.out}/share/dbus-1/{system,session}.conf $out
+
+      # avoid circular includes
+      sed -ri 's@(<include ignore_missing="yes">/etc/dbus-1/(system|session)\.conf</include>)@<!-- \1 -->@g' $out/{system,session}.conf
+
+      # include by full path
+      sed -ri "s@/etc/dbus-1/(system|session)-@$out/\1-@" $out/{system,session}.conf
+
       sed '${./dbus-system-local.conf.in}' \
         -e 's,@servicehelper@,${config.security.wrapperDir}/dbus-daemon-launch-helper,g' \
         -e 's,@extra@,${systemExtraxml},' \
@@ -38,7 +46,6 @@ let
         -e 's,@extra@,${sessionExtraxml},' \
         > "$out/session-local.conf"
     '';
-  };
 
 in
 
@@ -75,16 +82,21 @@ in
         '';
       };
 
+      socketActivated = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Make the user instance socket activated.
+        '';
+      };
     };
-
   };
 
-
   ###### implementation
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.dbus.daemon pkgs.dbus_tools ];
+    environment.systemPackages = [ pkgs.dbus.daemon pkgs.dbus ];
 
     environment.etc = singleton
       { source = configDir;
@@ -104,7 +116,7 @@ in
 
     security.setuidOwners = singleton
       { program = "dbus-daemon-launch-helper";
-        source = "${pkgs.dbus_daemon.out}/libexec/dbus-daemon-launch-helper";
+        source = "${pkgs.dbus.daemon}/libexec/dbus-daemon-launch-helper";
         owner = "root";
         group = "messagebus";
         setuid = true;
@@ -117,13 +129,29 @@ in
       config.system.path
     ];
 
-    # Don't restart dbus-daemon. Bad things tend to happen if we do.
-    systemd.services.dbus.reloadIfChanged = true;
+    systemd.services.dbus = {
+      # Don't restart dbus-daemon. Bad things tend to happen if we do.
+      reloadIfChanged = true;
+      restartTriggers = [ configDir ];
+      serviceConfig.ExecStart = [
+        ""
+        "${lib.getBin pkgs.dbus}/bin/dbus-daemon --config-file=${configDir}/system.conf ${daemonArgs}"
+      ];
+    };
 
-    systemd.services.dbus.restartTriggers = [ configDir ];
+    systemd.user = {
+      services.dbus = {
+        # Don't restart dbus-daemon. Bad things tend to happen if we do.
+        reloadIfChanged = true;
+        restartTriggers = [ configDir ];
+        serviceConfig.ExecStart = [
+          ""
+          "${lib.getBin pkgs.dbus}/bin/dbus-daemon --config-file=${configDir}/session.conf ${daemonArgs}"
+        ];
+      };
+      sockets.dbus.wantedBy = mkIf cfg.socketActivated [ "sockets.target" ];
+    };
 
     environment.pathsToLink = [ "/etc/dbus-1" "/share/dbus-1" ];
-
   };
-
 }
diff --git a/nixos/modules/services/ttys/agetty.nix b/nixos/modules/services/ttys/agetty.nix
index ea7196fc8733..051d54e932fb 100644
--- a/nixos/modules/services/ttys/agetty.nix
+++ b/nixos/modules/services/ttys/agetty.nix
@@ -80,8 +80,7 @@ in
       };
 
     systemd.services."container-getty@" =
-      { unitConfig.ConditionPathExists = "/dev/pts/%I"; # Work around being respawned when "machinectl login" exits.
-        serviceConfig.ExecStart = gettyCmd "--noclear --keep-baud pts/%I 115200,38400,9600 $TERM";
+      { serviceConfig.ExecStart = gettyCmd "--noclear --keep-baud pts/%I 115200,38400,9600 $TERM";
         restartIfChanged = false;
       };
 
diff --git a/nixos/modules/services/web-apps/selfoss.nix b/nixos/modules/services/web-apps/selfoss.nix
new file mode 100644
index 000000000000..5571f77334cc
--- /dev/null
+++ b/nixos/modules/services/web-apps/selfoss.nix
@@ -0,0 +1,166 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.selfoss;
+
+  poolName = "selfoss_pool";
+  phpfpmSocketName = "/var/run/phpfpm/${poolName}.sock";
+
+  dataDir = "/var/lib/selfoss";
+
+  selfoss-config =
+  let
+    db_type = cfg.database.type;
+    default_port = if (db_type == "mysql") then 3306 else 5342;
+  in
+  pkgs.writeText "selfoss-config.ini" ''
+    [globals]
+    ${lib.optionalString (db_type != "sqlite") ''
+      db_type=${db_type}
+      db_host=${cfg.database.host}
+      db_database=${cfg.database.name}
+      db_username=${cfg.database.user}
+      db_password=${cfg.database.password}
+      db_port=${if (cfg.database.port != null) then cfg.database.port
+                    else default_port}
+    ''
+    }
+    ${cfg.extraConfig}
+  '';
+in
+  {
+    options = {
+      services.selfoss = {
+        enable = mkEnableOption "selfoss";
+
+        user = mkOption {
+          type = types.str;
+          default = "nginx";
+          example = "nginx";
+          description = ''
+            User account under which both the service and the web-application run.
+          '';
+        };
+
+        pool = mkOption {
+          type = types.str;
+          default = "${poolName}";
+          description = ''
+            Name of existing phpfpm pool that is used to run web-application.
+            If not specified a pool will be created automatically with
+            default values.
+          '';
+        };
+
+      database = {
+        type = mkOption {
+          type = types.enum ["pgsql" "mysql" "sqlite"];
+          default = "sqlite";
+          description = ''
+            Database to store feeds. Supported are sqlite, pgsql and mysql.
+          '';
+        };
+
+        host = mkOption {
+          type = types.str;
+          default = "localhost";
+          description = ''
+            Host of the database (has no effect if type is "sqlite").
+          '';
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "tt_rss";
+          description = ''
+            Name of the existing database (has no effect if type is "sqlite").
+          '';
+        };
+
+        user = mkOption {
+          type = types.str;
+          default = "tt_rss";
+          description = ''
+            The database user. The user must exist and has access to
+            the specified database (has no effect if type is "sqlite").
+          '';
+        };
+
+        password = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          description = ''
+            The database user's password (has no effect if type is "sqlite").
+          '';
+        };
+
+        port = mkOption {
+          type = types.nullOr types.int;
+          default = null;
+          description = ''
+            The database's port. If not set, the default ports will be
+            provided (5432 and 3306 for pgsql and mysql respectively)
+            (has no effect if type is "sqlite").
+          '';
+        };
+      };
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra configuration added to config.ini
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") {
+      "${poolName}" = ''
+        listen = "${phpfpmSocketName}";
+        listen.owner = nginx
+        listen.group = nginx
+        listen.mode = 0600
+        user = nginx
+        pm = dynamic
+        pm.max_children = 75
+        pm.start_servers = 10
+        pm.min_spare_servers = 5
+        pm.max_spare_servers = 20
+        pm.max_requests = 500
+        catch_workers_output = 1
+      '';
+    };
+
+    systemd.services.selfoss-config = {
+      serviceConfig.Type = "oneshot";
+      script = ''
+        mkdir -m 755 -p ${dataDir}
+        cd ${dataDir}
+
+        # Delete all but the "data" folder
+        ls | grep -v data | while read line; do rm -rf $line; done || true
+
+        # Create the files
+        cp -r "${pkgs.selfoss}/"* "${dataDir}"
+        ln -sf "${selfoss-config}" "${dataDir}/config.ini"
+        chown -R "${cfg.user}" "${dataDir}"
+        chmod -R 755 "${dataDir}"
+      '';
+      wantedBy = [ "multi-user.target" ];
+    };
+
+    systemd.services.selfoss-update = {
+      serviceConfig = {
+        ExecStart = "${pkgs.php}/bin/php ${dataDir}/cliupdate.php";
+        User = "${cfg.user}";
+      };
+      startAt = "hourly";
+      after = [ "selfoss-config.service" ];
+      wantedBy = [ "multi-user.target" ];
+
+    };
+
+  };
+}
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index b08070f1e366..5193814da725 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -18,7 +18,6 @@ let
 
   poolName = "tt-rss";
   phpfpmSocketName = "/var/run/phpfpm/${poolName}.sock";
-  virtualHostName = "tt-rss";
 
   tt-rss-config = pkgs.writeText "config.php" ''
     <?php
@@ -34,10 +33,10 @@ let
       define('MYSQL_CHARSET', 'UTF8');
 
       define('DB_TYPE', '${cfg.database.type}');
-      define('DB_HOST', '${cfg.database.host}');
+      define('DB_HOST', '${optionalString (cfg.database.host != null) cfg.database.host}');
       define('DB_USER', '${cfg.database.user}');
       define('DB_NAME', '${cfg.database.name}');
-      define('DB_PASS', '${escape ["'" "\\"] cfg.database.password}');
+      define('DB_PASS', '${optionalString (cfg.database.password != null) (escape ["'" "\\"] cfg.database.password)}');
       define('DB_PORT', '${toString dbPort}');
 
       define('AUTH_AUTO_CREATE', ${boolToString cfg.auth.autoCreate});
@@ -91,12 +90,21 @@ let
 
       enable = mkEnableOption "tt-rss";
 
+      root = mkOption {
+        type = types.path;
+        default = "/var/lib/tt-rss";
+        example = "/var/lib/tt-rss";
+        description = ''
+          Root of the application.
+        '';
+      };
+
       user = mkOption {
         type = types.str;
         default = "nginx";
         example = "nginx";
         description = ''
-          User account under which both the service and the web-application run.
+          User account under which both the update daemon and the web-application run.
         '';
       };
 
@@ -110,17 +118,13 @@ let
         '';
       };
 
-      # TODO: Re-enable after https://github.com/NixOS/nixpkgs/pull/15862 is merged
-
-      # virtualHost = mkOption {
-      #   type = types.str;
-      #   default = "${virtualHostName}";
-      #   description = ''
-      #     Name of existing nginx virtual host that is used to run web-application.
-      #     If not specified a host will be created automatically with
-      #     default values.
-      #   '';
-      # };
+      virtualHost = mkOption {
+        type = types.nullOr types.str;
+        default = "tt-rss";
+        description = ''
+          Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost.
+        '';
+      };
 
       database = {
         type = mkOption {
@@ -132,10 +136,10 @@ let
         };
 
         host = mkOption {
-          type = types.str;
-          default = "localhost";
+          type = types.nullOr types.str;
+          default = null;
           description = ''
-            Host of the database.
+            Host of the database. Leave null to use Unix domain socket.
           '';
         };
 
@@ -362,7 +366,7 @@ let
 
       singleUserMode = mkOption {
         type = types.bool;
-        default = true;
+        default = false;
 
         description = ''
           Operate in single user mode, disables all functionality related to
@@ -445,17 +449,15 @@ let
 
   ###### implementation
 
-  config = let
-    root = "/var/lib/tt-rss";
-  in mkIf cfg.enable {
+  config = mkIf cfg.enable {
 
-    services.phpfpm.poolConfigs = if cfg.pool == "${poolName}" then {
+    services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") {
       "${poolName}" = ''
         listen = "${phpfpmSocketName}";
         listen.owner = nginx
         listen.group = nginx
         listen.mode = 0600
-        user = nginx
+        user = ${cfg.user}
         pm = dynamic
         pm.max_children = 75
         pm.start_servers = 10
@@ -464,36 +466,26 @@ let
         pm.max_requests = 500
         catch_workers_output = 1
       '';
-    } else {};
-
-    # TODO: Re-enable after https://github.com/NixOS/nixpkgs/pull/15862 is merged
-
-    # services.nginx.virtualHosts = if cfg.virtualHost == "${virtualHostName}" then {
-    #   "${virtualHostName}" = {
-    #     root = "${root}";
-    #     extraConfig = ''
-    #       access_log  /var/log/nginx-${virtualHostName}-access.log;
-    #       error_log   /var/log/nginx-${virtualHostName}-error.log;
-    #     '';
-
-    #     locations."/" = {
-    #       extraConfig = ''
-    #         index index.php;
-    #       '';
-    #     };
-
-    #     locations."~ \.php$" = {
-    #       extraConfig = ''
-    #         fastcgi_split_path_info ^(.+\.php)(/.+)$;
-    #         fastcgi_pass unix:${phpfpmSocketName};
-    #         fastcgi_index index.php;
-    #         fastcgi_param SCRIPT_FILENAME ${root}/$fastcgi_script_name;
-
-    #         include ${pkgs.nginx}/conf/fastcgi_params;
-    #       '';
-    #     };
-    #   };
-    # } else {};
+    };
+
+    services.nginx.virtualHosts = mkIf (cfg.virtualHost != null) {
+      "${cfg.virtualHost}" = {
+        root = "${cfg.root}";
+
+        locations."/" = {
+          index = "index.php";
+        };
+
+        locations."~ \.php$" = {
+          extraConfig = ''
+            fastcgi_split_path_info ^(.+\.php)(/.+)$;
+            fastcgi_pass unix:${phpfpmSocketName};
+            fastcgi_index index.php;
+            fastcgi_param SCRIPT_FILENAME ${cfg.root}/$fastcgi_script_name;
+          '';
+        };
+      };
+    };
 
 
     systemd.services.tt-rss = let
@@ -503,35 +495,34 @@ let
         description = "Tiny Tiny RSS feeds update daemon";
 
         preStart = let
-          callSql = if cfg.database.type == "pgsql" then (e: ''
-                 ${optionalString (cfg.database.password != null)
-                   "PGPASSWORD=${cfg.database.password}"} ${pkgs.postgresql95}/bin/psql \
-                     -U ${cfg.database.user}                                            \
-                     -h ${cfg.database.host}                                            \
-                     --port ${toString dbPort}                                          \
-                     -c '${e}'                                                          \
-                     ${cfg.database.name}'')
-
-               else if cfg.database.type == "mysql" then (e: ''
-                 echo '${e}' | ${pkgs.mysql}/bin/mysql                  \
-                   ${optionalString (cfg.database.password != null)
-                     "-p${cfg.database.password}"}                      \
-                   -u ${cfg.database.user}                              \
-                   -h ${cfg.database.host}                              \
-                   -P ${toString dbPort}                                \
-                   ${cfg.database.name}'')
-
-               else "";
+          callSql = e:
+              if cfg.database.type == "pgsql" then ''
+                  ${optionalString (cfg.database.password != null) "PGPASSWORD=${cfg.database.password}"} \
+                  ${pkgs.postgresql95}/bin/psql \
+                    -U ${cfg.database.user} \
+                    ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} --port ${toString dbPort}"} \
+                    -c '${e}' \
+                    ${cfg.database.name}''
+
+              else if cfg.database.type == "mysql" then ''
+                  echo '${e}' | ${pkgs.mysql}/bin/mysql \
+                    -u ${cfg.database.user} \
+                    ${optionalString (cfg.database.password != null) "-p${cfg.database.password}"} \
+                    ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} -P ${toString dbPort}"} \
+                    ${cfg.database.name}''
+
+              else "";
 
         in ''
-          rm -rf "${root}/*"
-          mkdir -m 755 -p "${root}"
-          cp -r "${pkgs.tt-rss}/"* "${root}"
-          ln -sf "${tt-rss-config}" "${root}/config.php"
-          chown -R "${cfg.user}" "${root}"
-          chmod -R 755 "${root}"
-        '' + (optionalString (cfg.database.type == "pgsql") ''
-
+          rm -rf "${cfg.root}/*"
+          mkdir -m 755 -p "${cfg.root}"
+          cp -r "${pkgs.tt-rss}/"* "${cfg.root}"
+          ln -sf "${tt-rss-config}" "${cfg.root}/config.php"
+          chown -R "${cfg.user}" "${cfg.root}"
+          chmod -R 755 "${cfg.root}"
+        ''
+
+        + (optionalString (cfg.database.type == "pgsql") ''
           exists=$(${callSql "select count(*) > 0 from pg_tables where tableowner = user"} \
           | tail -n+3 | head -n-2 | sed -e 's/[ \n\t]*//')
 
@@ -540,8 +531,9 @@ let
           else
             echo 'The database contains some data. Leaving it as it is.'
           fi;
-        '') + (optionalString (cfg.database.type == "mysql") ''
+        '')
 
+        + (optionalString (cfg.database.type == "mysql") ''
           exists=$(${callSql "select count(*) > 0 from information_schema.tables where table_schema = schema()"} \
           | tail -n+2 | sed -e 's/[ \n\t]*//')
 
@@ -554,7 +546,7 @@ let
 
         serviceConfig = {
           User = "${cfg.user}";
-          ExecStart = "${pkgs.php}/bin/php /var/lib/tt-rss/update.php --daemon";
+          ExecStart = "${pkgs.php}/bin/php ${cfg.root}/update.php --daemon";
           StandardOutput = "syslog";
           StandardError = "syslog";
           PermissionsStartOnly = true;
diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
index b4b5a6fdc07e..4f9e9f52f9e0 100644
--- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
@@ -83,11 +83,11 @@ let
 
   # Unpack Mediawiki and put the config file in its root directory.
   mediawikiRoot = pkgs.stdenv.mkDerivation rec {
-    name= "mediawiki-1.23.13";
+    name= "mediawiki-1.27.1";
 
     src = pkgs.fetchurl {
-      url = "http://download.wikimedia.org/mediawiki/1.23/${name}.tar.gz";
-      sha256 = "168wpf53n4ksj2g5q5r0hxapx6238dvsfng5ff9ixk6axsn0j5d0";
+      url = "http://download.wikimedia.org/mediawiki/1.27/${name}.tar.gz";
+      sha256 = "0sm3ymz93qragbwhzzbwq7f127mbj29inv0afg2z6p32jb1pd9h8";
     };
 
     skins = config.skins;
diff --git a/nixos/modules/services/web-servers/apache-httpd/moodle.nix b/nixos/modules/services/web-servers/apache-httpd/moodle.nix
index 87b1fba5aa10..aa00e89967db 100644
--- a/nixos/modules/services/web-servers/apache-httpd/moodle.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/moodle.nix
@@ -63,6 +63,10 @@ let
         cp -r * $out
         cp ${moodleConfig} $out/config.php
       '';
+    # Marked as broken due to needing an update for security issues.
+    # See: https://github.com/NixOS/nixpkgs/issues/18856
+    meta.broken = true;
+
   };
 
 in
diff --git a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
index 937b2698ce9b..007c7669d8ac 100644
--- a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
@@ -5,7 +5,8 @@ with lib;
 
 let
 
-  version = "4.3.1";
+  # Upgrading? We have a test! nix-build ./nixos/tests/wordpress.nix
+  version = "4.6.1";
   fullversion = "${version}";
 
   # Our bare-bones wp-config.php file using the above settings
@@ -74,7 +75,7 @@ let
       owner = "WordPress";
       repo = "WordPress";
       rev = "${fullversion}";
-      sha256 = "1rk10vcv4z9p04hfzc0wkbilrgx7m9ssyr6c3w6vw3vl1bcgqxza";
+      sha256 = "0n82xgjg1ry2p73hhgpslnkdzrma5n6hxxq76s7qskkzj0qjfvpn";
     };
     installPhase = ''
       mkdir -p $out
@@ -98,7 +99,7 @@ let
       # symlink additional plugin(s)
       ${concatMapStrings (plugin: "ln -s ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins) }
 
-      # symlink additional translation(s) 
+      # symlink additional translation(s)
       mkdir -p $out/wp-content/languages
       ${concatMapStrings (language: "ln -s ${language}/*.mo ${language}/*.po $out/wp-content/languages/\n") (selectedLanguages) }
     '';
@@ -123,7 +124,7 @@ in
   options = {
     dbHost = mkOption {
       default = "localhost";
-      description = "The location of the database server.";  
+      description = "The location of the database server.";
       example = "localhost";
     };
     dbName = mkOption {
@@ -253,7 +254,7 @@ in
       done
       ${pkgs.mysql}/bin/mysql -e 'CREATE DATABASE ${config.dbName};'
       ${pkgs.mysql}/bin/mysql -e 'GRANT ALL ON ${config.dbName}.* TO ${config.dbUser}@localhost IDENTIFIED BY "${config.dbPassword}";'
-    else 
+    else
       echo "Good, no need to do anything database related."
     fi
   '';
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index af7753470de6..443bd8c10000 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -18,9 +18,13 @@ let
 
     ${cfg.config}
 
-    ${optionalString (cfg.httpConfig == "" && cfg.config == "") ''
-    events {}
+    ${optionalString (cfg.eventsConfig != "" || cfg.config == "") ''
+    events {
+      ${cfg.eventsConfig}
+    }
+    ''}
 
+    ${optionalString (cfg.httpConfig == "" && cfg.config == "") ''
     http {
       include ${cfg.package}/conf/mime.types;
       include ${cfg.package}/conf/fastcgi.conf;
@@ -98,7 +102,6 @@ let
     }''}
 
     ${optionalString (cfg.httpConfig != "") ''
-    events {}
     http {
       include ${cfg.package}/conf/mime.types;
       include ${cfg.package}/conf/fastcgi.conf;
@@ -114,17 +117,18 @@ let
         port = if vhost.port != null then vhost.port else (if ssl then 443 else 80);
         listenString = toString port + optionalString ssl " ssl http2"
           + optionalString vhost.default " default";
-        acmeLocation = optionalString vhost.enableACME ''
+        acmeLocation = optionalString vhost.enableACME (''
           location /.well-known/acme-challenge {
-            try_files $uri @acme-fallback;
+            ${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"}
             root ${vhost.acmeRoot};
             auth_basic off;
           }
+        '' + (optionalString (vhost.acmeFallbackHost != null) ''
           location @acme-fallback {
             auth_basic off;
             proxy_pass http://${vhost.acmeFallbackHost};
           }
-        '';
+        ''));
       in ''
         ${optionalString vhost.forceSSL ''
           server {
@@ -165,6 +169,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}
     }
@@ -269,12 +275,20 @@ in
         ";
       };
 
+      eventsConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Configuration lines to be set inside the events block.
+        '';
+      };
+
       appendHttpConfig = mkOption {
         type = types.lines;
         default = "";
         description = "
           Configuration lines to be appended to the generated http block.
-          This is mutually exclusive with using config and httpConfig for 
+          This is mutually exclusive with using config and httpConfig for
           specifying the whole http block verbatim.
         ";
       };
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/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix
index ee3f68bf8059..dcebbc9229fc 100644
--- a/nixos/modules/services/web-servers/nginx/vhost-options.nix
+++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix
@@ -39,8 +39,8 @@ with lib;
     };
 
     acmeFallbackHost = mkOption {
-      type = types.str;
-      default = "0.0.0.0";
+      type = types.nullOr types.str;
+      default = null;
       description = ''
         Host which to proxy requests to if acme challenge is not found. Useful
         if you want multiple hosts to be able to verify the same domain name.
diff --git a/nixos/modules/services/web-servers/phpfpm/default.nix b/nixos/modules/services/web-servers/phpfpm/default.nix
index 29cfbb8e9a08..a3a23b222fbb 100644
--- a/nixos/modules/services/web-servers/phpfpm/default.nix
+++ b/nixos/modules/services/web-servers/phpfpm/default.nix
@@ -42,7 +42,7 @@ in {
         default = "";
         description = ''
           Extra configuration that should be put in the global section of
-          the PHP FPM configuration file. Do not specify the options
+          the PHP-FPM configuration file. Do not specify the options
           <literal>pid</literal>, <literal>error_log</literal> or
           <literal>daemonize</literal> here, since they are generated by
           NixOS.
@@ -54,7 +54,7 @@ in {
         default = pkgs.php;
         defaultText = "pkgs.php";
         description = ''
-          The PHP package to use for running the FPM service.
+          The PHP package to use for running the PHP-FPM service.
         '';
       };
 
@@ -86,7 +86,7 @@ in {
           }
         '';
         description = ''
-          A mapping between PHP FPM pool names and their configurations.
+          A mapping between PHP-FPM pool names and their configurations.
           See the documentation on <literal>php-fpm.conf</literal> for
           details on configuration directives. If no pools are defined,
           the phpfpm service is disabled.
@@ -98,8 +98,24 @@ in {
           inherit lib;
         }));
         default = {};
+        example = literalExample ''
+         {
+           mypool = {
+             listen = "/path/to/unix/socket";
+             extraConfig = '''
+               user = nobody
+               pm = dynamic
+               pm.max_children = 75
+               pm.start_servers = 10
+               pm.min_spare_servers = 5
+               pm.max_spare_servers = 20
+               pm.max_requests = 500
+             ''';
+           }
+         }'';
         description = ''
-          If no pools are defined, the phpfpm service is disabled.
+          PHP-FPM pools. If no pools or poolConfigs are defined, the PHP-FPM
+          service is disabled.
         '';
       };
     };
diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix
index c3be20b41e29..fa6b4c0629d7 100644
--- a/nixos/modules/services/web-servers/tomcat.nix
+++ b/nixos/modules/services/web-servers/tomcat.nix
@@ -10,6 +10,10 @@ in
 
 {
 
+  meta = {
+    maintainers = with maintainers; [ danbst ];
+  };
+
   ###### interface
 
   options = {
@@ -23,9 +27,9 @@ in
 
       package = mkOption {
         type = types.package;
-        default = pkgs.tomcat7;
-        defaultText = "pkgs.tomcat7";
-        example = lib.literalExample "pkgs.tomcat8";
+        default = pkgs.tomcat85;
+        defaultText = "pkgs.tomcat85";
+        example = lib.literalExample "pkgs.tomcatUnstable";
         description = ''
           Which tomcat package to use.
         '';
@@ -74,8 +78,8 @@ in
 
       webapps = mkOption {
         type = types.listOf types.package;
-        default = [ tomcat ];
-        defaultText = "[ tomcat ]";
+        default = [ tomcat.webapps ];
+        defaultText = "[ tomcat.webapps ]";
         description = "List containing WAR files or directories with WAR files which are web applications to be deployed on Tomcat";
       };
 
@@ -352,7 +356,7 @@ in
           ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c 'CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${cfg.jdk} JAVA_OPTS="${cfg.javaOpts}" CATALINA_OPTS="${cfg.catalinaOpts}" ${tomcat}/bin/startup.sh'
       '';
 
-      postStop = ''
+      preStop = ''
         echo "Stopping tomcat..."
         CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${cfg.jdk} ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c ${tomcat}/bin/shutdown.sh
       '';
diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 2e788d869607..7ea8b30d23d1 100644
--- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix
+++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -29,13 +29,13 @@ 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.
+      pkgs.gtk2 # To get GTK+'s themes.
       pkgs.tango-icon-theme
       pkgs.shared_mime_info
-      pkgs.gnome.gnomeicontheme
+      pkgs.gnome2.gnomeicontheme
       pkgs.xorg.xcursorthemes
     ];
 
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index b3da25448029..dc71531759b8 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -25,9 +25,8 @@ let
     '';
   };
 
-  nixos-gsettings-desktop-schemas = pkgs.stdenv.mkDerivation {
-    name = "nixos-gsettings-desktop-schemas";
-    buildCommand = ''
+  nixos-gsettings-desktop-schemas = pkgs.runCommand "nixos-gsettings-desktop-schemas" {}
+    ''
      mkdir -p $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
      cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0/schemas/*.xml $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
 
@@ -46,7 +45,6 @@ let
 
      ${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/
     '';
-  };
 
 in {
 
diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix
index 1927341e45d4..3aa4821a0521 100644
--- a/nixos/modules/services/x11/desktop-managers/kde4.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde4.nix
@@ -14,7 +14,7 @@ let
   # files), segfault sometimes and consume significant resources.
   # They can be re-enabled in the KDE System Settings under "Desktop
   # Search".
-  nepomukConfig = pkgs.writeTextFile
+  disableNepomuk = pkgs.writeTextFile
     { name = "nepomuk-config";
       destination = "/share/config/nepomukserverrc";
       text =
@@ -70,6 +70,18 @@ in
         type = types.package;
         description = "Custom kde-workspace, used for NixOS rebranding.";
       };
+
+      enablePIM = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Whether to enable PIM support. Note that enabling this pulls in Akonadi and MariaDB as dependencies.";
+      };
+
+      enableNepomuk = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable Nepomuk (deprecated).";
+      };
     };
   };
 
@@ -138,7 +150,6 @@ in
 
           pkgs.kde4.kde_wallpapers # contains kdm's default background
           pkgs.kde4.oxygen_icons
-          pkgs.virtuoso # to enable Nepomuk to find Virtuoso
 
           # Starts KDE's Polkit authentication agent.
           pkgs.kde4.polkit_kde_agent
@@ -149,20 +160,26 @@ in
           xorg.xmessage # so that startkde can show error messages
           xorg.xset # used by startkde, non-essential
           xorg.xauth # used by kdesu
-          pkgs.shared_desktop_ontologies # used by nepomuk
-          pkgs.strigi # used by nepomuk
+        ]
+      ++ optionals cfg.enablePIM
+        [ pkgs.kde4.kdepim_runtime
           pkgs.kde4.akonadi
           pkgs.mysql # used by akonadi
-          pkgs.kde4.kdepim_runtime
         ]
-      ++ lib.optional config.hardware.pulseaudio.enable pkgs.kde4.kmix  # Perhaps this should always be enabled
-      ++ lib.optional config.hardware.bluetooth.enable pkgs.kde4.bluedevil
-      ++ lib.optional config.networking.networkmanager.enable pkgs.kde4.plasma-nm
-      ++ [ nepomukConfig ] ++ phononBackendPackages;
+      ++ (if cfg.enableNepomuk then
+        [ pkgs.shared_desktop_ontologies # used by nepomuk
+          pkgs.strigi # used by nepomuk
+          pkgs.virtuoso # to enable Nepomuk to find Virtuoso
+        ] else
+        [ disableNepomuk ])
+      ++ optional config.hardware.pulseaudio.enable pkgs.kde4.kmix  # Perhaps this should always be enabled
+      ++ optional config.hardware.bluetooth.enable pkgs.kde4.bluedevil
+      ++ optional config.networking.networkmanager.enable pkgs.kde4.plasma-nm
+      ++ phononBackendPackages;
 
     environment.pathsToLink = [ "/share" ];
 
-    environment.profileRelativeEnvVars = mkIf (lib.elem "gstreamer" cfg.phononBackends) {
+    environment.profileRelativeEnvVars = mkIf (elem "gstreamer" cfg.phononBackends) {
       GST_PLUGIN_SYSTEM_PATH = [ "/lib/gstreamer-0.10" ];
     };
 
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 634d2a39576a..51d7d905d587 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -69,7 +69,7 @@ in
     services.xserver.updateDbusEnvironment = true;
 
     environment.systemPackages =
-      [ pkgs.gtk # To get GTK+'s themes.
+      [ pkgs.gtk2 # To get GTK+'s themes.
         pkgs.hicolor_icon_theme
         pkgs.tango-icon-theme
         pkgs.shared_mime_info
@@ -100,6 +100,7 @@ in
         pkgs.xfce.tumbler       # found via dbus
       ]
       ++ optional config.powerManagement.enable pkgs.xfce.xfce4_power_manager
+      ++ optional config.networking.networkmanager.enable pkgs.networkmanagerapplet
       ++ optionals (!cfg.noDesktop)
          [ pkgs.xfce.xfce4panel
            pkgs.xfce.xfdesktop
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 1c928ff22a1f..ce82af4ca68c 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -134,13 +134,8 @@ let
         (*) echo "$0: Desktop manager '$desktopManager' not found.";;
       esac
 
-      # FIXME: gdbus should not be in glib.dev!
-      ${optionalString (cfg.startDbusSession && cfg.updateDbusEnvironment) ''
-        ${pkgs.glib.dev}/bin/gdbus call --session \
-          --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus \
-          --method org.freedesktop.DBus.UpdateActivationEnvironment \
-          "{$(env | ${pkgs.gnused}/bin/sed "s/'/\\\\'/g; s/\([^=]*\)=\(.*\)/'\1':'\2'/" \
-                  | ${pkgs.coreutils}/bin/paste -sd,)}"
+      ${optionalString cfg.updateDbusEnvironment ''
+        ${lib.getBin pkgs.dbus}/bin/dbus-update-activation-environment --systemd --all
       ''}
 
       test -n "$waitPID" && wait "$waitPID"
@@ -306,7 +301,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/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
index d9f7f8f0dfc4..8b51c621e112 100644
--- a/nixos/modules/services/x11/display-managers/kdm.nix
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -54,19 +54,17 @@ let
       ''}
     '';
 
-  kdmrc = pkgs.stdenv.mkDerivation {
-    name = "kdmrc";
-    config = defaultConfig + cfg.extraConfig;
-    preferLocalBuild = true;
-    buildCommand =
-      ''
-        echo "$config" > $out
+  kdmrc = pkgs.runCommand "kdmrc"
+    { config = defaultConfig + cfg.extraConfig;
+      preferLocalBuild = true;
+    }
+    ''
+      echo "$config" > $out
 
-        # The default kdmrc would add "-nolisten tcp", and we already
-        # have that managed by nixos. Hence the grep.
-        cat ${kdebase_workspace}/share/config/kdm/kdmrc | grep -v nolisten >> $out
-      '';
-  };
+      # The default kdmrc would add "-nolisten tcp", and we already
+      # have that managed by nixos. Hence the grep.
+      cat ${kdebase_workspace}/share/config/kdm/kdmrc | grep -v nolisten >> $out
+    '';
 
 in
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
index 543dd628ce66..dfda90978b1e 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -16,11 +16,9 @@ let
   # The default greeter provided with this expression is the GTK greeter.
   # Again, we need a few things in the environment for the greeter to run with
   # fonts/icons.
-  wrappedGtkGreeter = stdenv.mkDerivation {
-    name = "lightdm-gtk-greeter";
-    buildInputs = [ pkgs.makeWrapper ];
-
-    buildCommand = ''
+  wrappedGtkGreeter = pkgs.runCommand "lightdm-gtk-greeter"
+    { buildInputs = [ pkgs.makeWrapper ]; }
+    ''
       # This wrapper ensures that we actually get themes
       makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
         $out/greeter \
@@ -40,7 +38,6 @@ let
       Type=Application
       EOF
     '';
-  };
 
   gtkGreeterConf = writeText "lightdm-gtk-greeter.conf"
     ''
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 47786f0a4321..33cd51f37c68 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -46,13 +46,15 @@ let
       [Seat:*]
       xserver-command = ${xserverWrapper}
       session-wrapper = ${dmcfg.session.script}
+      ${optionalString (elem defaultSessionName dmcfg.session.names) ''
+        user-session = ${defaultSessionName}
+      ''}
       ${optionalString cfg.greeter.enable ''
         greeter-session = ${cfg.greeter.name}
       ''}
       ${optionalString cfg.autoLogin.enable ''
         autologin-user = ${cfg.autoLogin.user}
         autologin-user-timeout = ${toString cfg.autoLogin.timeout}
-        autologin-session = ${defaultSessionName}
       ''}
       ${cfg.extraSeatDefaults}
     '';
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 16d1e89e8d96..4d2ddedca1ea 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -46,7 +46,7 @@ let
     HideUsers=${concatStringsSep "," dmcfg.hiddenUsers}
     HideShells=/run/current-system/sw/bin/nologin
 
-    [XDisplay]
+    [X11]
     MinimumVT=${toString xcfg.tty}
     ServerPath=${xserverWrapper}
     XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr
@@ -100,7 +100,7 @@ in
 
       theme = mkOption {
         type = types.str;
-        default = "maui";
+        default = "";
         description = ''
           Greeter theme to use.
         '';
diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix
index ce44c9f54a31..ca2ae1a47726 100644
--- a/nixos/modules/services/x11/display-managers/slim.nix
+++ b/nixos/modules/services/x11/display-managers/slim.nix
@@ -26,15 +26,13 @@ let
   # Unpack the SLiM theme, or use the default.
   slimThemesDir =
     let
-      unpackedTheme = pkgs.stdenv.mkDerivation {
-        name = "slim-theme";
-        buildCommand = ''
+      unpackedTheme = pkgs.runCommand "slim-theme" {}
+        ''
           mkdir -p $out
           cd $out
           unpackFile ${cfg.theme}
           ln -s * default
         '';
-      };
     in if cfg.theme == null then "${pkgs.slim}/share/slim/themes" else unpackedTheme;
 
 in
diff --git a/nixos/modules/services/x11/window-managers/awesome.nix b/nixos/modules/services/x11/window-managers/awesome.nix
index 455b3568499f..eb97449c6bd9 100644
--- a/nixos/modules/services/x11/window-managers/awesome.nix
+++ b/nixos/modules/services/x11/window-managers/awesome.nix
@@ -6,7 +6,7 @@ let
 
   cfg = config.services.xserver.windowManager.awesome;
   awesome = cfg.package;
-
+  inherit (pkgs.luaPackages) getLuaPath getLuaCPath;
 in
 
 {
@@ -46,10 +46,8 @@ in
       { name = "awesome";
         start =
           ''
-            ${concatMapStrings (pkg: ''
-              export LUA_CPATH=$LUA_CPATH''${LUA_CPATH:+;}${pkg}/lib/lua/${awesome.lua.luaversion}/?.so
-              export LUA_PATH=$LUA_PATH''${LUA_PATH:+;}${pkg}/lib/lua/${awesome.lua.luaversion}/?.lua
-            '') cfg.luaModules}
+            export LUA_CPATH="${lib.concatStringsSep ";" (map getLuaCPath cfg.luaModules)}"
+            export LUA_PATH="${lib.concatStringsSep ";" (map getLuaPath cfg.luaModules)}"
 
             ${awesome}/bin/awesome &
             waitPID=$!
@@ -59,5 +57,4 @@ in
     environment.systemPackages = [ awesome ];
 
   };
-
 }
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index b03f70385b1f..1bd578424ee4 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -71,15 +71,11 @@ let
     monitors = reverseList (foldl mkMonitor [] xrandrHeads);
   in concatMapStrings (getAttr "value") monitors;
 
-  configFile = pkgs.stdenv.mkDerivation {
-    name = "xserver.conf";
-
-    xfs = optionalString (cfg.useXFS != false)
-      ''FontPath "${toString cfg.useXFS}"'';
-
-    inherit (cfg) config;
-
-    buildCommand =
+  configFile = pkgs.runCommand "xserver.conf"
+    { xfs = optionalString (cfg.useXFS != false)
+        ''FontPath "${toString cfg.useXFS}"'';
+      inherit (cfg) config;
+    }
       ''
         echo 'Section "Files"' >> $out
         echo $xfs >> $out
@@ -102,7 +98,6 @@ let
 
         echo "$config" >> $out
       ''; # */
-  };
 
 in
 
@@ -654,6 +649,8 @@ in
         ${xrandrMonitorSections}
       '';
 
+    fonts.enableDefaultFonts = mkDefault true;
+
   };
 
 }
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index 4489e34831da..4a16a6762935 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -12,11 +12,13 @@ let
     '';
   });
 
-  path = map getBin
-    [ pkgs.coreutils pkgs.gnugrep pkgs.findutils
-      pkgs.glibc # needed for getent
-      pkgs.shadow
-      pkgs.nettools # needed for hostname
+  path = with pkgs; map getBin
+    [ coreutils
+      gnugrep
+      findutils
+      glibc # needed for getent
+      shadow
+      nettools # needed for hostname
     ];
 
 in
@@ -137,8 +139,13 @@ in
 
         mkdir -m 1777 -p /var/tmp
 
-        # Empty, read-only home directory of many system accounts.
-        mkdir -m 0555 -p /var/empty
+        # Empty, immutable home directory of many system accounts.
+        mkdir -p /var/empty
+        # Make sure it's really empty
+        ${pkgs.e2fsprogs}/bin/chattr -f -i /var/empty || true
+        find /var/empty -mindepth 1 -delete
+        chmod 0555 /var/empty
+        ${pkgs.e2fsprogs}/bin/chattr -f +i /var/empty || true
       '';
 
     system.activationScripts.usrbinenv = if config.environment.usrbinenv != null
@@ -152,11 +159,22 @@ in
         rmdir --ignore-fail-on-non-empty /usr/bin /usr
       '';
 
-    system.activationScripts.tmpfs =
+    system.activationScripts.specialfs =
       ''
-        ${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"
+
+          if ${pkgs.utillinux}/bin/mountpoint -q "$mountPoint"; then
+            local options="remount,$options"
+          else
+            mkdir -m 0755 -p "$mountPoint"
+          fi
+          ${pkgs.utillinux}/bin/mount -t "$fsType" -o "$options" "$device" "$mountPoint"
+        }
+        source ${config.system.build.earlyMountScript}
       '';
 
   };
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index bb97d0c53a6b..8747c1e3d4ac 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -213,33 +213,30 @@ while (my ($unit, $state) = each %{$activePrev}) {
                 elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") ) {
                     $unitsToSkip{$unit} = 1;
                 } else {
-                    # If this unit is socket-activated, then stop the
-                    # socket unit(s) as well, and restart the
-                    # socket(s) instead of the service.
-                    my $socketActivated = 0;
-                    if ($unit =~ /\.service$/) {
-                        my @sockets = split / /, ($unitInfo->{Sockets} // "");
-                        if (scalar @sockets == 0) {
-                            @sockets = ("$baseName.socket");
-                        }
-                        foreach my $socket (@sockets) {
-                            if (defined $activePrev->{$socket}) {
-                                $unitsToStop{$unit} = 1;
-                                $unitsToStart{$unit} = 1;
-                                recordUnit($startListFile, $socket);
-                                $socketActivated = 1;
-                            }
-                        }
-                    }
-
                     if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {
-
                         # This unit should be restarted instead of
                         # stopped and started.
                         $unitsToRestart{$unit} = 1;
                         recordUnit($restartListFile, $unit);
-
                     } else {
+                        # If this unit is socket-activated, then stop the
+                        # socket unit(s) as well, and restart the
+                        # socket(s) instead of the service.
+                        my $socketActivated = 0;
+                        if ($unit =~ /\.service$/) {
+                            my @sockets = split / /, ($unitInfo->{Sockets} // "");
+                            if (scalar @sockets == 0) {
+                                @sockets = ("$baseName.socket");
+                            }
+                            foreach my $socket (@sockets) {
+                                if (defined $activePrev->{$socket}) {
+                                    $unitsToStop{$socket} = 1;
+                                    $unitsToStart{$socket} = 1;
+                                    recordUnit($startListFile, $socket);
+                                    $socketActivated = 1;
+                                }
+                            }
+                        }
 
                         # If the unit is not socket-activated, record
                         # that this unit needs to be started below.
@@ -251,7 +248,6 @@ while (my ($unit, $state) = each %{$activePrev}) {
                         }
 
                         $unitsToStop{$unit} = 1;
-
                     }
                 }
             }
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
index bc899984c57d..a8c7d4b3ee5e 100644
--- a/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -85,10 +85,14 @@ in
   };
 
   config = mkIf (config.boot.initrd.network.enable && cfg.enable) {
-    assertions = [ {
-      assertion = cfg.hostRSAKey != null || cfg.hostDSSKey != null || cfg.hostECDSAKey != null;
-      message = "You should specify at least one host key for initrd SSH";
-    } ];
+    assertions = [
+      { assertion = cfg.hostRSAKey != null || cfg.hostDSSKey != null || cfg.hostECDSAKey != null;
+        message = "You should specify at least one host key for initrd SSH";
+      }
+      { assertion = cfg.authorizedKeys != [];
+        message = "You should specify at least one authorized key for initrd SSH";
+      }
+    ];
 
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index 0f342f44fe76..ba15d0318b17 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -203,6 +203,12 @@ in
         # Misc. stuff.
         "pcips2" "atkbd"
 
+        # Temporary fix for https://github.com/NixOS/nixpkgs/issues/18451
+        # Remove as soon as upstream gets fixed - marking it:
+        # TODO
+        # FIXME
+        "i8042"
+
         # To wait for SCSI devices to appear.
         "scsi_wait_scan"
 
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 0640ec306e18..cae045f78c37 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -55,7 +55,7 @@ let
       inherit (cfg)
         version extraConfig extraPerEntryConfig extraEntries
         extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels
-        default fsIdentifier efiSupport gfxmodeEfi gfxmodeBios;
+        default fsIdentifier efiSupport efiInstallAsRemovable gfxmodeEfi gfxmodeBios;
       path = (makeBinPath ([
         pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfs-progs
         pkgs.utillinux ] ++ (if cfg.efiSupport && (cfg.version == 2) then [pkgs.efibootmgr ] else [])
@@ -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,12 +351,50 @@ 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.
         '';
       };
 
+      efiInstallAsRemovable = mkOption {
+        default = false;
+        example = true;
+        type = types.bool;
+        description = ''
+          Whether to invoke <literal>grub-install</literal> with
+          <literal>--removable</literal>.</para>
+
+          <para>Unless you turn this on, GRUB will install itself somewhere in
+          <literal>boot.loader.efi.efiSysMountPoint</literal> (exactly where
+          depends on other config variables). If you've set
+          <literal>boot.loader.efi.canTouchEfiVariables</literal> *AND* you
+          are currently booted in UEFI mode, then GRUB will use
+          <literal>efibootmgr</literal> to modify the boot order in the
+          EFI variables of your firmware to include this location. If you are
+          *not* booted in UEFI mode at the time GRUB is being installed, the
+          NVRAM will not be modified, and your system will not find GRUB at
+          boot time. However, GRUB will still return success so you may miss
+          the warning that gets printed ("<literal>efibootmgr: EFI variables
+          are not supported on this system.</literal>").</para>
+
+          <para>If you turn this feature on, GRUB will install itself in a
+          special location within <literal>efiSysMountPoint</literal> (namely
+          <literal>EFI/boot/boot$arch.efi</literal>) which the firmwares
+          are hardcoded to try first, regardless of NVRAM EFI variables.</para>
+
+          <para>To summarize, turn this on if:
+          <itemizedlist>
+            <listitem><para>You are installing NixOS and want it to boot in UEFI mode,
+            but you are currently booted in legacy mode</para></listitem>
+            <listitem><para>You want to make a drive that will boot regardless of
+            the NVRAM state of the computer (like a USB "removable" drive)</para></listitem>
+            <listitem><para>You simply dislike the idea of depending on NVRAM
+            state to make your drive bootable</para></listitem>
+          </itemizedlist>
+        '';
+      };
+
       enableCryptodisk = mkOption {
         default = false;
         type = types.bool;
@@ -425,13 +463,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;
@@ -458,7 +503,7 @@ in
             + "'boot.loader.grub.mirroredBoots' to make the system bootable.";
         }
         {
-          assertion = all (c: c < 2) (mapAttrsToList (_: c: c) bootDeviceCounters);
+          assertion = cfg.efiSupport || all (c: c < 2) (mapAttrsToList (_: c: c) bootDeviceCounters);
           message = "You cannot have duplicated devices in mirroredBoots";
         }
         {
@@ -477,6 +522,14 @@ in
           assertion = !cfg.trustedBoot.enable || cfg.trustedBoot.systemHasTPM == "YES_TPM_is_activated";
           message = "Trusted GRUB can break the system! Confirm that the system has an activated TPM by setting 'systemHasTPM'.";
         }
+        {
+          assertion = cfg.efiInstallAsRemovable -> cfg.efiSupport;
+          message = "If you wish to to use boot.loader.grub.efiInstallAsRemovable, then turn on boot.loader.grub.efiSupport";
+        }
+        {
+          assertion = cfg.efiInstallAsRemovable -> !config.boot.loader.efi.canTouchEfiVariables;
+          message = "If you wish to to use boot.loader.grub.efiInstallAsRemovable, then turn off boot.loader.efi.canTouchEfiVariables";
+        }
       ] ++ flip concatMap cfg.mirroredBoots (args: [
         {
           assertion = args.devices != [ ];
@@ -500,7 +553,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..b93395300b72 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"); }
@@ -58,6 +60,7 @@ my $grubTargetEfi = get("grubTargetEfi");
 my $bootPath = get("bootPath");
 my $storePath = get("storePath");
 my $canTouchEfiVariables = get("canTouchEfiVariables");
+my $efiInstallAsRemovable = get("efiInstallAsRemovable");
 my $efiSysMountPoint = get("efiSysMountPoint");
 my $gfxmodeEfi = get("gfxmodeEfi");
 my $gfxmodeBios = get("gfxmodeBios");
@@ -97,6 +100,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 +141,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 +177,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 +190,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 +198,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";
                     }
@@ -537,13 +545,15 @@ if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) {
 # install EFI GRUB
 if (($requireNewInstall != 0) && ($efiTarget eq "only" || $efiTarget eq "both")) {
     print STDERR "installing the GRUB $grubVersion EFI boot loader into $efiSysMountPoint...\n";
+    my @command = ("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--boot-directory=$bootPath", "--efi-directory=$efiSysMountPoint");
     if ($canTouchEfiVariables eq "true") {
-        system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--boot-directory=$bootPath", "--efi-directory=$efiSysMountPoint", "--bootloader-id=$bootloaderId") == 0
-                or die "$0: installation of GRUB EFI into $efiSysMountPoint failed\n";
+        push @command, "--bootloader-id=$bootloaderId";
     } else {
-        system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--boot-directory=$bootPath", "--efi-directory=$efiSysMountPoint", "--no-nvram") == 0
-                or die "$0: installation of GRUB EFI into $efiSysMountPoint failed\n";
+        push @command, "--no-nvram";
+        push @command, "--removable" if $efiInstallAsRemovable eq "true";
     }
+
+    (system @command) == 0 or die "$0: installation of GRUB EFI into $efiSysMountPoint failed\n";
 }
 
 
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index ab7485500261..38b4b437369d 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -677,8 +677,7 @@ in
     };
 
     systemd.services.systemd-networkd-wait-online = {
-      before = [ "network-online.target" "ip-up.target" ];
-      wantedBy = [ "network-online.target" "ip-up.target" ];
+      wantedBy = [ "network-online.target" ];
     };
 
     systemd.services."systemd-network-wait-online@" = {
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..8d02cd81e0e1 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,25 +134,9 @@ 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 ];
-    buildCommand = ''
+  udevRules = pkgs.runCommand "udev-rules"
+    { allowedReferences = [ extraUtils ]; }
+    ''
       mkdir -p $out
 
       echo 'ENV{LD_LIBRARY_PATH}="${extraUtils}/lib"' > $out/00-env.rules
@@ -185,7 +175,6 @@ let
       substituteInPlace $out/60-persistent-storage.rules \
         --replace ID_CDROM_MEDIA_TRACK_COUNT_DATA ID_CDROM_MEDIA
     ''; # */
-  };
 
 
   # The init script of boot stage 1 (loading kernel modules for
@@ -199,15 +188,18 @@ 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;
 
     resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}")
-                    (filter (sd: (sd ? label || hasPrefix "/dev/" sd.device) && !sd.randomEncryption 
-                    # Don't include zram devices
-                    && !(hasPrefix "/dev/zram" sd.device)) config.swapDevices);
+                    (filter (sd: hasPrefix "/dev/" sd.device && !sd.randomEncryption
+                             # Don't include zram devices
+                             && !(hasPrefix "/dev/zram" sd.device)
+                            ) config.swapDevices);
 
     fsInfo =
       let f = fs: [ fs.mountPoint (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}") fs.fsType (builtins.concatStringsSep "," fs.options) ];
@@ -236,16 +228,12 @@ let
         { object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf;
           symlink = "/etc/mdadm.conf";
         }
-        { object = pkgs.stdenv.mkDerivation {
-            name = "initrd-kmod-blacklist-ubuntu";
-            builder = pkgs.writeText "builder.sh" ''
-              source $stdenv/setup
+        { object = pkgs.runCommand "initrd-kmod-blacklist-ubuntu"
+            { src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; }
+            ''
               target=$out
-
               ${pkgs.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out
             '';
-            src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf";
-          };
           symlink = "/etc/modprobe.d/ubuntu.conf";
         }
         { object = pkgs.kmod-debian-aliases;
@@ -405,9 +393,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..f827e530f877 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -29,7 +29,7 @@ setPath "@path@"
 # Normally, stage 1 mounts the root filesystem read/writable.
 # However, in some environments, stage 2 is executed directly, and the
 # root is read-only.  So make it writable here.
-if [ "$container" != systemd-nspawn ]; then
+if [ -z "$container" ]; then
     mount -n -o remount,rw none /
 fi
 
@@ -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,24 +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
-    rm -rf /run/keys
-    mkdir /run/keys
-    mount -t ramfs ramfs /run/keys
-    chown 0:96 /run/keys
-    chmod 0750 /run/keys
-fi
-
 mkdir -m 0755 -p /run/lock
 
 
@@ -150,13 +131,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/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index df72be1b4be5..2ac041f14128 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -14,6 +14,7 @@ let
   upstreamSystemUnits =
     [ # Targets.
       "basic.target"
+      "busnames.target"
       "sysinit.target"
       "sockets.target"
       "graphical.target"
@@ -140,6 +141,7 @@ let
       "user.slice"
       "machine.slice"
       "systemd-machined.service"
+      "systemd-nspawn@.service"
 
       # Temporary file creation / cleanup.
       "systemd-tmpfiles-clean.service"
@@ -569,6 +571,16 @@ in
       '';
     };
 
+    systemd.user.extraConfig = mkOption {
+      default = "";
+      type = types.lines;
+      example = "DefaultCPUAccounting=yes";
+      description = ''
+        Extra config options for systemd user instances. See man systemd-user.conf for
+        available options.
+      '';
+    };
+
     systemd.tmpfiles.rules = mkOption {
       type = types.listOf types.str;
       default = [];
@@ -663,6 +675,11 @@ in
         ${config.systemd.extraConfig}
       '';
 
+      "systemd/user.conf".text = ''
+        [Manager]
+        ${config.systemd.user.extraConfig}
+      '';
+
       "systemd/journald.conf".text = ''
         [Journal]
         RateLimitInterval=${config.services.journald.rateLimitInterval}
@@ -725,18 +742,6 @@ in
         unitConfig.X-StopOnReconfiguration = true;
       };
 
-    systemd.targets.network-online.after = [ "ip-up.target" ];
-
-    systemd.targets.network-pre = {
-      wantedBy = [ "network.target" ];
-      before = [ "network.target" ];
-    };
-
-    systemd.targets.remote-fs-pre = {
-      wantedBy = [ "remote-fs.target" ];
-      before = [ "remote-fs.target" ];
-    };
-
     systemd.units =
       mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
       // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
@@ -803,6 +808,8 @@ in
     systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
     systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ];
     systemd.services.systemd-logind.stopIfChanged = false;
+    systemd.services.systemd-journald.restartTriggers = [ config.environment.etc."systemd/journald.conf".source ];
+    systemd.services.systemd-journald.stopIfChanged = false;
     systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
     systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
     systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ];
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..49ba66ad50af 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" "ramfs" "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,23 @@ 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" ]; };
+      "/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}" ]; };
+
+      # To hold secrets that shouldn't be written to disk (generally used for NixOps, harmless elsewhere)
+      "/run/keys" = { fsType = "ramfs"; options = [ "nosuid" "nodev" "mode=750" "gid=${toString config.ids.gids.keys}" ]; };
+    } // optionalAttrs (!config.boot.isContainer) {
+      # systemd-nspawn populates /sys by itself, and remounting it causes all
+      # kinds of weird issues (most noticeably, waiting for host disk device
+      # nodes).
+      "/sys" = { fsType = "sysfs"; options = [ "nosuid" "noexec" "nodev" ]; };
+    };
+
   };
 
 }
diff --git a/nixos/modules/tasks/filesystems/nfs.nix b/nixos/modules/tasks/filesystems/nfs.nix
index e454eca3a0e5..e9a7ccc721a9 100644
--- a/nixos/modules/tasks/filesystems/nfs.nix
+++ b/nixos/modules/tasks/filesystems/nfs.nix
@@ -38,15 +38,17 @@ in
         default = null;
         example = 4000;
         description = ''
-          Use fixed port for rpc.statd, useful if NFS server is behind firewall.
+          Use a fixed port for <command>rpc.statd</command>. This is
+          useful if the NFS server is behind a firewall.
         '';
       };
       lockdPort = mkOption {
         default = null;
         example = 4001;
         description = ''
-          Use fixed port for NFS lock manager kernel module (lockd/nlockmgr),
-          useful if NFS server is behind firewall.
+          Use a fixed port for the NFS lock manager kernel module
+          (<literal>lockd/nlockmgr</literal>).  This is useful if the
+          NFS server is behind a firewall.
         '';
       };
     };
@@ -68,13 +70,16 @@ in
 
     boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];
 
+    # FIXME: should use upstream units from nfs-utils.
+
     systemd.services.statd =
       { description = "NFSv3 Network Status Monitor";
 
         path = [ pkgs.nfs-utils pkgs.sysvtools pkgs.utillinux ];
 
-        wantedBy = [ "remote-fs-pre.target" ];
+        wants = [ "remote-fs-pre.target" ];
         before = [ "remote-fs-pre.target" ];
+        wantedBy = [ "remote-fs.target" ];
         requires = [ "basic.target" "rpcbind.service" ];
         after = [ "basic.target" "rpcbind.service" ];
 
@@ -100,8 +105,9 @@ in
 
         path = [ pkgs.sysvtools pkgs.utillinux ];
 
-        wantedBy = [ "remote-fs-pre.target" ];
+        wants = [ "remote-fs-pre.target" ];
         before = [ "remote-fs-pre.target" ];
+        wantedBy = [ "remote-fs.target" ];
         requires = [ "rpcbind.service" ];
         after = [ "rpcbind.service" ];
 
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/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
index c960e401f9b1..d1b62e0fd4e4 100644
--- a/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -142,7 +142,6 @@ in
                     # (Flushing this interface may have removed it.)
                     ${config.systemd.package}/bin/systemctl try-restart --no-block network-setup.service
                   fi
-                  ${config.systemd.package}/bin/systemctl start ip-up.target
                 '';
             preStop = flip concatMapStrings (ips) (ip:
                 let
diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix
index 301ee43fd0e5..974041d7e1a5 100644
--- a/nixos/modules/tasks/network-interfaces-systemd.nix
+++ b/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -43,7 +43,7 @@ in
       message = "networking.bridges.${n}.rstp is not supported by networkd.";
     });
 
-    systemd.services.dhcpcd.enable = mkDefault false;
+    networking.dhcpcd.enable = mkDefault false;
 
     systemd.services.network-local-commands = {
       after = [ "systemd-networkd.service" ];
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index c52bd904caec..9042418b7234 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -231,7 +231,7 @@ let
         type = types.bool;
         description = ''
           Whether this interface is virtual and should be created by tunctl.
-          This is mainly useful for creating bridges between a host a virtual
+          This is mainly useful for creating bridges between a host and a virtual
           network such as VPN or a virtual machine.
         '';
       };
@@ -391,7 +391,7 @@ in
     };
 
     networking.localCommands = mkOption {
-      type = types.str;
+      type = types.lines;
       default = "";
       example = "text=anything; echo You can put $text here.";
       description = ''
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/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix
index a89cd454dc73..6817eb837a01 100644
--- a/nixos/modules/virtualisation/azure-agent.nix
+++ b/nixos/modules/virtualisation/azure-agent.nix
@@ -178,7 +178,8 @@ in
 
     systemd.services.waagent = {
       wantedBy = [ "multi-user.target" ];
-      after = [ "ip-up.target" "sshd.service" ];
+      after = [ "network-online.target" "sshd.service" ];
+      wants = [ "network-online.target" ];
 
       path = [ pkgs.e2fsprogs ];
       description = "Windows Azure Agent Service";
diff --git a/nixos/modules/virtualisation/azure-bootstrap-blobs.nix b/nixos/modules/virtualisation/azure-bootstrap-blobs.nix
new file mode 100644
index 000000000000..281be9a12318
--- /dev/null
+++ b/nixos/modules/virtualisation/azure-bootstrap-blobs.nix
@@ -0,0 +1,3 @@
+{
+    "16.03" = "https://nixos.blob.core.windows.net/images/nixos-image-16.03.847.8688c17-x86_64-linux.vhd";
+}
diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix
index 760a7100c6e0..e2905913b6c5 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
@@ -116,8 +116,8 @@ in
 
       wantedBy = [ "multi-user.target" "sshd.service" ];
       before = [ "sshd.service" ];
-      wants = [ "ip-up.target" ];
-      after = [ "ip-up.target" ];
+      wants = [ "network-online.target" ];
+      after = [ "network-online.target" ];
 
       path = [ pkgs.wget pkgs.iproute ];
 
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index d83841452f95..1410a1481704 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -12,21 +12,21 @@ let
         ''
         echo "Bringing ${name} up"
         ip link set dev ${name} up
-        ${optionalString (cfg . "localAddress" or null != null) ''
+        ${optionalString (cfg.localAddress != null) ''
           echo "Setting ip for ${name}"
-          ip addr add ${cfg . "localAddress"} dev ${name}
+          ip addr add ${cfg.localAddress} dev ${name}
         ''}
-        ${optionalString (cfg . "localAddress6" or null != null) ''
+        ${optionalString (cfg.localAddress6 != null) ''
           echo "Setting ip6 for ${name}"
-          ip -6 addr add ${cfg . "localAddress6"} dev ${name}
+          ip -6 addr add ${cfg.localAddress6} dev ${name}
         ''}
-        ${optionalString (cfg . "hostAddress" or null != null) ''
+        ${optionalString (cfg.hostAddress != null) ''
           echo "Setting route to host for ${name}"
-          ip route add ${cfg . "hostAddress"} dev ${name}
+          ip route add ${cfg.hostAddress} dev ${name}
         ''}
-        ${optionalString (cfg . "hostAddress6" or null != null) ''
+        ${optionalString (cfg.hostAddress6 != null) ''
           echo "Setting route6 to host for ${name}"
-          ip -6 route add ${cfg . "hostAddress6"} dev ${name}
+          ip -6 route add ${cfg.hostAddress6} dev ${name}
         ''}
         ''
         );
@@ -56,9 +56,7 @@ let
             ip -6 route add default via $HOST_ADDRESS6
           fi
 
-          ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg . "extraVeths" or {})}
-          ip a
-          ip r
+          ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
         fi
 
         # Start the regular stage 1 script.
@@ -67,7 +65,8 @@ let
     );
 
   nspawnExtraVethArgs = (name: cfg: "--network-veth-extra=${name}");
-  startScript = (cfg:
+
+  startScript = cfg:
     ''
       mkdir -p -m 0755 "$root/etc" "$root/var/lib"
       mkdir -p -m 0700 "$root/var/lib/private" "$root/root" /run/containers
@@ -92,11 +91,7 @@ let
         fi
       fi
 
-      ${if cfg . "extraVeths" or null != null then
-        ''extraFlags+=" ${concatStringsSep " " (mapAttrsToList nspawnExtraVethArgs cfg . "extraVeths" or {})}"''
-        else
-          ''# No extra veth pairs to create''
-      }
+      extraFlags+=" ${concatStringsSep " " (mapAttrsToList nspawnExtraVethArgs cfg.extraVeths)}"
 
       for iface in $INTERFACES; do
         extraFlags+=" --network-interface=$iface"
@@ -134,11 +129,13 @@ let
         --setenv HOST_ADDRESS6="$HOST_ADDRESS6" \
         --setenv LOCAL_ADDRESS6="$LOCAL_ADDRESS6" \
         --setenv PATH="$PATH" \
+        ${if cfg.additionalCapabilities != null then
+          ''--capability="${concatStringsSep " " cfg.additionalCapabilities}"'' else ""
+        } \
         ${containerInit cfg} "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/init"
-    ''
-    );
+    '';
 
-  preStartScript = (cfg:
+  preStartScript = cfg:
     ''
       # Clean up existing machined registration and interfaces.
       machinectl terminate "$INSTANCE" 2> /dev/null || true
@@ -151,45 +148,43 @@ let
       ${concatStringsSep "\n" (
         mapAttrsToList (name: cfg:
           ''ip link del dev ${name} 2> /dev/null || true ''
-        ) cfg . "extraVeths" or {}
+        ) cfg.extraVeths
       )}
-   ''
-    );
+   '';
+
   postStartScript = (cfg:
     let
-      ipcall = (cfg: ipcmd: variable: attribute:
-        if cfg . attribute or null == null then
+      ipcall = cfg: ipcmd: variable: attribute:
+        if cfg.${attribute} == null then
           ''
             if [ -n "${variable}" ]; then
               ${ipcmd} add ${variable} dev $ifaceHost
             fi
           ''
         else
-          ''${ipcmd} add ${cfg . attribute} dev $ifaceHost''
-        );
-      renderExtraVeth = (name: cfg:
-        if cfg . "hostBridge" or null != null then
+          ''${ipcmd} add ${cfg.${attribute}} dev $ifaceHost'';
+      renderExtraVeth = name: cfg:
+        if cfg.hostBridge != null then
           ''
             # Add ${name} to bridge ${cfg.hostBridge}
             ip link set dev ${name} master ${cfg.hostBridge} up
           ''
         else
           ''
-          # Set IPs and routes for ${name}
-          ${optionalString (cfg . "hostAddress" or null != null) ''
-            ip addr add ${cfg . "hostAddress"} dev ${name}
-          ''}
-          ${optionalString (cfg . "hostAddress6" or null != null) ''
-            ip -6 addr add ${cfg . "hostAddress6"} dev ${name}
-          ''}
-          ${optionalString (cfg . "localAddress" or null != null) ''
-            ip route add ${cfg . "localAddress"} dev ${name}
-          ''}
-          ${optionalString (cfg . "localAddress6" or null != null) ''
-            ip -6 route add ${cfg . "localAddress6"} dev ${name}
-          ''}
-          ''
-        );
+            # Set IPs and routes for ${name}
+            ${optionalString (cfg.hostAddress != null) ''
+              ip addr add ${cfg.hostAddress} dev ${name}
+            ''}
+            ${optionalString (cfg.hostAddress6 != null) ''
+              ip -6 addr add ${cfg.hostAddress6} dev ${name}
+            ''}
+            ${optionalString (cfg.localAddress != null) ''
+              ip route add ${cfg.localAddress} dev ${name}
+            ''}
+            ${optionalString (cfg.localAddress6 != null) ''
+              ip -6 route add ${cfg.localAddress6} dev ${name}
+            ''}
+          '';
     in
       ''
         if [ "$PRIVATE_NETWORK" = 1 ]; then
@@ -202,7 +197,7 @@ let
             ${ipcall cfg "ip route" "$LOCAL_ADDRESS" "localAddress"}
             ${ipcall cfg "ip -6 route" "$LOCAL_ADDRESS6" "localAddress6"}
           fi
-          ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg . "extraVeths" or {})}
+          ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
         fi
 
         # Get the leader PID so that we can signal it in
@@ -213,6 +208,41 @@ let
       ''
   );
 
+  serviceDirectives = cfg: {
+    ExecReload = pkgs.writeScript "reload-container"
+      ''
+        #! ${pkgs.stdenv.shell} -e
+        ${pkgs.nixos-container}/bin/nixos-container run "$INSTANCE" -- \
+          bash --login -c "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/bin/switch-to-configuration test"
+      '';
+
+    SyslogIdentifier = "container %i";
+
+    EnvironmentFile = "-/etc/containers/%i.conf";
+
+    Type = "notify";
+
+    # Note that on reboot, systemd-nspawn returns 133, so this
+    # unit will be restarted. On poweroff, it returns 0, so the
+    # unit won't be restarted.
+    RestartForceExitStatus = "133";
+    SuccessExitStatus = "133";
+
+    Restart = "on-failure";
+
+    # Hack: we don't want to kill systemd-nspawn, since we call
+    # "machinectl poweroff" in preStop to shut down the
+    # container cleanly. But systemd requires sending a signal
+    # (at least if we want remaining processes to be killed
+    # after the timeout). So send an ignored signal.
+    KillMode = "mixed";
+    KillSignal = "WINCH";
+
+    DevicePolicy = "closed";
+    DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices;
+  };
+
+
   system = config.nixpkgs.system;
 
   bindMountOpts = { name, config, ... }: {
@@ -243,6 +273,27 @@ let
 
   };
 
+  allowedDeviceOpts = { name, config, ... }: {
+    options = {
+      node = mkOption {
+        example = "/dev/net/tun";
+        type = types.str;
+        description = "Path to device node";
+      };
+      modifier = mkOption {
+        example = "rw";
+        type = types.str;
+        description = ''
+          Device node access modifier. Takes a combination
+          <literal>r</literal> (read), <literal>w</literal> (write), and
+          <literal>m</literal> (mknod). See the
+          <literal>systemd.resource-control(5)</literal> man page for more
+          information.'';
+      };
+    };
+  };
+
+
   mkBindFlag = d:
                let flagPrefix = if d.isReadOnly then " --bind-ro=" else " --bind=";
                    mountstr = if d.hostPath != null then "${d.hostPath}:${d.mountPoint}" else "${d.mountPoint}";
@@ -307,6 +358,17 @@ let
 
   };
 
+  dummyConfig =
+    {
+      extraVeths = {};
+      additionalCapabilities = [];
+      allowedDevices = [];
+      hostAddress = null;
+      hostAddress6 = null;
+      localAddress = null;
+      localAddress6 = null;
+    };
+
 in
 
 {
@@ -340,6 +402,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 {
@@ -353,6 +429,26 @@ in
               '';
             };
 
+            additionalCapabilities = mkOption {
+              type = types.listOf types.str;
+              default = [];
+              example = [ "CAP_NET_ADMIN" "CAP_MKNOD" ];
+              description = ''
+                Grant additional capabilities to the container.  See the
+                capabilities(7) and systemd-nspawn(1) man pages for more
+                information.
+              '';
+            };
+            enableTun = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Allows the container to create and setup tunnel interfaces
+                by granting the <literal>NET_ADMIN</literal> capability and
+                enabling access to <literal>/dev/net/tun</literal>.
+              '';
+            };
+
             privateNetwork = mkOption {
               type = types.bool;
               default = false;
@@ -407,21 +503,22 @@ in
                 '';
             };
 
+            allowedDevices = mkOption {
+              type = types.listOf types.optionSet;
+              options = [ allowedDeviceOpts ];
+              default = [];
+              example = [ { node = "/dev/net/tun"; modifier = "rw"; } ];
+              description = ''
+                A list of device nodes to which the containers has access to.
+              '';
+            };
+
           } // 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;
               })
             ];
         }));
@@ -446,7 +543,7 @@ in
         containers.  Each container appears as a service
         <literal>container-<replaceable>name</replaceable></literal>
         on the host system, allowing it to be started and stopped via
-        <command>systemctl</command> .
+        <command>systemctl</command>.
       '';
     };
 
@@ -465,11 +562,11 @@ in
       environment.INSTANCE = "%i";
       environment.root = "/var/lib/containers/%i";
 
-      preStart = preStartScript {};
+      preStart = preStartScript dummyConfig;
 
-      script = startScript {};
+      script = startScript dummyConfig;
 
-      postStart = postStartScript {};
+      postStart = postStartScript dummyConfig;
 
       preStop =
         ''
@@ -482,59 +579,39 @@ in
 
       restartIfChanged = false;
 
-      serviceConfig = {
-        ExecReload = pkgs.writeScript "reload-container"
-          ''
-            #! ${pkgs.stdenv.shell} -e
-            ${pkgs.nixos-container}/bin/nixos-container run "$INSTANCE" -- \
-              bash --login -c "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/bin/switch-to-configuration test"
-          '';
-
-        SyslogIdentifier = "container %i";
-
-        EnvironmentFile = "-/etc/containers/%i.conf";
-
-        Type = "notify";
-
-        # Note that on reboot, systemd-nspawn returns 133, so this
-        # unit will be restarted. On poweroff, it returns 0, so the
-        # unit won't be restarted.
-        RestartForceExitStatus = "133";
-        SuccessExitStatus = "133";
-
-        Restart = "on-failure";
-
-        # Hack: we don't want to kill systemd-nspawn, since we call
-        # "machinectl poweroff" in preStop to shut down the
-        # container cleanly. But systemd requires sending a signal
-        # (at least if we want remaining processes to be killed
-        # after the timeout). So send an ignored signal.
-        KillMode = "mixed";
-        KillSignal = "WINCH";
-
-        DevicePolicy = "closed";
-      };
+      serviceConfig = serviceDirectives dummyConfig;
     };
   in {
     systemd.services = listToAttrs (filter (x: x.value != null) (
       # The generic container template used by imperative containers
       [{ name = "container@"; value = unit; }]
       # declarative containers
-      ++ (mapAttrsToList (name: cfg: nameValuePair "container@${name}" (
-        unit // {
-          preStart = preStartScript cfg;
-          script = startScript cfg;
-          postStart = postStartScript cfg;
-        } // (
-        if cfg.autoStart then
-          {
-            wantedBy = [ "multi-user.target" ];
-            wants = [ "network.target" ];
-            after = [ "network.target" ];
-            restartTriggers = [ cfg.path ];
-            reloadIfChanged = true;
-          }
-        else {})
+      ++ (mapAttrsToList (name: cfg: nameValuePair "container@${name}" (let
+          config = cfg // (
+          if cfg.enableTun then
+            {
+              allowedDevices = cfg.allowedDevices
+                ++ [ { node = "/dev/net/tun"; modifier = "rw"; } ];
+              additionalCapabilities = cfg.additionalCapabilities
+                ++ [ "CAP_NET_ADMIN" ];
+            }
+          else {});
+        in
+          unit // {
+            preStart = preStartScript config;
+            script = startScript config;
+            postStart = postStartScript config;
+            serviceConfig = serviceDirectives config;
+          } // (
+          if config.autoStart then
+            {
+              wantedBy = [ "multi-user.target" ];
+              wants = [ "network.target" ];
+              after = [ "network.target" ];
+              restartTriggers = [ config.path ];
+              reloadIfChanged = true;
+            }
+          else {})
       )) config.containers)
     ));
 
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index ebc2be087a5b..92fe98f3f9c2 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -40,13 +40,25 @@ in
       };
     storageDriver =
       mkOption {
-        type = types.enum ["aufs" "btrfs" "devicemapper" "overlay" "zfs"];
-        default = "devicemapper";
+        type = types.nullOr (types.enum ["aufs" "btrfs" "devicemapper" "overlay" "overlay2" "zfs"]);
+        default = null;
         description =
           ''
-            This option determines which Docker storage driver to use.
+            This option determines which Docker storage driver to use. By default
+            it let's docker automatically choose preferred storage driver.
           '';
       };
+
+    logDriver =
+      mkOption {
+        type = types.enum ["none" "json-file" "syslog" "journald" "gelf" "fluentd" "awslogs" "splunk" "etwlogs" "gcplogs"];
+        default = "journald";
+        description =
+          ''
+            This option determines which Docker log driver to use.
+          '';
+      };
+
     extraOptions =
       mkOption {
         type = types.separatedString " ";
@@ -88,7 +100,12 @@ in
         after = [ "network.target" ] ++ (optional cfg.socketActivation "docker.socket") ;
         requires = optional cfg.socketActivation "docker.socket";
         serviceConfig = {
-          ExecStart = "${pkgs.docker}/bin/docker daemon --group=docker --storage-driver=${cfg.storageDriver} ${optionalString cfg.socketActivation "--host=fd://"} ${cfg.extraOptions}";
+          ExecStart = ''${pkgs.docker}/bin/dockerd \
+            --group=docker --log-driver=${cfg.logDriver} \
+            ${optionalString (cfg.storageDriver != null) "--storage-driver=${cfg.storageDriver}"} \
+            ${optionalString cfg.socketActivation "--host=fd://"} \
+            ${cfg.extraOptions}
+          '';
           #  I'm not sure if that limits aren't too high, but it's what
           #  goes in config bundled with docker itself
           LimitNOFILE = 1048576;
diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix
index 59b77dde5d9a..489b612f1675 100644
--- a/nixos/modules/virtualisation/google-compute-image.nix
+++ b/nixos/modules/virtualisation/google-compute-image.nix
@@ -134,8 +134,8 @@ in
 
       wantedBy = [ "sshd.service" ];
       before = [ "sshd.service" ];
-      after = [ "network-online.target" "ip-up.target" ];
-      wants = [ "network-online.target" "ip-up.target" ];
+      after = [ "network-online.target" ];
+      wants = [ "network-online.target" ];
 
       script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'";
                    mktemp = "mktemp --tmpdir=/run"; in
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..7214543871d6 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -4,8 +4,13 @@ with lib;
 
 let
   cfg = config.virtualisation.virtualbox.host;
-  virtualbox = config.boot.kernelPackages.virtualbox.override {
-    inherit (cfg) enableHardening;
+
+  virtualbox = pkgs.virtualbox.override {
+    inherit (cfg) enableHardening headless;
+  };
+
+  kernelModules = config.boot.kernelPackages.virtualbox.override {
+    inherit virtualbox;
   };
 
 in
@@ -47,11 +52,20 @@ 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 [{
     boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];
-    boot.extraModulePackages = [ virtualbox ];
+    boot.extraModulePackages = [ kernelModules ];
     environment.systemPackages = [ virtualbox ];
 
     security.setuidOwners = let
diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix
index fab59b2525a5..d68b3bb73904 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
+          export HOME=$PWD
+          export PATH=${pkgs.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..."
-          export HOME=$PWD
-          export PATH=${pkgs.linuxPackages.virtualbox}/bin:$PATH
           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";