summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-07-20 22:57:23 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-07-20 22:57:23 +0200
commitbc1773fe16dbb1bf1e9cf0808675f6ee24b321f2 (patch)
tree46cabc8461a9a812bd1c530d9d7924af388f2932 /nixos/modules
parent01dc343c2c613c263a2180d1850847f33653f94f (diff)
parent05c0fc15c03f1ae0580ee1cbcf7ff6261d32868c (diff)
downloadnixlib-bc1773fe16dbb1bf1e9cf0808675f6ee24b321f2.tar
nixlib-bc1773fe16dbb1bf1e9cf0808675f6ee24b321f2.tar.gz
nixlib-bc1773fe16dbb1bf1e9cf0808675f6ee24b321f2.tar.bz2
nixlib-bc1773fe16dbb1bf1e9cf0808675f6ee24b321f2.tar.lz
nixlib-bc1773fe16dbb1bf1e9cf0808675f6ee24b321f2.tar.xz
nixlib-bc1773fe16dbb1bf1e9cf0808675f6ee24b321f2.tar.zst
nixlib-bc1773fe16dbb1bf1e9cf0808675f6ee24b321f2.zip
Merge remote-tracking branch 'origin/staging' into systemd-219
Conflicts:
	pkgs/os-specific/linux/kernel/linux-3.4.nix
	pkgs/os-specific/linux/systemd/default.nix
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/fonts/corefonts.nix4
-rw-r--r--nixos/modules/config/i18n.nix2
-rw-r--r--nixos/modules/config/krb5.nix2
-rw-r--r--nixos/modules/config/pulseaudio.nix19
-rw-r--r--nixos/modules/config/shells-environment.nix2
-rw-r--r--nixos/modules/config/system-path.nix2
-rw-r--r--nixos/modules/config/users-groups.nix9
-rw-r--r--nixos/modules/hardware/video/bumblebee.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-base.nix18
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical.nix17
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-minimal.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix16
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl28
-rw-r--r--nixos/modules/misc/assertions.nix2
-rw-r--r--nixos/modules/misc/extra-arguments.nix2
-rw-r--r--nixos/modules/misc/ids.nix20
-rw-r--r--nixos/modules/misc/nixpkgs.nix2
-rw-r--r--nixos/modules/module-list.nix19
-rw-r--r--nixos/modules/profiles/all-hardware.nix2
-rw-r--r--nixos/modules/profiles/base.nix5
-rw-r--r--nixos/modules/profiles/installation-device.nix23
-rw-r--r--nixos/modules/profiles/minimal.nix1
-rw-r--r--nixos/modules/profiles/qemu-guest.nix2
-rw-r--r--nixos/modules/programs/ssh.nix4
-rw-r--r--nixos/modules/programs/venus.nix2
-rw-r--r--nixos/modules/rename.nix4
-rw-r--r--nixos/modules/security/ca.nix8
-rw-r--r--nixos/modules/security/pam.nix18
-rw-r--r--nixos/modules/security/pam_mount.nix72
-rw-r--r--nixos/modules/services/audio/mpd.nix2
-rw-r--r--nixos/modules/services/backup/almir.nix2
-rw-r--r--nixos/modules/services/backup/bacula.nix6
-rw-r--r--nixos/modules/services/cluster/kubernetes.nix119
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/default.nix4
-rw-r--r--nixos/modules/services/databases/influxdb.nix2
-rw-r--r--nixos/modules/services/databases/mysql.nix3
-rw-r--r--nixos/modules/services/databases/neo4j.nix2
-rw-r--r--nixos/modules/services/databases/postgresql.nix7
-rw-r--r--nixos/modules/services/desktops/gnome3/gnome-keyring.nix2
-rw-r--r--nixos/modules/services/hardware/udev.nix3
-rw-r--r--nixos/modules/services/hardware/udisks2.nix2
-rw-r--r--nixos/modules/services/logging/logcheck.nix2
-rw-r--r--nixos/modules/services/logging/rsyslogd.nix2
-rw-r--r--nixos/modules/services/logging/syslogd.nix2
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix2
-rw-r--r--nixos/modules/services/mail/postfix.nix40
-rw-r--r--nixos/modules/services/misc/apache-kafka.nix17
-rw-r--r--nixos/modules/services/misc/confd.nix2
-rw-r--r--nixos/modules/services/misc/devmon.nix28
-rw-r--r--nixos/modules/services/misc/disnix.nix2
-rw-r--r--nixos/modules/services/misc/docker-registry.nix15
-rw-r--r--nixos/modules/services/misc/gitit.nix659
-rw-r--r--nixos/modules/services/misc/gitolite.nix2
-rw-r--r--nixos/modules/services/misc/gpsd.nix4
-rw-r--r--nixos/modules/services/misc/mediatomb.nix15
-rw-r--r--nixos/modules/services/misc/mesos-master.nix4
-rw-r--r--nixos/modules/services/misc/mesos-slave.nix29
-rw-r--r--nixos/modules/services/misc/mwlib.nix259
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix48
-rw-r--r--nixos/modules/services/misc/plex.nix2
-rw-r--r--nixos/modules/services/misc/redmine.nix2
-rw-r--r--nixos/modules/services/misc/ripple-data-api.nix2
-rw-r--r--nixos/modules/services/misc/ripple-rest.nix110
-rw-r--r--nixos/modules/services/misc/rippled.nix16
-rw-r--r--nixos/modules/services/misc/subsonic.nix157
-rw-r--r--nixos/modules/services/misc/sundtek.nix33
-rw-r--r--nixos/modules/services/misc/zookeeper.nix4
-rw-r--r--nixos/modules/services/monitoring/apcupsd.nix4
-rw-r--r--nixos/modules/services/monitoring/das_watchdog.nix34
-rw-r--r--nixos/modules/services/monitoring/dd-agent.nix8
-rw-r--r--nixos/modules/services/monitoring/grafana.nix335
-rw-r--r--nixos/modules/services/monitoring/graphite.nix41
-rw-r--r--nixos/modules/services/monitoring/riemann-tools.nix62
-rw-r--r--nixos/modules/services/monitoring/scollector.nix2
-rw-r--r--nixos/modules/services/monitoring/statsd.nix6
-rw-r--r--nixos/modules/services/monitoring/ups.nix6
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix2
-rw-r--r--nixos/modules/services/networking/atftpd.nix4
-rw-r--r--nixos/modules/services/networking/bitlbee.nix32
-rw-r--r--nixos/modules/services/networking/btsync.nix4
-rw-r--r--nixos/modules/services/networking/charybdis.nix6
-rw-r--r--nixos/modules/services/networking/consul.nix183
-rw-r--r--nixos/modules/services/networking/ddclient.nix2
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix179
-rw-r--r--nixos/modules/services/networking/dnsmasq.nix2
-rw-r--r--nixos/modules/services/networking/docker-registry-server.nix98
-rw-r--r--nixos/modules/services/networking/firefox/sync-server.nix2
-rw-r--r--nixos/modules/services/networking/firewall.nix4
-rw-r--r--nixos/modules/services/networking/freenet.nix4
-rw-r--r--nixos/modules/services/networking/iodined.nix4
-rw-r--r--nixos/modules/services/networking/kippo.nix4
-rw-r--r--nixos/modules/services/networking/minidlna.nix4
-rw-r--r--nixos/modules/services/networking/networkmanager.nix4
-rw-r--r--nixos/modules/services/networking/nix-serve.nix16
-rw-r--r--nixos/modules/services/networking/notbit.nix12
-rw-r--r--nixos/modules/services/networking/ntopng.nix2
-rw-r--r--nixos/modules/services/networking/polipo.nix2
-rw-r--r--nixos/modules/services/networking/racoon.nix42
-rw-r--r--nixos/modules/services/networking/skydns.nix91
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix21
-rw-r--r--nixos/modules/services/networking/tvheadend.nix61
-rw-r--r--nixos/modules/services/networking/unifi.nix4
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix2
-rw-r--r--nixos/modules/services/networking/zerotierone.nix32
-rw-r--r--nixos/modules/services/networking/znc.nix4
-rw-r--r--nixos/modules/services/scheduling/chronos.nix2
-rw-r--r--nixos/modules/services/scheduling/marathon.nix35
-rw-r--r--nixos/modules/services/search/elasticsearch.nix4
-rw-r--r--nixos/modules/services/system/dbus.nix3
-rw-r--r--nixos/modules/services/torrent/peerflix.nix2
-rw-r--r--nixos/modules/services/torrent/transmission.nix4
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix3
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/wordpress.nix110
-rw-r--r--nixos/modules/services/web-servers/lighttpd/cgit.nix2
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix8
-rw-r--r--nixos/modules/services/web-servers/lighttpd/gitweb.nix2
-rw-r--r--nixos/modules/services/web-servers/phpfpm.nix2
-rw-r--r--nixos/modules/services/web-servers/shellinabox.nix122
-rw-r--r--nixos/modules/services/web-servers/uwsgi.nix42
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix6
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/slim.nix5
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix27
-rw-r--r--nixos/modules/services/x11/redshift.nix12
-rw-r--r--nixos/modules/services/x11/unclutter.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix1
-rw-r--r--nixos/modules/services/x11/window-managers/notion.nix32
-rw-r--r--nixos/modules/services/x11/window-managers/stumpwm.nix7
-rw-r--r--nixos/modules/services/x11/xserver.nix13
-rw-r--r--nixos/modules/system/activation/top-level.nix13
-rw-r--r--nixos/modules/system/boot/coredump.nix51
-rw-r--r--nixos/modules/system/boot/kernel.nix2
-rw-r--r--nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix44
-rw-r--r--nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix8
-rw-r--r--nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh132
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix196
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl87
-rw-r--r--nixos/modules/system/boot/loader/grub/winkler-gnu-blue-640x480.pngbin74487 -> 0 bytes
-rw-r--r--nixos/modules/system/boot/loader/grub/winkler-gnu-blue.README6
-rw-r--r--nixos/modules/system/boot/luksroot.nix15
-rw-r--r--nixos/modules/system/boot/modprobe.nix2
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh2
-rw-r--r--nixos/modules/system/boot/stage-1.nix2
-rw-r--r--nixos/modules/system/boot/systemd-lib.nix16
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix4
-rw-r--r--nixos/modules/system/boot/systemd.nix2
-rw-r--r--nixos/modules/system/etc/etc.nix1
-rw-r--r--nixos/modules/tasks/filesystems.nix2
-rw-r--r--nixos/modules/tasks/filesystems/exfat.nix11
-rw-r--r--nixos/modules/tasks/kbd.nix2
-rw-r--r--nixos/modules/tasks/network-interfaces.nix2
-rw-r--r--nixos/modules/tasks/trackpoint.nix48
-rw-r--r--nixos/modules/virtualisation/amazon-init.nix51
-rw-r--r--nixos/modules/virtualisation/docker.nix5
-rw-r--r--nixos/modules/virtualisation/ec2-data.nix22
-rw-r--r--nixos/modules/virtualisation/google-compute-image.nix48
-rw-r--r--nixos/modules/virtualisation/nova-image.nix12
-rw-r--r--nixos/modules/virtualisation/nova.nix2
-rw-r--r--nixos/modules/virtualisation/openvswitch.nix132
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix53
-rw-r--r--nixos/modules/virtualisation/vmware-guest.nix2
-rw-r--r--nixos/modules/virtualisation/xen-dom0.nix120
163 files changed, 4078 insertions, 722 deletions
diff --git a/nixos/modules/config/fonts/corefonts.nix b/nixos/modules/config/fonts/corefonts.nix
index ad7970879324..b9f69879a103 100644
--- a/nixos/modules/config/fonts/corefonts.nix
+++ b/nixos/modules/config/fonts/corefonts.nix
@@ -1,3 +1,6 @@
+# This module is deprecated, since you can just say ‘fonts.fonts = [
+# pkgs.corefonts ];’ instead.
+
 { config, lib, pkgs, ... }:
 
 with lib;
@@ -9,6 +12,7 @@ with lib;
     fonts = {
 
       enableCoreFonts = mkOption {
+        visible = false;
         default = false;
         description = ''
           Whether to include Microsoft's proprietary Core Fonts.  These fonts
diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix
index f2aacf9b2924..3622b21626b3 100644
--- a/nixos/modules/config/i18n.nix
+++ b/nixos/modules/config/i18n.nix
@@ -43,7 +43,7 @@ in
 
       consoleFont = mkOption {
         type = types.str;
-        default = "lat9w-16";
+        default = "Lat2-Terminus16";
         example = "LatArCyrHeb-16";
         description = ''
           The font used for the virtual consoles.  Leave empty to use
diff --git a/nixos/modules/config/krb5.nix b/nixos/modules/config/krb5.nix
index 991b5b16cc68..d2198e4ac1ae 100644
--- a/nixos/modules/config/krb5.nix
+++ b/nixos/modules/config/krb5.nix
@@ -48,7 +48,7 @@ in
 
   config = mkIf config.krb5.enable {
 
-    environment.systemPackages = [ pkgs.krb5 ];
+    environment.systemPackages = [ pkgs.krb5Full ];
 
     environment.etc."krb5.conf".text =
       ''
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index c41e4ea604d5..2ebc61260558 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -12,7 +12,7 @@ let
 
   # Forces 32bit pulseaudio and alsaPlugins to be built/supported for apps
   # using 32bit alsa on 64bit linux.
-  enable32BitAlsaPlugins = stdenv.isx86_64 && (pkgs_i686.alsaLib != null && pkgs_i686.pulseaudio != null);
+  enable32BitAlsaPlugins = cfg.support32Bit && stdenv.isx86_64 && (pkgs_i686.alsaLib != null && pkgs_i686.libpulseaudio != null);
 
   ids = config.ids;
 
@@ -78,6 +78,15 @@ in {
         '';
       };
 
+      support32Bit = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to include the 32-bit pulseaudio libraries in the systemn or not.
+          This is only useful on 64-bit systems and currently limited to x86_64-linux.
+        '';
+      };
+
       configFile = mkOption {
         type = types.path;
         description = ''
@@ -89,12 +98,12 @@ in {
 
       package = mkOption {
         type = types.package;
-        default = pulseaudioFull;
+        default = pulseaudioLight;
         example = literalExample "pkgs.pulseaudioFull";
         description = ''
-          The PulseAudio derivation to use.  This can be used to disable
-          features (such as JACK support, Bluetooth) that are enabled in the
-          pulseaudioFull package in Nixpkgs.
+          The PulseAudio derivation to use.  This can be used to enable
+          features (such as JACK support, Bluetooth) via the
+          <literal>pulseaudioFull</literal> package.
         '';
       };
 
diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix
index e5b342afcc41..bff0b2991323 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -63,7 +63,7 @@ in
       description = ''
         A list of profiles used to setup the global environment.
       '';
-      type = types.listOf types.string;
+      type = types.listOf types.str;
     };
 
     environment.profileRelativeEnvVars = mkOption {
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index d22f9ebd1dfd..62390f452ba2 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -38,7 +38,7 @@ let
       pkgs.nano
       pkgs.ncurses
       pkgs.netcat
-      pkgs.openssh
+      config.programs.ssh.package
       pkgs.perl
       pkgs.procps
       pkgs.rsync
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 9d48edf2f26c..478f433b431c 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -108,6 +108,15 @@ let
         description = "The user's home directory.";
       };
 
+      cryptHomeLuks = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Path to encrypted luks device that contains
+          the user's home directory.
+        '';
+      };
+
       shell = mkOption {
         type = types.str;
         default = "/run/current-system/sw/bin/nologin";
diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix
index e20ebc3041e7..e341eac4a819 100644
--- a/nixos/modules/hardware/video/bumblebee.nix
+++ b/nixos/modules/hardware/video/bumblebee.nix
@@ -26,7 +26,7 @@ in
     hardware.bumblebee.group = mkOption {
       default = "wheel";
       example = "video";
-      type = types.uniq types.str;
+      type = types.str;
       description = ''Group for bumblebee socket'';
     };
     hardware.bumblebee.connectDisplay = mkOption {
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
index 446d79ce2200..bc3bd872d2a5 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
@@ -7,8 +7,7 @@ with lib;
 
 {
   imports =
-    [ ./channel.nix
-      ./iso-image.nix
+    [ ./iso-image.nix
 
       # Profiles of this basic installation CD.
       ../../profiles/all-hardware.nix
@@ -21,18 +20,6 @@ with lib;
 
   isoImage.volumeID = substring 0 11 "NIXOS_ISO";
 
-  # Make the installer more likely to succeed in low memory
-  # environments.  The kernel's overcommit heustistics bite us
-  # fairly often, preventing processes such as nix-worker or
-  # download-using-manifests.pl from forking even if there is
-  # plenty of free memory.
-  boot.kernel.sysctl."vm.overcommit_memory" = "1";
-
-  # To speed up installation a little bit, include the complete stdenv
-  # in the Nix store on the CD.  Archive::Cpio is needed for the
-  # initrd builder.
-  isoImage.storeContents = [ pkgs.stdenv pkgs.busybox pkgs.perlPackages.ArchiveCpio ];
-
   # EFI booting
   isoImage.makeEfiBootable = true;
 
@@ -42,9 +29,6 @@ with lib;
   # Add Memtest86+ to the CD.
   boot.loader.grub.memtest86.enable = true;
 
-  # Get a console as soon as the initrd loads fbcon on EFI boot.
-  boot.initrd.kernelModules = [ "fbcon" ];
-
   # Allow the user to log in as root without a password.
   users.extraUsers.root.initialHashedPassword = "";
 }
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix
index 189cca9e23b9..d14768bc1079 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix
@@ -11,9 +11,16 @@ with lib;
   # Provide wicd for easy wireless configuration.
   #networking.wicd.enable = true;
 
-  # Include gparted for partitioning disks
-  environment.systemPackages = [ pkgs.gparted ];
-  
+  environment.systemPackages =
+    [ # Include gparted for partitioning disks.
+      pkgs.gparted
+
+      # Include some editors.
+      pkgs.vim
+      pkgs.bvi # binary editor
+      pkgs.joe
+    ];
+
   # Provide networkmanager for easy wireless configuration.
   networking.networkmanager.enable = true;
   networking.wireless.enable = mkForce false;
@@ -67,7 +74,7 @@ with lib;
       loadTemplate("org.kde.plasma-desktop.defaultPanel")
 
       for (var i = 0; i < screenCount; ++i) {
-      	var desktop = new Activity
+        var desktop = new Activity
         desktop.name = i18n("Desktop")
         desktop.screen = i
         desktop.wallpaperPlugin = 'image'
@@ -75,7 +82,7 @@ with lib;
 
         var folderview = desktop.addWidget("folderview");
         folderview.writeConfig("url", "desktop:/");
-        
+
         //Create more panels for other screens
         if (i > 0){
           var panel = new Panel
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix b/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix
index a7498906a86b..4641b8fcf9d1 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix
@@ -1,7 +1,7 @@
 # This module defines a small NixOS installation CD.  It does not
 # contain any graphical stuff.
 
-{ config, pkgs, ... }:
+{ config, lib, ... }:
 
 {
   imports =
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index c546b8df4744..c9abff2ecfc0 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -40,7 +40,7 @@ let
     DEFAULT boot
 
     LABEL boot
-    MENU LABEL NixOS ${config.system.nixosVersion} Installer
+    MENU LABEL NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel}
     LINUX /boot/bzImage
     APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
     INITRD /boot/initrd
@@ -192,6 +192,18 @@ in
       '';
     };
 
+    isoImage.appendToMenuLabel = mkOption {
+      default = " Installer";
+      example = " Live System";
+      description = ''
+        The string to append after the menu label for the NixOS system.
+        This will be directly appended (without whitespace) to the NixOS version
+        string, like for example if it is set to <literal>XXX</literal>:
+
+        <para><literal>NixOS 99.99-pre666XXX</literal></para>
+      '';
+    };
+
   };
 
   config = {
@@ -204,7 +216,7 @@ in
 
     # !!! Hack - attributes expected by other modules.
     system.boot.loader.kernelFile = "bzImage";
-    environment.systemPackages = [ pkgs.grub2 pkgs.syslinux ];
+    environment.systemPackages = [ pkgs.grub2 pkgs.grub2_efi pkgs.syslinux ];
 
     # In stage 1 of the boot, mount the CD as the root FS by label so
     # that we don't need to know its device.  We pass the label of the
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index ec3137ede4ff..187ea7635eb5 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -70,7 +70,7 @@ my @attrs = ();
 my @kernelModules = ();
 my @initrdKernelModules = ();
 my @modulePackages = ();
-my @imports = ("<nixpkgs/nixos/modules/installer/scan/not-detected.nix>");
+my @imports;
 
 
 sub debug {
@@ -245,6 +245,18 @@ if ($virt eq "qemu" || $virt eq "kvm" || $virt eq "bochs") {
 }
 
 
+# Pull in NixOS configuration for containers.
+if ($virt eq "systemd-nspawn") {
+    push @attrs, "boot.isContainer = true;";
+}
+
+
+# Provide firmware for devices that are not detected by this script,
+# unless we're in a VM/container.
+push @imports, "<nixpkgs/nixos/modules/installer/scan/not-detected.nix>"
+    if $virt eq "none";
+
+
 # For a device name like /dev/sda1, find a more stable path like
 # /dev/disk/by-uuid/X or /dev/disk/by-label/Y.
 sub findStableDevPath {
@@ -311,9 +323,9 @@ foreach my $fs (read_file("/proc/self/mountinfo")) {
 
     # Maybe this is a bind-mount of a filesystem we saw earlier?
     if (defined $fsByDev{$fields[2]}) {
-        # Make sure this isn't a btrfs subvolume
-        my ($status, @msg) = runCommand("btrfs subvol show $rootDir$mountPoint");
-        if (join("", @msg) =~ /ERROR:/) {
+        # Make sure this isn't a btrfs subvolume.
+        my $msg = `btrfs subvol show $rootDir$mountPoint`;
+        if ($? != 0 || $msg =~ /ERROR:/s) {
             my $path = $fields[3]; $path = "" if $path eq "/";
             my $base = $fsByDev{$fields[2]};
             $base = "" if $base eq "/";
@@ -354,7 +366,7 @@ EOF
         if ($status != 0 || join("", @msg) =~ /ERROR:/) {
             die "Failed to retrieve subvolume info for $mountPoint\n";
         }
-        my @ids = join("", @id_info) =~ m/Object ID:[ \t\n]*([^ \t\n]*)/;
+        my @ids = join("", @id_info) =~ m/Subvolume ID:[ \t\n]*([^ \t\n]*)/;
         if ($#ids > 0) {
             die "Btrfs subvol name for $mountPoint listed multiple times in mount\n"
         } elsif ($#ids == 0) {
@@ -459,14 +471,14 @@ if ($showHardwareConfig) {
     if ($force || ! -e $fn) {
         print STDERR "writing $fn...\n";
 
-        my $bootloaderConfig;
+        my $bootloaderConfig = "";
         if (-e "/sys/firmware/efi/efivars") {
             $bootLoaderConfig = <<EOF;
   # Use the gummiboot efi boot loader.
   boot.loader.gummiboot.enable = true;
   boot.loader.efi.canTouchEfiVariables = true;
 EOF
-        } else {
+        } elsif ($virt ne "systemd-nspawn") {
             $bootLoaderConfig = <<EOF;
   # Use the GRUB 2 boot loader.
   boot.loader.grub.enable = true;
@@ -495,7 +507,7 @@ $bootLoaderConfig
 
   # Select internationalisation properties.
   # i18n = {
-  #   consoleFont = "lat9w-16";
+  #   consoleFont = "Lat2-Terminus16";
   #   consoleKeyMap = "us";
   #   defaultLocale = "en_US.UTF-8";
   # };
diff --git a/nixos/modules/misc/assertions.nix b/nixos/modules/misc/assertions.nix
index c1be36e98cba..c42de038e61f 100644
--- a/nixos/modules/misc/assertions.nix
+++ b/nixos/modules/misc/assertions.nix
@@ -21,7 +21,7 @@ with lib;
     warnings = mkOption {
       internal = true;
       default = [];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       example = [ "The `foo' service is deprecated and will go away soon!" ];
       description = ''
         This option allows modules to show warnings to users during
diff --git a/nixos/modules/misc/extra-arguments.nix b/nixos/modules/misc/extra-arguments.nix
index c2c8903546d5..ff2ff7cd4322 100644
--- a/nixos/modules/misc/extra-arguments.nix
+++ b/nixos/modules/misc/extra-arguments.nix
@@ -2,8 +2,6 @@
 
 {
   _module.args = {
-    modulesPath = ../.;
-
     pkgs_i686 = import ../../lib/nixpkgs.nix {
       system = "i686-linux";
       config.allowUnfree = true;
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index cc1976e236bd..fd75db1abe77 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -217,6 +217,15 @@
       asterisk = 192;
       plex = 193;
       bird = 195;
+      grafana = 196;
+      skydns = 197;
+      ripple-rest = 198;
+      nix-serve = 199;
+      tvheadend = 200;
+      uwsgi = 201;
+      gitit = 202;
+      riemanntools = 203;
+      subsonic = 204;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -373,7 +382,7 @@
       seeks = 148;
       prosody = 149;
       i2pd = 150;
-      #dnscrypt-proxy = 151; # unused
+      dnscrypt-proxy = 151;
       systemd-network = 152;
       systemd-resolve = 153;
       systemd-timesync = 154;
@@ -412,6 +421,15 @@
       plex = 193;
       sabnzbd = 194;
       bird = 195;
+      #grafana = 196; #unused
+      #skydns = 197; #unused
+      #ripple-rest = 198; #unused
+      #nix-serve = 199; #unused
+      #tvheadend = 200; #unused
+      uwsgi = 201;
+      gitit = 202;
+      riemanntools = 203;
+      subsonic = 204;
 
       # 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/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix
index 114feb2562db..fb5516c953c2 100644
--- a/nixos/modules/misc/nixpkgs.nix
+++ b/nixos/modules/misc/nixpkgs.nix
@@ -59,7 +59,7 @@ in
     };
 
     nixpkgs.system = mkOption {
-      type = types.uniq types.str;
+      type = types.str;
       example = "i686-linux";
       description = ''
         Specifies the Nix platform type for which NixOS should be built.
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index bef3f7f2fe73..f771bced5ef6 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -84,6 +84,7 @@
   ./security/grsecurity.nix
   ./security/pam.nix
   ./security/pam_usb.nix
+  ./security/pam_mount.nix
   ./security/polkit.nix
   ./security/prey.nix
   ./security/rngd.nix
@@ -188,12 +189,14 @@
   ./services/misc/cpuminer-cryptonight.nix
   ./services/misc/cgminer.nix
   ./services/misc/confd.nix
+  ./services/misc/devmon.nix
   ./services/misc/dictd.nix
   ./services/misc/disnix.nix
   ./services/misc/docker-registry.nix
   ./services/misc/etcd.nix
   ./services/misc/felix.nix
   ./services/misc/folding-at-home.nix
+  ./services/misc/gitit.nix
   ./services/misc/gitlab.nix
   ./services/misc/gitolite.nix
   ./services/misc/gpsd.nix
@@ -202,6 +205,7 @@
   ./services/misc/mediatomb.nix
   ./services/misc/mesos-master.nix
   ./services/misc/mesos-slave.nix
+  ./services/misc/mwlib.nix
   ./services/misc/nix-daemon.nix
   ./services/misc/nix-gc.nix
   ./services/misc/nixos-manual.nix
@@ -211,9 +215,12 @@
   ./services/misc/plex.nix
   ./services/misc/redmine.nix
   ./services/misc/rippled.nix
+  ./services/misc/ripple-rest.nix
   ./services/misc/ripple-data-api.nix
   ./services/misc/rogue.nix
   ./services/misc/siproxd.nix
+  ./services/misc/subsonic.nix
+  ./services/misc/sundtek.nix
   ./services/misc/svnserve.nix
   ./services/misc/synergy.nix
   ./services/misc/uhub.nix
@@ -222,13 +229,16 @@
   ./services/monitoring/bosun.nix
   ./services/monitoring/cadvisor.nix
   ./services/monitoring/collectd.nix
+  ./services/monitoring/das_watchdog.nix
   ./services/monitoring/dd-agent.nix
+  ./services/monitoring/grafana.nix
   ./services/monitoring/graphite.nix
   ./services/monitoring/monit.nix
   ./services/monitoring/munin.nix
   ./services/monitoring/nagios.nix
   ./services/monitoring/riemann.nix
   ./services/monitoring/riemann-dash.nix
+  ./services/monitoring/riemann-tools.nix
   ./services/monitoring/scollector.nix
   ./services/monitoring/smartd.nix
   ./services/monitoring/statsd.nix
@@ -266,6 +276,7 @@
   ./services/networking/dhcpd.nix
   ./services/networking/dnscrypt-proxy.nix
   ./services/networking/dnsmasq.nix
+  ./services/networking/docker-registry-server.nix
   ./services/networking/ejabberd.nix
   ./services/networking/firefox/sync-server.nix
   ./services/networking/firewall.nix
@@ -306,6 +317,7 @@
   ./services/networking/privoxy.nix
   ./services/networking/prosody.nix
   ./services/networking/quassel.nix
+  ./services/networking/racoon.nix
   ./services/networking/radicale.nix
   ./services/networking/radvd.nix
   ./services/networking/rdnssd.nix
@@ -313,6 +325,7 @@
   ./services/networking/sabnzbd.nix
   ./services/networking/searx.nix
   ./services/networking/seeks.nix
+  ./services/networking/skydns.nix
   ./services/networking/spiped.nix
   ./services/networking/sslh.nix
   ./services/networking/ssh/lshd.nix
@@ -326,6 +339,7 @@
   ./services/networking/tftpd.nix
   ./services/networking/tlsdated.nix
   ./services/networking/tox-bootstrapd.nix
+  ./services/networking/tvheadend.nix
   ./services/networking/unbound.nix
   ./services/networking/unifi.nix
   ./services/networking/vsftpd.nix
@@ -334,6 +348,7 @@
   ./services/networking/wicd.nix
   ./services/networking/wpa_supplicant.nix
   ./services/networking/xinetd.nix
+  ./services/networking/zerotierone.nix
   ./services/networking/znc.nix
   ./services/printing/cupsd.nix
   ./services/scheduling/atd.nix
@@ -373,6 +388,7 @@
   ./services/web-servers/lighttpd/gitweb.nix
   ./services/web-servers/nginx/default.nix
   ./services/web-servers/phpfpm.nix
+  ./services/web-servers/shellinabox.nix
   ./services/web-servers/tomcat.nix
   ./services/web-servers/uwsgi.nix
   ./services/web-servers/varnish/default.nix
@@ -406,12 +422,14 @@
   ./services/x11/xserver.nix
   ./system/activation/activation-script.nix
   ./system/activation/top-level.nix
+  ./system/boot/coredump.nix
   ./system/boot/emergency-mode.nix
   ./system/boot/kernel.nix
   ./system/boot/kexec.nix
   ./system/boot/loader/efi.nix
   ./system/boot/loader/loader.nix
   ./system/boot/loader/generations-dir/generations-dir.nix
+  ./system/boot/loader/generic-extlinux-compatible
   ./system/boot/loader/grub/grub.nix
   ./system/boot/loader/grub/ipxe.nix
   ./system/boot/loader/grub/memtest.nix
@@ -436,6 +454,7 @@
   ./tasks/filesystems.nix
   ./tasks/filesystems/btrfs.nix
   ./tasks/filesystems/cifs.nix
+  ./tasks/filesystems/exfat.nix
   ./tasks/filesystems/ext.nix
   ./tasks/filesystems/f2fs.nix
   ./tasks/filesystems/jfs.nix
diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix
index 6385ee69500f..99b45228ce4d 100644
--- a/nixos/modules/profiles/all-hardware.nix
+++ b/nixos/modules/profiles/all-hardware.nix
@@ -40,7 +40,7 @@
       "ohci1394" "sbp2"
 
       # Virtio (QEMU, KVM etc.) support.
-      "virtio_net" "virtio_pci" "virtio_blk" "virtio_balloon" "virtio_console"
+      "virtio_net" "virtio_pci" "virtio_blk" "virtio_scsi" "virtio_balloon" "virtio_console"
 
       # Keyboards
       "usbhid" "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat"
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 6c8e99943797..c207829aabd6 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -44,11 +44,6 @@
     pkgs.zip
     pkgs.dar # disk archiver
     pkgs.cabextract
-
-    # Some editors.
-    pkgs.vim
-    pkgs.bvi # binary editor
-    pkgs.joe
   ];
 
   # Include support for various filesystems.
diff --git a/nixos/modules/profiles/installation-device.nix b/nixos/modules/profiles/installation-device.nix
index a41d17e51821..946032781f40 100644
--- a/nixos/modules/profiles/installation-device.nix
+++ b/nixos/modules/profiles/installation-device.nix
@@ -1,5 +1,5 @@
 # Provide a basic configuration for installation devices like CDs.
-{ config, lib, ... }:
+{ config, pkgs, lib, ... }:
 
 with lib;
 
@@ -13,10 +13,17 @@ with lib;
       # Allow "nixos-rebuild" to work properly by providing
       # /etc/nixos/configuration.nix.
       ./clone-config.nix
+
+      # Include a copy of Nixpkgs so that nixos-install works out of
+      # the box.
+      ../installer/cd-dvd/channel.nix
     ];
 
   config = {
 
+    # Enable in installer, even if the minimal profile disables it.
+    services.nixosManual.enable = mkForce true;
+
     # Show the manual.
     services.nixosManual.showManual = true;
 
@@ -43,7 +50,7 @@ with lib;
     systemd.services.sshd.wantedBy = mkOverride 50 [];
 
     # Enable wpa_supplicant, but don't start it by default.
-    networking.wireless.enable = true;
+    networking.wireless.enable = mkDefault true;
     jobs.wpa_supplicant.startOn = mkOverride 50 "";
 
     # Tell the Nix evaluator to garbage collect more aggressively.
@@ -51,5 +58,17 @@ with lib;
     # (yet) have swap set up.
     environment.variables.GC_INITIAL_HEAP_SIZE = "100000";
 
+    # Make the installer more likely to succeed in low memory
+    # environments.  The kernel's overcommit heustistics bite us
+    # fairly often, preventing processes such as nix-worker or
+    # download-using-manifests.pl from forking even if there is
+    # plenty of free memory.
+    boot.kernel.sysctl."vm.overcommit_memory" = "1";
+
+    # To speed up installation a little bit, include the complete
+    # stdenv in the Nix store on the CD.  Archive::Cpio is needed for
+    # the initrd builder.
+    system.extraDependencies = [ pkgs.stdenv pkgs.busybox pkgs.perlPackages.ArchiveCpio ];
+
   };
 }
diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix
index 69729923e035..3b18ae129b93 100644
--- a/nixos/modules/profiles/minimal.nix
+++ b/nixos/modules/profiles/minimal.nix
@@ -8,4 +8,5 @@ with lib;
 {
   environment.noXlibs = mkDefault true;
   i18n.supportedLocales = [ config.i18n.defaultLocale ];
+  services.nixosManual.enable = mkDefault false;
 }
diff --git a/nixos/modules/profiles/qemu-guest.nix b/nixos/modules/profiles/qemu-guest.nix
index 79890aa7f17c..759fdb7f8e5f 100644
--- a/nixos/modules/profiles/qemu-guest.nix
+++ b/nixos/modules/profiles/qemu-guest.nix
@@ -4,7 +4,7 @@
 { config, pkgs, ... }:
 
 {
-  boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_blk" "9p" "9pnet_virtio" ];
+  boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" ];
   boot.initrd.kernelModules = [ "virtio_balloon" "virtio_console" "virtio_rng" ];
 
   boot.initrd.postDeviceCommands =
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index 6ca73eea5f6f..0d1ec500afc4 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -27,7 +27,7 @@ in
     programs.ssh = {
 
       askPassword = mkOption {
-        type = types.string;
+        type = types.str;
         default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
         description = ''Program used by SSH to ask for passwords.'';
       };
@@ -77,7 +77,7 @@ in
       };
 
       agentTimeout = mkOption {
-        type = types.nullOr types.string;
+        type = types.nullOr types.str;
         default = null;
         example = "1h";
         description = ''
diff --git a/nixos/modules/programs/venus.nix b/nixos/modules/programs/venus.nix
index 2b70a795f4fd..3b5ae07e82f7 100644
--- a/nixos/modules/programs/venus.nix
+++ b/nixos/modules/programs/venus.nix
@@ -166,7 +166,7 @@ in
         script = "exec venus-planet ${configFile}";
         serviceConfig.User = "${cfg.user}";
         serviceConfig.Group = "${cfg.group}";
-        environment.OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
+        environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
         startAt = cfg.dates;
       };
 
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index fc83e7ed590a..a928f47f439e 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -141,6 +141,9 @@ in zipModules ([]
 ++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ]
 ++ obsolete [ "services" "xserver" "desktopManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ]
 
+# DNSCrypt-proxy
+++ obsolete [ "services" "dnscrypt-proxy" "port" ] [ "services" "dnscrypt-proxy" "localPort" ]
+
 # Options that are obsolete and have no replacement.
 ++ obsolete' [ "boot" "loader" "grub" "bootDevice" ]
 ++ obsolete' [ "boot" "initrd" "luks" "enable" ]
@@ -148,5 +151,6 @@ in zipModules ([]
 ++ obsolete' [ "services" "samba" "defaultShare" ]
 ++ obsolete' [ "services" "syslog-ng" "serviceName" ]
 ++ obsolete' [ "services" "syslog-ng" "listenToJournal" ]
+++ obsolete' [ "ec2" "metadata" ]
 
 )
diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix
index e60cb5cdb67d..ddfad52d42ed 100644
--- a/nixos/modules/security/ca.nix
+++ b/nixos/modules/security/ca.nix
@@ -22,7 +22,7 @@ in
     security.pki.certificateFiles = mkOption {
       type = types.listOf types.path;
       default = [];
-      example = literalExample "[ \"\${pkgs.cacert}/etc/ca-bundle.crt\" ]";
+      example = literalExample "[ \"\${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt\" ]";
       description = ''
         A list of files containing trusted root certificates in PEM
         format. These are concatenated to form
@@ -33,7 +33,7 @@ in
     };
 
     security.pki.certificates = mkOption {
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       default = [];
       example = singleton ''
         NixOS.org
@@ -53,7 +53,7 @@ in
 
   config = {
 
-    security.pki.certificateFiles = [ "${pkgs.cacert}/etc/ca-bundle.crt" ];
+    security.pki.certificateFiles = [ "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ];
 
     # NixOS canonical location + Debian/Ubuntu/Arch/Gentoo compatibility.
     environment.etc."ssl/certs/ca-certificates.crt".source = caBundle;
@@ -67,8 +67,6 @@ in
     environment.sessionVariables =
       { SSL_CERT_FILE          = "/etc/ssl/certs/ca-certificates.crt";
         # FIXME: unneeded - remove eventually.
-        OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
-        # FIXME: unneeded - remove eventually.
         GIT_SSL_CAINFO         = "/etc/ssl/certs/ca-certificates.crt";
       };
 
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 35622b12ea33..02520fb88cdd 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -126,6 +126,14 @@ let
         '';
       };
 
+      pamMount = mkOption {
+        default = config.security.pam.mount.enable;
+        type = types.bool;
+        description = ''
+          Enable PAM mount (pam_mount) system to mount fileystems on user login.
+        '';
+      };
+
       allowNullPassword = mkOption {
         default = false;
         type = types.bool;
@@ -224,7 +232,9 @@ let
           ${optionalString cfg.usbAuth
               "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
           ${optionalString cfg.unixAuth
-              "auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"}
+              "auth ${if (config.security.pam.enableEcryptfs || cfg.pamMount) then "required" else "sufficient"} pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"}
+          ${optionalString cfg.pamMount
+              "auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so"}
           ${optionalString config.security.pam.enableEcryptfs
               "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
           ${optionalString cfg.otpwAuth
@@ -238,12 +248,14 @@ let
             auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
             auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
           ''}
-          ${optionalString (! config.security.pam.enableEcryptfs) "auth required pam_deny.so"}
+          ${optionalString (!(config.security.pam.enableEcryptfs || cfg.pamMount)) "auth required pam_deny.so"}
 
           # Password management.
           ${optionalString config.security.pam.enableEcryptfs
               "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
           password requisite pam_unix.so nullok sha512
+          ${optionalString cfg.pamMount
+              "password optional ${pkgs.pam_mount}/lib/security/pam_mount.so"}
           ${optionalString config.users.ldap.enable
               "password sufficient ${pam_ldap}/lib/security/pam_ldap.so"}
           ${optionalString config.krb5.enable
@@ -280,6 +292,8 @@ let
               "session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}"}
           ${optionalString (cfg.showMotd && config.users.motd != null)
               "session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"}
+          ${optionalString cfg.pamMount
+              "session optional ${pkgs.pam_mount}/lib/security/pam_mount.so"}
         '';
     };
 
diff --git a/nixos/modules/security/pam_mount.nix b/nixos/modules/security/pam_mount.nix
new file mode 100644
index 000000000000..a5299728348d
--- /dev/null
+++ b/nixos/modules/security/pam_mount.nix
@@ -0,0 +1,72 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.security.pam.mount;
+
+  anyPamMount = any (attrByPath ["pamMount"] false) (attrValues config.security.pam.services);
+in
+
+{
+  options = {
+
+    security.pam.mount = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable PAM mount system to mount fileystems on user login.
+        '';
+      };
+
+      extraVolumes = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          List of volume definitions for pam_mount.
+          For more information, visit <link
+          xlink:href="http://pam-mount.sourceforge.net/pam_mount.conf.5.html" />.
+        '';
+      };
+    };
+
+  };
+
+  config = mkIf (cfg.enable || anyPamMount) {
+
+    environment.systemPackages = [ pkgs.pam_mount ];
+    environment.etc = [{
+      target = "security/pam_mount.conf.xml";
+      source =
+        let
+          extraUserVolumes = filterAttrs (n: u: u.cryptHomeLuks != null) config.users.extraUsers;
+          userVolumeEntry = user: "<volume user=\"${user.name}\" path=\"${user.cryptHomeLuks}\" mountpoint=\"${user.home}\" />\n";
+        in
+         pkgs.writeText "pam_mount.conf.xml" ''
+          <?xml version="1.0" encoding="utf-8" ?>
+          <!DOCTYPE pam_mount SYSTEM "pam_mount.conf.xml.dtd">
+          <!-- auto generated from Nixos: modules/config/users-groups.nix -->
+          <pam_mount>
+          <debug enable="0" />
+
+          ${concatStrings (map userVolumeEntry (attrValues extraUserVolumes))}
+          ${concatStringsSep "\n" cfg.extraVolumes}
+
+          <!-- if activated, requires ofl from hxtools to be present -->
+          <logout wait="0" hup="no" term="no" kill="no" />
+          <!-- set PATH variable for pam_mount module -->
+          <path>${pkgs.utillinux}/bin</path>
+          <!-- create mount point if not present -->
+          <mkmountpoint enable="1" remove="true" />
+
+          <!-- specify the binaries to be called -->
+          <cryptmount>${pkgs.pam_mount}/bin/mount.crypt %(VOLUME) %(MNTPT)</cryptmount>
+          <cryptumount>${pkgs.pam_mount}/bin/umount.crypt %(MNTPT)</cryptumount>
+          <pmvarrun>${pkgs.pam_mount}/bin/pmvarrun -u %(USER) -o %(OPERATION)</pmvarrun>
+          </pam_mount>
+          '';
+    }];
+
+  };
+}
diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix
index 06ba4b9b5acb..5515f827b290 100644
--- a/nixos/modules/services/audio/mpd.nix
+++ b/nixos/modules/services/audio/mpd.nix
@@ -118,7 +118,7 @@ in {
       preStart = "mkdir -p ${cfg.dataDir} && chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}";
       script = "exec mpd --no-daemon ${mpdConf}";
       serviceConfig = {
-        User = "mpd";
+        User = "${cfg.user}";
         PermissionsStartOnly = true;
       };
     };
diff --git a/nixos/modules/services/backup/almir.nix b/nixos/modules/services/backup/almir.nix
index ec39a997028a..fbb4ff4034f1 100644
--- a/nixos/modules/services/backup/almir.nix
+++ b/nixos/modules/services/backup/almir.nix
@@ -95,7 +95,7 @@ in {
 
       port = mkOption {
         default = 35000;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           Port for Almir web server to listen on.
         '';
diff --git a/nixos/modules/services/backup/bacula.nix b/nixos/modules/services/backup/bacula.nix
index c2255f688181..9e3ae66f808b 100644
--- a/nixos/modules/services/backup/bacula.nix
+++ b/nixos/modules/services/backup/bacula.nix
@@ -182,7 +182,7 @@ in {
  
       port = mkOption {
         default = 9102;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
         	This specifies the port number on which the Client listens for Director connections. It must agree with the FDPort specified in the Client resource of the Director's configuration file. The default is 9102.
         '';
@@ -237,7 +237,7 @@ in {
  
       port = mkOption {
         default = 9103;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           Specifies port number on which the Storage daemon listens for Director connections. The default is 9103.
         '';
@@ -302,7 +302,7 @@ in {
  
       port = mkOption {
         default = 9101;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           Specify the port (a positive integer) on which the Director daemon will listen for Bacula Console connections. This same port number must be specified in the Director resource of the Console configuration file. The default is 9101, so normally this directive need not be specified. This directive should not be used if you specify DirAddresses (N.B plural) directive.
         '';
diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix
index 6a775bb159fc..d00c1aaa1055 100644
--- a/nixos/modules/services/cluster/kubernetes.nix
+++ b/nixos/modules/services/cluster/kubernetes.nix
@@ -224,7 +224,7 @@ in {
 
       machines = mkOption {
         description = "Kubernetes controller list of machines to schedule to schedule onto";
-        default = [config.networking.hostName];
+        default = [];
         type = types.listOf types.str;
       };
 
@@ -242,6 +242,12 @@ in {
         type = types.bool;
       };
 
+      registerNode = mkOption {
+        description = "Whether to auto register kubelet with API server.";
+        default = true;
+        type = types.bool;
+      };
+
       address = mkOption {
         description = "Kubernetes kubelet info server listening address.";
         default = "0.0.0.0";
@@ -274,7 +280,7 @@ in {
 
       cadvisorPort = mkOption {
         description = "Kubernetes kubelet local cadvisor port.";
-        default = config.services.cadvisor.port;
+        default = 4194;
         type = types.int;
       };
 
@@ -286,7 +292,7 @@ in {
 
       clusterDomain = mkOption {
         description = "Use alternative domain.";
-        default = "";
+        default = "kubernetes.io";
         type = types.str;
       };
 
@@ -322,13 +328,35 @@ in {
         type = types.str;
       };
     };
+
+    kube2sky = {
+      enable = mkEnableOption "Whether to enable kube2sky dns service.";
+
+      domain = mkOption  {
+        description = "Kuberntes kube2sky domain under which all DNS names will be hosted.";
+        default = cfg.kubelet.clusterDomain;
+        type = types.str;
+      };
+
+      master = mkOption {
+        description = "Kubernetes apiserver address";
+        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
+        type = types.str;
+      };
+
+      extraOpts = mkOption {
+        description = "Kubernetes kube2sky extra command line options.";
+        default = "";
+        type = types.str;
+      };
+    };
   };
 
   ###### implementation
 
   config = mkMerge [
     (mkIf cfg.apiserver.enable {
-      systemd.services.kubernetes-apiserver = {
+      systemd.services.kube-apiserver = {
         description = "Kubernetes Api Server";
         wantedBy = [ "multi-user.target" ];
         requires = ["kubernetes-setup.service"];
@@ -343,26 +371,25 @@ in {
                 (concatImapStringsSep "\n" (i: v: v + "," + (toString i))
                     (mapAttrsToList (name: token: token + "," + name) cfg.apiserver.tokenAuth));
           in ''${cfg.package}/bin/kube-apiserver \
-            --etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \
-            --address=${cfg.apiserver.address} \
-            --port=${toString cfg.apiserver.port} \
-            --read_only_port=${toString cfg.apiserver.readOnlyPort} \
-            --public_address_override=${cfg.apiserver.publicAddress} \
-            --allow_privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \
+            --etcd-servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \
+            --insecure-bind-address=${cfg.apiserver.address} \
+            --insecure-port=${toString cfg.apiserver.port} \
+            --read-only-port=${toString cfg.apiserver.readOnlyPort} \
+            --bind-address=${cfg.apiserver.publicAddress} \
+            --allow-privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \
             ${optionalString (cfg.apiserver.tlsCertFile!="")
-              "--tls_cert_file=${cfg.apiserver.tlsCertFile}"} \
+              "--tls-cert-file=${cfg.apiserver.tlsCertFile}"} \
             ${optionalString (cfg.apiserver.tlsPrivateKeyFile!="")
-              "--tls_private_key_file=${cfg.apiserver.tlsPrivateKeyFile}"} \
+              "--tls-private-key-file=${cfg.apiserver.tlsPrivateKeyFile}"} \
             ${optionalString (cfg.apiserver.tokenAuth!=[])
-              "--token_auth_file=${tokenAuthFile}"} \
-            --authorization_mode=${cfg.apiserver.authorizationMode} \
+              "--token-auth-file=${tokenAuthFile}"} \
+            --authorization-mode=${cfg.apiserver.authorizationMode} \
             ${optionalString (cfg.apiserver.authorizationMode == "ABAC")
-              "--authorization_policy_file=${authorizationPolicyFile}"} \
-            --secure_port=${toString cfg.apiserver.securePort} \
-            --portal_net=${cfg.apiserver.portalNet} \
+              "--authorization-policy-file=${authorizationPolicyFile}"} \
+            --secure-port=${toString cfg.apiserver.securePort} \
+            --service-cluster-ip-range=${cfg.apiserver.portalNet} \
             --logtostderr=true \
-            --runtime_config=api/v1beta3 \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.apiserver.extraOpts}
           '';
           User = "kubernetes";
@@ -376,7 +403,7 @@ in {
     })
 
     (mkIf cfg.scheduler.enable {
-      systemd.services.kubernetes-scheduler = {
+      systemd.services.kube-scheduler = {
         description = "Kubernetes Scheduler Service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
@@ -386,7 +413,7 @@ in {
             --port=${toString cfg.scheduler.port} \
             --master=${cfg.scheduler.master} \
             --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.scheduler.extraOpts}
           '';
           User = "kubernetes";
@@ -395,7 +422,7 @@ in {
     })
 
     (mkIf cfg.controllerManager.enable {
-      systemd.services.kubernetes-controller-manager = {
+      systemd.services.kube-controller-manager = {
         description = "Kubernetes Controller Manager Service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
@@ -406,7 +433,7 @@ in {
             --master=${cfg.controllerManager.master} \
             --machines=${concatStringsSep "," cfg.controllerManager.machines} \
             --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.controllerManager.extraOpts}
           '';
           User = "kubernetes";
@@ -415,7 +442,7 @@ in {
     })
 
     (mkIf cfg.kubelet.enable {
-      systemd.services.kubernetes-kubelet = {
+      systemd.services.kubelet = {
         description = "Kubernetes Kubelet Service";
         wantedBy = [ "multi-user.target" ];
         requires = ["kubernetes-setup.service"];
@@ -423,17 +450,18 @@ in {
         script = ''
           export PATH="/bin:/sbin:/usr/bin:/usr/sbin:$PATH"
           exec ${cfg.package}/bin/kubelet \
-            --api_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.kubelet.apiServers}  \
+            --api-servers=${concatMapStringsSep "," (f: "http://${f}") cfg.kubelet.apiServers}  \
+            --register-node=${if cfg.kubelet.registerNode then "true" else "false"} \
             --address=${cfg.kubelet.address} \
             --port=${toString cfg.kubelet.port} \
-            --hostname_override=${cfg.kubelet.hostname} \
-            --allow_privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \
-            --root_dir=${cfg.dataDir} \
+            --hostname-override=${cfg.kubelet.hostname} \
+            --allow-privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \
+            --root-dir=${cfg.dataDir} \
             --cadvisor_port=${toString cfg.kubelet.cadvisorPort} \
             ${optionalString (cfg.kubelet.clusterDns != "")
-                ''--cluster_dns=${cfg.kubelet.clusterDns}''} \
+                ''--cluster-dns=${cfg.kubelet.clusterDns}''} \
             ${optionalString (cfg.kubelet.clusterDomain != "")
-                ''--cluster_domain=${cfg.kubelet.clusterDomain}''} \
+                ''--cluster-domain=${cfg.kubelet.clusterDomain}''} \
             --logtostderr=true \
             ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
             ${cfg.kubelet.extraOpts}
@@ -443,32 +471,53 @@ in {
     })
 
     (mkIf cfg.proxy.enable {
-      systemd.services.kubernetes-proxy = {
+      systemd.services.kube-proxy = {
         description = "Kubernetes Proxy Service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network-interfaces.target" "etcd.service" ];
         serviceConfig = {
           ExecStart = ''${cfg.package}/bin/kube-proxy \
             --master=${cfg.proxy.master} \
-            --bind_address=${cfg.proxy.address} \
+            --bind-address=${cfg.proxy.address} \
             --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.proxy.extraOpts}
           '';
         };
       };
     })
 
+    (mkIf cfg.kube2sky.enable {
+      systemd.services.kube2sky = {
+        description = "Kubernetes Dns Bridge Service";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" "skydns.service" "etcd.service" "kubernetes-apiserver.service" ];
+        serviceConfig = {
+          ExecStart = ''${cfg.package}/bin/kube2sky \
+            -etcd-server=http://${head cfg.etcdServers} \
+            -domain=${cfg.kube2sky.domain} \
+            -kube_master_url=http://${cfg.kube2sky.master} \
+            -logtostderr=true \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
+            ${cfg.kube2sky.extraOpts}
+          '';
+          User = "kubernetes";
+        };
+      };
+
+      services.skydns.enable = mkDefault true;
+      services.skydns.domain = mkDefault cfg.kubelet.clusterDomain;
+    })
+
     (mkIf (any (el: el == "master") cfg.roles) {
       services.kubernetes.apiserver.enable = mkDefault true;
       services.kubernetes.scheduler.enable = mkDefault true;
       services.kubernetes.controllerManager.enable = mkDefault true;
+      services.kubernetes.kube2sky.enable = mkDefault true;
     })
 
     (mkIf (any (el: el == "node") cfg.roles) {
       virtualisation.docker.enable = mkDefault true;
-      services.cadvisor.enable = mkDefault true;
-      services.cadvisor.port = mkDefault 4194;
       services.kubernetes.kubelet.enable = mkDefault true;
       services.kubernetes.proxy.enable = mkDefault true;
     })
diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix
index 29a81f066ab9..95d2aecfac7d 100644
--- a/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -50,14 +50,14 @@ in {
 
       port = mkOption {
         default = 8080;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           Specifies port number on which the jenkins HTTP interface listens. The default is 8080.
         '';
       };
 
       packages = mkOption {
-        default = [ pkgs.stdenv pkgs.git pkgs.jdk pkgs.openssh pkgs.nix ];
+        default = [ pkgs.stdenv pkgs.git pkgs.jdk config.programs.ssh.package pkgs.nix ];
         type = types.listOf types.package;
         description = ''
           Packages to add to PATH for the jenkins process.
diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix
index b57ccebae16e..08963f7aab7f 100644
--- a/nixos/modules/services/databases/influxdb.nix
+++ b/nixos/modules/services/databases/influxdb.nix
@@ -55,7 +55,7 @@ in
       enable = mkOption {
         default = false;
         description = "Whether to enable the influxdb server";
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       package = mkOption {
diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix
index b5919047cc11..1cdecedfc772 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -180,7 +180,8 @@ in
             chown -R ${cfg.user} ${cfg.pidDir}
 
             # Make the socket directory
-            mkdir -m 0755 -p /run/mysqld
+            mkdir -p /run/mysqld
+            chmod 0755 /run/mysqld
             chown -R ${cfg.user} /run/mysqld
           '';
 
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index 575034c93ab2..3cf22db7da2b 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -43,7 +43,7 @@ in {
     enable = mkOption {
       description = "Whether to enable neo4j.";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
     };
 
     package = mkOption {
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index de14c56f7971..97927055ce37 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -154,7 +154,7 @@ in
 
   config = mkIf config.services.postgresql.enable {
 
-    services.postgresql.authentication =
+    services.postgresql.authentication = mkAfter
       ''
         # Generated file; do not edit!
         local all all              ident ${optionalString pre84 "sameuser"}
@@ -186,8 +186,9 @@ in
         preStart =
           ''
             # Initialise the database.
-            if ! test -e ${cfg.dataDir}; then
+            if ! test -e ${cfg.dataDir}/PG_VERSION; then
                 mkdir -m 0700 -p ${cfg.dataDir}
+                rm -f ${cfg.dataDir}/*.conf
                 if [ "$(id -u)" = 0 ]; then
                   chown -R postgres ${cfg.dataDir}
                   su -s ${pkgs.stdenv.shell} postgres -c 'initdb -U root'
@@ -195,8 +196,6 @@ in
                   # For non-root operation.
                   initdb
                 fi
-                rm -f ${cfg.dataDir}/*.conf
-                touch "${cfg.dataDir}/.first_startup"
             fi
 
             ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf"
diff --git a/nixos/modules/services/desktops/gnome3/gnome-keyring.nix b/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
index 566c8a50e269..a8f1bcc28fbe 100644
--- a/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
+++ b/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
@@ -21,7 +21,7 @@ in
         description = ''
           Whether to enable GNOME Keyring daemon, a service designed to
           take care of the user's security credentials,
-          such as user names and passwordsa search engine.
+          such as user names and passwords.
         '';
       };
 
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 50588e449587..fc89de777e8e 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -28,7 +28,10 @@ let
   # Perform substitutions in all udev rules files.
   udevRules = stdenv.mkDerivation {
     name = "udev-rules";
+
     preferLocalBuild = true;
+    allowSubstitutes = false;
+
     buildCommand = ''
       mkdir -p $out
       shopt -s nullglob
diff --git a/nixos/modules/services/hardware/udisks2.nix b/nixos/modules/services/hardware/udisks2.nix
index f5b641c7378b..fd6d8886348e 100644
--- a/nixos/modules/services/hardware/udisks2.nix
+++ b/nixos/modules/services/hardware/udisks2.nix
@@ -46,7 +46,7 @@ with lib;
       serviceConfig = {
         Type = "dbus";
         BusName = "org.freedesktop.UDisks2";
-        ExecStart = "${pkgs.udisks2}/lib/udisks2/udisksd --no-debug";
+        ExecStart = "${pkgs.udisks2}/libexec/udisks2/udisksd --no-debug";
       };
     };
   };
diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix
index 1cd032ffa76b..6069262b4705 100644
--- a/nixos/modules/services/logging/logcheck.nix
+++ b/nixos/modules/services/logging/logcheck.nix
@@ -192,7 +192,7 @@ in
 
       extraGroups = mkOption {
         default = [];
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         example = [ "postdrop" "mongodb" ];
         description = ''
           Extra groups for the logcheck user, for example to be able to use sendmail,
diff --git a/nixos/modules/services/logging/rsyslogd.nix b/nixos/modules/services/logging/rsyslogd.nix
index d4b7aa809f00..1ea96b8f1325 100644
--- a/nixos/modules/services/logging/rsyslogd.nix
+++ b/nixos/modules/services/logging/rsyslogd.nix
@@ -66,7 +66,7 @@ in
       };
 
       extraParams = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [ ];
         example = [ "-m 0" ];
         description = ''
diff --git a/nixos/modules/services/logging/syslogd.nix b/nixos/modules/services/logging/syslogd.nix
index 325868079e22..a0f8e89fa691 100644
--- a/nixos/modules/services/logging/syslogd.nix
+++ b/nixos/modules/services/logging/syslogd.nix
@@ -83,7 +83,7 @@ in
       };
 
       extraParams = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [ ];
         example = [ "-m 0" ];
         description = ''
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index fbc4b1d7d8a8..a3e50b422920 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -24,7 +24,7 @@ in {
       };
 
       extraServerArgs = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [];
         example = [ "-v" "-P mta" ];
         description = ''
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index 839da7407ef9..29e0cf7a8829 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -78,7 +78,7 @@ let
 
       smtpd_use_tls = yes
 
-      recipientDelimiter = ${cfg.recipientDelimiter}
+      recipient_delimiter = ${cfg.recipientDelimiter}
     ''
     + optionalString (cfg.virtual != "") ''
       virtual_alias_maps = hash:/etc/postfix/virtual
@@ -369,30 +369,30 @@ in
 
         daemonType = "fork";
 
-        preStart =
-          ''
-            if ! [ -d /var/spool/postfix ]; then
-              ${pkgs.coreutils}/bin/mkdir -p /var/spool/mail /var/postfix/conf /var/postfix/queue
-            fi
+        preStart = ''
+          if ! [ -d /var/spool/postfix ]; then
+            ${pkgs.coreutils}/bin/mkdir -p /var/spool/mail /var/postfix/conf /var/postfix/queue
+          fi
 
-            ${pkgs.coreutils}/bin/chown -R ${user}:${group} /var/postfix
-            ${pkgs.coreutils}/bin/chown -R ${user}:${setgidGroup} /var/postfix/queue
-            ${pkgs.coreutils}/bin/chmod -R ug+rwX /var/postfix/queue
-            ${pkgs.coreutils}/bin/chown root:root /var/spool/mail
-            ${pkgs.coreutils}/bin/chmod a+rwxt /var/spool/mail
+          ${pkgs.coreutils}/bin/chown -R ${user}:${group} /var/postfix
+          ${pkgs.coreutils}/bin/chown -R ${user}:${setgidGroup} /var/postfix/queue
+          ${pkgs.coreutils}/bin/chmod -R ug+rwX /var/postfix/queue
+          ${pkgs.coreutils}/bin/chown root:root /var/spool/mail
+          ${pkgs.coreutils}/bin/chmod a+rwxt /var/spool/mail
+          ${pkgs.coreutils}/bin/ln -sf /var/spool/mail /var/mail
 
-            ln -sf "${pkgs.postfix}/share/postfix/conf/"* /var/postfix/conf
+          ln -sf "${pkgs.postfix}/etc/postfix/"* /var/postfix/conf
 
-            ln -sf ${aliasesFile} /var/postfix/conf/aliases
-            ln -sf ${virtualFile} /var/postfix/conf/virtual
-            ln -sf ${mainCfFile} /var/postfix/conf/main.cf
-            ln -sf ${masterCfFile} /var/postfix/conf/master.cf
+          ln -sf ${aliasesFile} /var/postfix/conf/aliases
+          ln -sf ${virtualFile} /var/postfix/conf/virtual
+          ln -sf ${mainCfFile} /var/postfix/conf/main.cf
+          ln -sf ${masterCfFile} /var/postfix/conf/master.cf
 
-            ${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases
-            ${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual
+          ${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases
+          ${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual
 
-            ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
-          '';
+          ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
+        '';
 
         preStop = ''
             ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop
diff --git a/nixos/modules/services/misc/apache-kafka.nix b/nixos/modules/services/misc/apache-kafka.nix
index 168615153fed..f6198e03bae5 100644
--- a/nixos/modules/services/misc/apache-kafka.nix
+++ b/nixos/modules/services/misc/apache-kafka.nix
@@ -33,7 +33,7 @@ in {
     enable = mkOption {
       description = "Whether to enable Apache Kafka.";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
     };
 
     brokerId = mkOption {
@@ -108,7 +108,7 @@ in {
         "-Djava.awt.headless=true"
         "-Djava.net.preferIPv4Stack=true"
       ];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       example = [
         "-Djava.net.preferIPv4Stack=true"
         "-Dcom.sun.management.jmxremote"
@@ -116,11 +116,19 @@ in {
       ];
     };
 
+    package = mkOption {
+      description = "The kafka package to use";
+
+      default = pkgs.apacheKafka;
+
+      type = types.package;
+    };
+
   };
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [pkgs.apacheKafka];
+    environment.systemPackages = [cfg.package];
 
     users.extraUsers = singleton {
       name = "apache-kafka";
@@ -136,13 +144,14 @@ in {
       serviceConfig = {
         ExecStart = ''
           ${pkgs.jre}/bin/java \
-            -cp "${pkgs.apacheKafka}/libs/*:${configDir}" \
+            -cp "${cfg.package}/libs/*:${configDir}" \
             ${toString cfg.jvmOptions} \
             kafka.Kafka \
             ${configDir}/server.properties
         '';
         User = "apache-kafka";
         PermissionsStartOnly = true;
+        SuccessExitStatus = "0 143";
       };
       preStart = ''
         mkdir -m 0700 -p ${concatStringsSep " " cfg.logDirs}
diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix
index 7094bb460895..98738b6497bf 100644
--- a/nixos/modules/services/misc/confd.nix
+++ b/nixos/modules/services/misc/confd.nix
@@ -17,7 +17,7 @@ let
 
 in {
   options.services.confd = {
-    enable = mkEnableOption "Whether to enable confd service.";
+    enable = mkEnableOption "confd service";
 
     backend = mkOption {
       description = "Confd config storage backend to use.";
diff --git a/nixos/modules/services/misc/devmon.nix b/nixos/modules/services/misc/devmon.nix
new file mode 100644
index 000000000000..7a1f7c2e079e
--- /dev/null
+++ b/nixos/modules/services/misc/devmon.nix
@@ -0,0 +1,28 @@
+{ pkgs, config, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.devmon;
+
+in {
+  options = {
+    services.devmon = {
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable devmon, an automatic device mounting daemon.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.devmon = {
+      description = "devmon automatic device mounting daemon";
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.udevil ];
+      serviceConfig.ExecStart = "${pkgs.udevil}/bin/devmon";
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index 48bb9e4293e7..c439efe9f8e7 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -67,7 +67,7 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService;
+    environment.systemPackages = [ pkgs.disnix pkgs.dysnomia ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService;
 
     services.dbus.enable = true;
     services.dbus.packages = [ pkgs.disnix ];
diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix
index d25fd13a77df..f472e530a70b 100644
--- a/nixos/modules/services/misc/docker-registry.nix
+++ b/nixos/modules/services/misc/docker-registry.nix
@@ -29,7 +29,7 @@ in {
 
     storagePath = mkOption {
       type = types.path;
-      default = "/var/lib/docker/registry";
+      default = "/var/lib/docker-registry";
       description = "Docker registry storage path.";
     };
 
@@ -61,14 +61,9 @@ in {
         User = "docker-registry";
         Group = "docker";
         PermissionsStartOnly = true;
+        WorkingDirectory = cfg.storagePath;
       };
 
-      preStart = ''
-        mkdir -p ${cfg.storagePath}
-        if [ "$(id -u)" = 0 ]; then
-          chown -R docker-registry:docker ${cfg.storagePath}
-        fi
-      '';
       postStart = ''
         until ${pkgs.curl}/bin/curl -s -o /dev/null 'http://${cfg.host}:${toString cfg.port}/'; do
           sleep 1;
@@ -77,6 +72,10 @@ in {
     };
 
     users.extraGroups.docker.gid = mkDefault config.ids.gids.docker;
-    users.extraUsers.docker-registry.uid = config.ids.uids.docker-registry;
+    users.extraUsers.docker-registry = {
+      createHome = true;
+      home = cfg.storagePath;
+      uid = config.ids.uids.docker-registry;
+    };
   };
 }
diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix
new file mode 100644
index 000000000000..56e735d7356b
--- /dev/null
+++ b/nixos/modules/services/misc/gitit.nix
@@ -0,0 +1,659 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.gitit;
+
+  homeDir = "/var/lib/gitit";
+
+  gititShared = with cfg.haskellPackages; gitit + "/share/" + pkgs.stdenv.system + "-" + ghc.name + "/" + gitit.pname + "-" + gitit.version;
+
+  gititWithPkgs = hsPkgs: extras: hsPkgs.ghcWithPackages (self: with self; [ gitit ] ++ (extras self));
+
+  gititSh = hsPkgs: extras: with pkgs; let
+    env = gititWithPkgs hsPkgs extras;
+  in writeScript "gitit" ''
+    #!${stdenv.shell}
+    cd $HOME
+    export PATH="${makeSearchPath "bin" (
+      [ git curl ] ++ (if cfg.pdfExport == "yes" then [texLiveFull] else [])
+      )}:$PATH";
+    export NIX_GHC="${env}/bin/ghc"
+    export NIX_GHCPKG="${env}/bin/ghc-pkg"
+    export NIX_GHC_DOCDIR="${env}/share/doc/ghc/html"
+    export NIX_GHC_LIBDIR=$( $NIX_GHC --print-libdir )
+    ${env}/bin/gitit -f ${configFile}
+  '';
+
+  gititOptions = let
+
+    yesNo = types.enum [ "yes" "no" ];
+
+  in {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Enable the gitit service.";
+      };
+
+      haskellPackages = mkOption {
+        default = pkgs.haskellPackages;
+        defaultText = "pkgs.haskellPackages";
+        example = literalExample "pkgs.haskell.packages.ghc784";
+        description = "haskellPackages used to build gitit and plugins.";
+      };
+
+      extraPackages = mkOption {
+        default = self: [];
+        example = literalExample ''
+          haskellPackages: [
+            haskellPackages.wreq
+          ]
+        '';
+        description = ''
+          Extra packages available to ghc when running gitit. The
+          value must be a function which receives the attrset defined
+          in <varname>haskellPackages</varname> as the sole argument.
+        '';
+      };
+
+      address = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        description = "IP address on which the web server will listen.";
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 5001;
+        description = "Port on which the web server will run.";
+      };
+
+      wikiTitle = mkOption {
+        type = types.str;
+        default = "Gitit!";
+        description = "The wiki title.";
+      };
+
+      repositoryType = mkOption {
+        type = types.enum ["git" "darcs" "mercurial"];
+        default = "git";
+        description = "Specifies the type of repository used for wiki content.";
+      };
+
+      repositoryPath = mkOption {
+        type = types.path;
+        default = homeDir + "/wiki";
+        description = ''
+          Specifies the path of the repository directory. If it does not
+          exist, gitit will create it on startup.
+        '';
+      };
+
+      requireAuthentication = mkOption {
+        type = types.enum [ "none" "modify" "read" ];
+        default = "modify";
+        description = ''
+          If 'none', login is never required, and pages can be edited
+          anonymously.  If 'modify', login is required to modify the wiki
+          (edit, add, delete pages, upload files).  If 'read', login is
+          required to see any wiki pages.
+        '';
+      };
+
+      authenticationMethod = mkOption {
+        type = types.enum [ "form" "http" "generic"];
+        default = "form";
+        description = ''
+          'form' means that users will be logged in and registered using forms
+          in the gitit web interface.  'http' means that gitit will assume that
+          HTTP authentication is in place and take the logged in username from
+          the "Authorization" field of the HTTP request header (in addition,
+          the login/logout and registration links will be suppressed).
+          'generic' means that gitit will assume that some form of
+          authentication is in place that directly sets REMOTE_USER to the name
+          of the authenticated user (e.g. mod_auth_cas on apache).  'rpx' means
+          that gitit will attempt to log in through https://rpxnow.com.  This
+          requires that 'rpx-domain', 'rpx-key', and 'base-url' be set below,
+          and that 'curl' be in the system path.
+        '';
+      };
+
+      userFile = mkOption {
+        type = types.path;
+        default = homeDir + "/gitit-users";
+        description = ''
+          Specifies the path of the file containing user login information.  If
+          it does not exist, gitit will create it (with an empty user list).
+          This file is not used if 'http' is selected for
+          authentication-method.
+        '';
+      };
+
+      sessionTimeout = mkOption {
+        type = types.int;
+        default = 60;
+        description = ''
+          Number of minutes of inactivity before a session expires.
+        '';
+      };
+
+      staticDir = mkOption {
+        type = types.path;
+        default = gititShared + "/data/static";
+        description = ''
+          Specifies the path of the static directory (containing javascript,
+          css, and images).  If it does not exist, gitit will create it and
+          populate it with required scripts, stylesheets, and images.
+        '';
+      };
+
+      defaultPageType = mkOption {
+        type = types.enum [ "markdown" "rst" "latex" "html" "markdown+lhs" "rst+lhs" "latex+lhs" ];
+        default = "markdown";
+        description = ''
+          Specifies the type of markup used to interpret pages in the wiki.
+          Possible values are markdown, rst, latex, html, markdown+lhs,
+          rst+lhs, and latex+lhs. (the +lhs variants treat the input as
+          literate Haskell. See pandoc's documentation for more details.) If
+          Markdown is selected, pandoc's syntax extensions (for footnotes,
+          delimited code blocks, etc.) will be enabled. Note that pandoc's
+          restructuredtext parser is not complete, so some pages may not be
+          rendered correctly if rst is selected. The same goes for latex and
+          html.
+        '';
+      };
+
+      math = mkOption {
+        type = types.enum [ "mathml" "raw" "mathjax" "jsmath" "google" ];
+        default = "mathml";
+        description = ''
+          Specifies how LaTeX math is to be displayed.  Possible values are
+          mathml, raw, mathjax, jsmath, and google.  If mathml is selected,
+          gitit will convert LaTeX math to MathML and link in a script,
+          MathMLinHTML.js, that allows the MathML to be seen in Gecko browsers,
+          IE + mathplayer, and Opera. In other browsers you may get a jumble of
+          characters.  If raw is selected, the LaTeX math will be displayed as
+          raw LaTeX math.  If mathjax is selected, gitit will link to the
+          remote mathjax script.  If jsMath is selected, gitit will link to the
+          script /js/jsMath/easy/load.js, and will assume that jsMath has been
+          installed into the js/jsMath directory.  This is the most portable
+          solution. If google is selected, the google chart API is called to
+          render the formula as an image. This requires a connection to google,
+          and might raise a technical or a privacy problem.
+        '';
+      };
+
+      mathJaxScript = mkOption {
+        type = types.str;
+        default = "https://d3eoax9i5htok0.cloudfront.net/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+        description = ''
+          Specifies the path to MathJax rendering script.  You might want to
+          use your own MathJax script to render formulas without Internet
+          connection or if you want to use some special LaTeX packages.  Note:
+          path specified there cannot be an absolute path to a script on your
+          hdd, instead you should run your (local if you wish) HTTP server
+          which will serve the MathJax.js script. You can easily (in four lines
+          of code) serve MathJax.js using
+          http://happstack.com/docs/crashcourse/FileServing.html Do not forget
+          the "http://" prefix (e.g. http://localhost:1234/MathJax.js).
+        '';
+      };
+
+      showLhsBirdTracks = mkOption {
+        type = yesNo;
+        default = "no";
+        description = ''
+          Specifies whether to show Haskell code blocks in "bird style", with
+          "> " at the beginning of each line.
+        '';
+      };
+
+      templatesDir = mkOption {
+        type = types.path;
+        default = gititShared + "/data/templates";
+        description = ''
+          Specifies the path of the directory containing page templates.  If it
+          does not exist, gitit will create it with default templates.  Users
+          may wish to edit the templates to customize the appearance of their
+          wiki. The template files are HStringTemplate templates.  Variables to
+          be interpolated appear between $\'s. Literal $\'s must be
+          backslash-escaped.
+        '';
+      };
+
+      logFile = mkOption {
+        type = types.path;
+        default = homeDir + "/gitit.log";
+        description = ''
+          Specifies the path of gitit's log file.  If it does not exist, gitit
+          will create it. The log is in Apache combined log format.
+        '';
+      };
+
+      logLevel = mkOption {
+        type = types.enum [ "DEBUG" "INFO" "NOTICE" "WARNING" "ERROR" "CRITICAL" "ALERT" "EMERGENCY" ];
+        default = "ERROR";
+        description = ''
+          Determines how much information is logged.  Possible values (from
+          most to least verbose) are DEBUG, INFO, NOTICE, WARNING, ERROR,
+          CRITICAL, ALERT, EMERGENCY.
+        '';
+      };
+
+      frontPage = mkOption {
+        type = types.str;
+        default = "Front Page";
+        description = ''
+          Specifies which wiki page is to be used as the wiki's front page.
+          Gitit creates a default front page on startup, if one does not exist
+          already.
+        '';
+      };
+
+      noDelete = mkOption {
+        type = types.str;
+        default = "Front Page, Help";
+        description = ''
+          Specifies pages that cannot be deleted through the web interface.
+          (They can still be deleted directly using git or darcs.) A
+          comma-separated list of page names.  Leave blank to allow every page
+          to be deleted.
+        '';
+      };
+
+      noEdit = mkOption {
+        type = types.str;
+        default = "Help";
+        description = ''
+          Specifies pages that cannot be edited through the web interface.
+          Leave blank to allow every page to be edited.
+        '';
+      };
+
+      defaultSummary = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Specifies text to be used in the change description if the author
+          leaves the "description" field blank.  If default-summary is blank
+          (the default), the author will be required to fill in the description
+          field.
+        '';
+      };
+
+      tableOfContents = mkOption {
+        type = yesNo;
+        default = "yes";
+        description = ''
+          Specifies whether to print a tables of contents (with links to
+          sections) on each wiki page.
+        '';
+      };
+
+      plugins = mkOption {
+        type = types.path;
+        default = gititShared + "/plugins/Dot.hs";
+        description = ''
+          Specifies a list of plugins to load.  Plugins may be specified either
+          by their path or by their module name.  If the plugin name starts
+          with Gitit.Plugin., gitit will assume that the plugin is an installed
+          module and will not try to find a source file.
+          Examples:
+          plugins: plugins/DotPlugin.hs, CapitalizeEmphasisPlugin.hs
+          plugins: plugins/DotPlugin
+          plugins: Gitit.Plugin.InterwikiLinks
+        '';
+      };
+
+      useCache = mkOption {
+        type = yesNo;
+        default = "no";
+        description = ''
+          Specifies whether to cache rendered pages.  Note that if use-feed is
+          selected, feeds will be cached regardless of the value of use-cache.
+        '';
+      };
+
+      cacheDir = mkOption {
+        type = types.path;
+        default = homeDir + "/cache";
+        description = "Path where rendered pages will be cached.";
+      };
+
+      maxUploadSize = mkOption {
+        type = types.str;
+        default = "1000K";
+        description = ''
+          Specifies an upper limit on the size (in bytes) of files uploaded
+          through the wiki's web interface.  To disable uploads, set this to
+          0K.  This will result in the uploads link disappearing and the
+          _upload url becoming inactive.
+        '';
+      };
+
+      maxPageSize = mkOption {
+        type = types.str;
+        default = "1000K";
+        description = "Specifies an upper limit on the size (in bytes) of pages.";
+      };
+
+      debugMode = mkOption {
+        type = yesNo;
+        default = "no";
+        description = "Causes debug information to be logged while gitit is running.";
+      };
+
+      compressResponses = mkOption {
+        type = yesNo;
+        default = "yes";
+        description = "Specifies whether HTTP responses should be compressed.";
+      };
+
+      mimeTypesFile = mkOption {
+        type = types.path;
+        default = "/etc/mime/types.info";
+        description = ''
+          Specifies the path of a file containing mime type mappings.  Each
+          line of the file should contain two fields, separated by whitespace.
+          The first field is the mime type, the second is a file extension.
+          For example:
+          video/x-ms-wmx                    wmx
+          If the file is not found, some simple defaults will be used.
+        '';
+      };
+
+      useReCaptcha = mkOption {
+        type = yesNo;
+        default = "no";
+        description = ''
+          If "yes", causes gitit to use the reCAPTCHA service
+          (http://recaptcha.net) to prevent bots from creating accounts.
+        '';
+      };
+
+      reCaptchaPrivateKey = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Specifies the private key for the reCAPTCHA service.  To get
+          these, you need to create an account at http://recaptcha.net.
+        '';
+      };
+
+      reCaptchaPublicKey = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Specifies the public key for the reCAPTCHA service.  To get
+          these, you need to create an account at http://recaptcha.net.
+        '';
+      };
+
+      accessQuestion = mkOption {
+        type = types.str;
+        default = "What is the code given to you by Ms. X?";
+        description = ''
+          Specifies a question that users must answer when they attempt to
+          create an account
+        '';
+      };
+
+      accessQuestionAnswers = mkOption {
+        type = types.str;
+        default = "RED DOG, red dog";
+        description = ''
+          Specifies a question that users must answer when they attempt to
+          create an account, along with a comma-separated list of acceptable
+          answers.  This can be used to institute a rudimentary password for
+          signing up as a user on the wiki, or as an alternative to reCAPTCHA.
+          Example:
+          access-question:  What is the code given to you by Ms. X?
+          access-question-answers:  RED DOG, red dog
+        '';
+      };
+
+      rpxDomain = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Specifies the domain and key of your RPX account.  The domain is just
+          the prefix of the complete RPX domain, so if your full domain is
+          'https://foo.rpxnow.com/', use 'foo' as the value of rpx-domain.
+        '';
+      };
+
+      rpxKey = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = "RPX account access key.";
+      };
+
+      mailCommand = mkOption {
+        type = types.str;
+        default = "sendmail %s";
+        description = ''
+          Specifies the command to use to send notification emails.  '%s' will
+          be replaced by the destination email address.  The body of the
+          message will be read from stdin.  If this field is left blank,
+          password reset will not be offered.
+        '';
+      };
+
+      resetPasswordMessage = mkOption {
+        type = types.lines;
+        default = ''
+          > From: gitit@$hostname$
+          > To: $useremail$
+          > Subject: Wiki password reset
+          >
+          > Hello $username$,
+          >
+          > To reset your password, please follow the link below:
+          > http://$hostname$:$port$$resetlink$
+          >
+          > Regards
+        '';
+        description = ''
+          Gives the text of the message that will be sent to the user should
+          she want to reset her password, or change other registration info.
+          The lines must be indented, and must begin with '>'.  The initial
+          spaces and '> ' will be stripped off.  $username$ will be replaced by
+          the user's username, $useremail$ by her email address, $hostname$ by
+          the hostname on which the wiki is running (as returned by the
+          hostname system call), $port$ by the port on which the wiki is
+          running, and $resetlink$ by the relative path of a reset link derived
+          from the user's existing hashed password. If your gitit wiki is being
+          proxied to a location other than the root path of $port$, you should
+          change the link to reflect this: for example, to
+          http://$hostname$/path/to/wiki$resetlink$ or
+          http://gitit.$hostname$$resetlink$
+        '';
+      };
+
+      useFeed = mkOption {
+        type = yesNo;
+        default = "no";
+        description = ''
+          Specifies whether an ATOM feed should be enabled (for the site and
+          for individual pages).
+        '';
+      };
+
+      baseUrl = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          The base URL of the wiki, to be used in constructing feed IDs and RPX
+          token_urls.  Set this if use-feed is 'yes' or authentication-method
+          is 'rpx'.
+        '';
+      };
+
+      absoluteUrls = mkOption {
+        type = yesNo;
+        default = "no";
+        description = ''
+          Make wikilinks absolute with respect to the base-url.  So, for
+          example, in a wiki served at the base URL '/wiki', on a page
+          Sub/Page, the wikilink '[Cactus]()' will produce a link to
+          '/wiki/Cactus' if absolute-urls is 'yes', and a relative link to
+          'Cactus' (referring to '/wiki/Sub/Cactus') if absolute-urls is 'no'.
+        '';
+      };
+
+      feedDays = mkOption {
+        type = types.int;
+        default = 14;
+        description = "Number of days to be included in feeds.";
+      };
+
+      feedRefreshTime = mkOption {
+        type = types.int;
+        default = 60;
+        description = "Number of minutes to cache feeds before refreshing.";
+      };
+
+      pdfExport = mkOption {
+        type = yesNo;
+        default = "no";
+        description = ''
+          If yes, PDF will appear in export options. PDF will be created using
+          pdflatex, which must be installed and in the path. Note that PDF
+          exports create significant additional server load.
+        '';
+      };
+
+      pandocUserData = mkOption {
+        type = with types; nullOr path;
+        default = null;
+        description = ''
+          If a directory is specified, this will be searched for pandoc
+          customizations. These can include a templates/ directory for custom
+          templates for various export formats, an S5 directory for custom S5
+          styles, and a reference.odt for ODT exports. If no directory is
+          specified, $HOME/.pandoc will be searched. See pandoc's README for
+          more information.
+        '';
+      };
+
+      xssSanitize = mkOption {
+        type = yesNo;
+        default = "yes";
+        description = ''
+          If yes, all HTML (including that produced by pandoc) is filtered
+          through xss-sanitize.  Set to no only if you trust all of your users.
+        '';
+      };
+  };
+
+  configFile = pkgs.writeText "gitit.conf" ''
+    address: ${cfg.address}
+    port: ${toString cfg.port}
+    wiki-title: ${cfg.wikiTitle}
+    repository-type: ${cfg.repositoryType}
+    repository-path: ${cfg.repositoryPath}
+    require-authentication: ${cfg.requireAuthentication}
+    authentication-method: ${cfg.authenticationMethod}
+    user-file: ${cfg.userFile}
+    session-timeout: ${toString cfg.sessionTimeout}
+    static-dir: ${cfg.staticDir}
+    default-page-type: ${cfg.defaultPageType}
+    math: ${cfg.math}
+    mathjax-script: ${cfg.mathJaxScript}
+    show-lhs-bird-tracks: ${cfg.showLhsBirdTracks}
+    templates-dir: ${cfg.templatesDir}
+    log-file: ${cfg.logFile}
+    log-level: ${cfg.logLevel}
+    front-page: ${cfg.frontPage}
+    no-delete: ${cfg.noDelete}
+    no-edit: ${cfg.noEdit}
+    default-summary: ${cfg.defaultSummary}
+    table-of-contents: ${cfg.tableOfContents}
+    plugins: ${cfg.plugins}
+    use-cache: ${cfg.useCache}
+    cache-dir: ${cfg.cacheDir}
+    max-upload-size: ${cfg.maxUploadSize}
+    max-page-size: ${cfg.maxPageSize}
+    debug-mode: ${cfg.debugMode}
+    compress-responses: ${cfg.compressResponses}
+    mime-types-file: ${cfg.mimeTypesFile}
+    use-recaptcha: ${cfg.useReCaptcha}
+    recaptcha-private-key: ${toString cfg.reCaptchaPrivateKey}
+    recaptcha-public-key: ${toString cfg.reCaptchaPublicKey}
+    access-question: ${cfg.accessQuestion}
+    access-question-answers: ${cfg.accessQuestionAnswers}
+    rpx-domain: ${toString cfg.rpxDomain}
+    rpx-key: ${toString cfg.rpxKey}
+    mail-command: ${cfg.mailCommand}
+    reset-password-message: ${cfg.resetPasswordMessage}
+    use-feed: ${cfg.useFeed}
+    base-url: ${toString cfg.baseUrl}
+    absolute-urls: ${cfg.absoluteUrls}
+    feed-days: ${toString cfg.feedDays}
+    feed-refresh-time: ${toString cfg.feedRefreshTime}
+    pdf-export: ${cfg.pdfExport}
+    pandoc-user-data: ${toString cfg.pandocUserData}
+    xss-sanitize: ${cfg.xssSanitize}
+  '';
+
+in
+
+{
+
+  options.services.gitit = gititOptions;
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers.gitit = {
+      group = config.users.extraGroups.gitit.name;
+      description = "Gitit user";
+      home = homeDir;
+      createHome = true;
+      uid = config.ids.uids.gitit;
+    };
+
+    users.extraGroups.gitit.gid = config.ids.gids.gitit;
+
+    systemd.services.gitit = let
+      uid = toString config.ids.uids.gitit;
+      gid = toString config.ids.gids.gitit;
+    in {
+      description = "Git and Pandoc Powered Wiki";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = with cfg; ''
+        chown ${uid}:${gid} -R ${homeDir}
+        for dir in ${repositoryPath} ${staticDir} ${templatesDir} ${cacheDir}
+        do
+          if [ ! -d $dir ]
+          then
+            mkdir -p $dir
+            find $dir -type d -exec chmod 0750 {} +
+            find $dir -type f -exec chmod 0640 {} +
+          fi
+        done
+        cd ${repositoryPath}
+        if [ ! -d  .git ]
+        then
+          ${pkgs.git}/bin/git init
+          ${pkgs.git}/bin/git config user.email "gitit@${config.networking.hostName}"
+          ${pkgs.git}/bin/git config user.name "gitit"
+          chown ${uid}:${gid} -R {repositoryPath}
+        fi
+        cd -
+      '';
+
+      serviceConfig = {
+        User = config.users.extraUsers.gitit.name;
+        Group = config.users.extraGroups.gitit.name;
+        ExecStart = with cfg; gititSh haskellPackages extraPackages;
+      };
+    };
+  };
+}
+
diff --git a/nixos/modules/services/misc/gitolite.nix b/nixos/modules/services/misc/gitolite.nix
index 16335c8aca73..5012bed0c422 100644
--- a/nixos/modules/services/misc/gitolite.nix
+++ b/nixos/modules/services/misc/gitolite.nix
@@ -75,7 +75,7 @@ in
       serviceConfig.Type = "oneshot";
       serviceConfig.RemainAfterExit = true;
 
-      path = [ pkgs.gitolite pkgs.git pkgs.perl pkgs.bash pkgs.openssh ];
+      path = [ pkgs.gitolite pkgs.git pkgs.perl pkgs.bash config.programs.ssh.package ];
       script = ''
         cd ${cfg.dataDir}
         mkdir -p .gitolite/logs
diff --git a/nixos/modules/services/misc/gpsd.nix b/nixos/modules/services/misc/gpsd.nix
index 4a677f33fa0c..a4a4c7b5d937 100644
--- a/nixos/modules/services/misc/gpsd.nix
+++ b/nixos/modules/services/misc/gpsd.nix
@@ -54,7 +54,7 @@ in
       };
 
       port = mkOption {
-        type = types.uniq types.int;
+        type = types.int;
         default = 2947;
         description = ''
           The port where to listen for TCP connections.
@@ -62,7 +62,7 @@ in
       };
 
       debugLevel = mkOption {
-        type = types.uniq types.int;
+        type = types.int;
         default = 0;
         description = ''
           The debugging level.
diff --git a/nixos/modules/services/misc/mediatomb.nix b/nixos/modules/services/misc/mediatomb.nix
index 23227548039c..40ec2831ff09 100644
--- a/nixos/modules/services/misc/mediatomb.nix
+++ b/nixos/modules/services/misc/mediatomb.nix
@@ -49,10 +49,10 @@ let
     </server>
     <import hidden-files="no">
       <scripting script-charset="UTF-8">
-        <common-script>/nix/store/cngbzn39vidd6jm4wgzxfafqll74ybfa-mediatomb-0.12.1/share/mediatomb/js/common.js</common-script>
-        <playlist-script>/nix/store/cngbzn39vidd6jm4wgzxfafqll74ybfa-mediatomb-0.12.1/share/mediatomb/js/playlists.js</playlist-script>
+        <common-script>${pkgs.mediatomb}/share/mediatomb/js/common.js</common-script>
+        <playlist-script>${pkgs.mediatomb}/share/mediatomb/js/playlists.js</playlist-script>
         <virtual-layout type="builtin">
-          <import-script>/nix/store/cngbzn39vidd6jm4wgzxfafqll74ybfa-mediatomb-0.12.1/share/mediatomb/js/import.js</import-script>
+          <import-script>${pkgs.mediatomb}/share/mediatomb/js/import.js</import-script>
         </virtual-layout>
       </scripting>
       <mappings>
@@ -230,6 +230,13 @@ in {
         '';
       };
 
+      interface = mkOption {
+        default = "";
+        description = ''
+          A specific interface to bind to.
+        '';
+      };
+
       uuid = mkOption {
         default = "fdfc8a4e-a3ad-4c1d-b43d-a2eedb03a687";
         description = ''
@@ -256,7 +263,7 @@ in {
       after = [ "local-fs.target" "network.target" ];
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.mediatomb ];
-      serviceConfig.ExecStart = "${pkgs.mediatomb}/bin/mediatomb -p ${toString cfg.port} ${if cfg.customCfg then "" else "-c ${mtConf}"} -m ${cfg.dataDir}";
+      serviceConfig.ExecStart = "${pkgs.mediatomb}/bin/mediatomb -p ${toString cfg.port} ${if cfg.interface!="" then "-e ${cfg.interface}" else ""} ${if cfg.customCfg then "" else "-c ${mtConf}"} -m ${cfg.dataDir}";
       serviceConfig.User = "${cfg.user}";
     };
 
diff --git a/nixos/modules/services/misc/mesos-master.nix b/nixos/modules/services/misc/mesos-master.nix
index 52f08c53b1dc..497646b2b418 100644
--- a/nixos/modules/services/misc/mesos-master.nix
+++ b/nixos/modules/services/misc/mesos-master.nix
@@ -13,7 +13,7 @@ in {
       enable = mkOption {
         description = "Whether to enable the Mesos Master.";
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       port = mkOption {
@@ -45,7 +45,7 @@ in {
           See https://mesos.apache.org/documentation/latest/configuration/
         '';
         default = [ "" ];
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         example = [ "--credentials=VALUE" ];
       };
 
diff --git a/nixos/modules/services/misc/mesos-slave.nix b/nixos/modules/services/misc/mesos-slave.nix
index 26fb3fdb00c9..8c29734813a1 100644
--- a/nixos/modules/services/misc/mesos-slave.nix
+++ b/nixos/modules/services/misc/mesos-slave.nix
@@ -12,6 +12,8 @@ let
   attribsArg = optionalString (cfg.attributes != {})
                               "--attributes=${mkAttributes cfg.attributes}";
 
+  containerizers = [ "mesos" ] ++ (optional cfg.withDocker "docker");
+
 in {
 
   options.services.mesos = {
@@ -19,11 +21,17 @@ in {
       enable = mkOption {
         description = "Whether to enable the Mesos Slave.";
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
+      };
+
+      ip = mkOption {
+        description = "IP address to listen on.";
+        default = "0.0.0.0";
+        type = types.string;
       };
 
       port = mkOption {
-        description = "Mesos Slave port";
+        description = "Port to listen on.";
         default = 5051;
         type = types.int;
       };
@@ -43,6 +51,12 @@ in {
         type = types.bool;
       };
 
+      withDocker = mkOption {
+        description = "Enable the docker containerizer.";
+        default = config.virtualisation.docker.enable;
+        type = types.bool;
+      };
+
       workDir = mkOption {
         description = "The Mesos work directory.";
         default = "/var/lib/mesos/slave";
@@ -56,7 +70,7 @@ in {
           See https://mesos.apache.org/documentation/latest/configuration/
         '';
         default = [ "" ];
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         example = [ "--gc_delay=3days" ];
       };
 
@@ -92,17 +106,18 @@ in {
       description = "Mesos Slave";
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" ];
-      environment.MESOS_CONTAINERIZERS = "docker,mesos";
+      environment.MESOS_CONTAINERIZERS = concatStringsSep "," containerizers;
       serviceConfig = {
         ExecStart = ''
           ${pkgs.mesos}/bin/mesos-slave \
+            --ip=${cfg.ip} \
             --port=${toString cfg.port} \
             --master=${cfg.master} \
-            ${optionalString cfg.withHadoop "--hadoop-home=${pkgs.hadoop}"} \
-            ${attribsArg} \
             --work_dir=${cfg.workDir} \
             --logging_level=${cfg.logLevel} \
-            --docker=${pkgs.docker}/libexec/docker/docker \
+            ${attribsArg} \
+            ${optionalString cfg.withHadoop "--hadoop-home=${pkgs.hadoop}"} \
+            ${optionalString cfg.withDocker "--docker=${pkgs.docker}/libexec/docker/docker"} \
             ${toString cfg.extraCmdLineOptions}
         '';
         PermissionsStartOnly = true;
diff --git a/nixos/modules/services/misc/mwlib.nix b/nixos/modules/services/misc/mwlib.nix
new file mode 100644
index 000000000000..a8edecff2a1e
--- /dev/null
+++ b/nixos/modules/services/misc/mwlib.nix
@@ -0,0 +1,259 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.mwlib;
+  pypkgs = pkgs.python27Packages;
+
+  inherit (pypkgs) python mwlib;
+
+  user = mkOption {
+    default = "nobody";
+    type = types.str;
+    description = "User to run as.";
+  };
+
+in
+{
+
+  options.services.mwlib = {
+
+    nserve = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to enable nserve. Nserve is a HTTP
+          server.  The Collection extension is talking to
+          that program directly.  Nserve uses at least
+          one qserve instance in order to distribute
+          and manage jobs.
+        '';
+      }; # nserve.enable
+
+      port = mkOption {
+        default = 8899;
+        type = types.int;
+        description = "Specify port to listen on.";
+      }; # nserve.port
+
+      address = mkOption {
+        default = "127.0.0.1";
+        type = types.str;
+        description = "Specify network interface to listen on.";
+      }; # nserve.address
+
+      qserve = mkOption {
+        default = [ "${cfg.qserve.address}:${toString cfg.qserve.port}" ];
+        type = types.listOf types.str;
+        description = "Register qserve instance.";
+      }; # nserve.qserve
+
+      inherit user;
+    }; # nserve
+
+    qserve = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          A job queue server used to distribute and manage
+          jobs. You should start one qserve instance
+          for each machine that is supposed to render pdf
+          files. Unless you’re operating the Wikipedia
+          installation, one machine should suffice.
+        '';
+      }; # qserve.enable
+
+      port = mkOption {
+        default = 14311;
+        type = types.int;
+        description = "Specify port to listen on.";
+      }; # qserve.port
+
+      address = mkOption {
+        default = "127.0.0.1";
+        type = types.str;
+        description = "Specify network interface to listen on.";
+      }; # qserve.address
+
+      datadir = mkOption {
+        default = "/var/lib/mwlib-qserve";
+        type = types.path;
+        description = "qserve data directory (FIXME: unused?)";
+      }; # qserve.datadir
+
+      allow = mkOption {
+        default = [ "127.0.0.1" ];
+        type = types.listOf types.str;
+        description = "List of allowed client IPs. Empty means any.";
+      }; # qserve.allow
+
+      inherit user;
+    }; # qserve
+
+    nslave = {
+      enable = mkOption {
+        default = cfg.qserve.enable;
+        type = types.bool;
+        description = ''
+          Pulls new jobs from exactly one qserve instance
+          and calls the zip and render programs
+          in order to download article collections and
+          convert them to different output formats. Nslave
+          uses a cache directory to store the generated
+          documents. Nslave also starts an internal http
+          server serving the content of the cache directory.
+        '';
+      }; # nslave.enable
+
+      cachedir = mkOption {
+        default = "/var/cache/mwlib-nslave";
+        type = types.path;
+        description = "Directory to store generated documents.";
+      }; # nslave.cachedir
+
+      numprocs = mkOption {
+        default = 10;
+        type = types.int;
+        description = "Number of parallel jobs to be executed.";
+      }; # nslave.numprocs
+
+      http = mkOption {
+        default = {};
+        description = ''
+          Internal http server serving the content of the cache directory.
+          You have to enable it, or use your own way for serving files
+          and set the http.url option accordingly.
+          '';
+        type = types.submodule ({
+          options = {
+            enable = mkOption {
+              default = true;
+              type = types.bool;
+              description = "Enable internal http server.";
+            }; # nslave.http.enable
+
+            port = mkOption {
+              default = 8898;
+              type = types.int;
+              description = "Port to listen to when serving files from cache.";
+            }; # nslave.http.port
+
+            address = mkOption {
+              default = "127.0.0.1";
+              type = types.str;
+              description = "Specify network interface to listen on.";
+            }; # nslave.http.address
+
+            url = mkOption {
+              default = "http://localhost:${toString cfg.nslave.http.port}/cache";
+              type = types.str;
+              description = ''
+                Specify URL for accessing generated files from cache.
+                The Collection extension of Mediawiki won't be able to
+                download files without it.
+                '';
+            }; # nslave.http.url
+          };
+        }); # types.submodule
+      }; # nslave.http
+
+      inherit user;
+    }; # nslave
+
+  }; # options.services
+
+  config = { 
+
+    systemd.services.mwlib-nserve = mkIf cfg.nserve.enable
+    {
+      description = "mwlib network interface";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "mwlib-qserve.service" ];
+
+      serviceConfig = {
+        ExecStart = concatStringsSep " " (
+          [
+            "${mwlib}/bin/nserve"
+            "--port ${toString cfg.nserve.port}"
+            "--interface ${cfg.nserve.address}"
+          ] ++ cfg.nserve.qserve
+        );
+        User = cfg.nserve.user;
+      };
+    }; # systemd.services.mwlib-nserve
+
+    systemd.services.mwlib-qserve = mkIf cfg.qserve.enable
+    {
+      description = "mwlib job queue server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "local-fs.target" ];
+
+      preStart = ''
+        mkdir -pv '${cfg.qserve.datadir}'
+        chown -Rc ${cfg.qserve.user}:`id -ng ${cfg.qserve.user}` '${cfg.qserve.datadir}'
+        chmod -Rc u=rwX,go= '${cfg.qserve.datadir}'
+      '';
+
+      serviceConfig = {
+        ExecStart = concatStringsSep " " (
+          [
+            "${mwlib}/bin/mw-qserve"
+            "-p ${toString cfg.qserve.port}"
+            "-i ${cfg.qserve.address}"
+            "-d ${cfg.qserve.datadir}"
+          ] ++ map (a: "-a ${a}") cfg.qserve.allow
+        );
+        User = cfg.qserve.user;
+        PermissionsStartOnly = true;
+      };
+    }; # systemd.services.mwlib-qserve
+
+    systemd.services.mwlib-nslave = mkIf cfg.nslave.enable
+    {
+      description = "mwlib worker";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "local-fs.target" ];
+
+      preStart = ''
+        mkdir -pv '${cfg.nslave.cachedir}'
+        chown -Rc ${cfg.nslave.user}:`id -ng ${cfg.nslave.user}` '${cfg.nslave.cachedir}'
+        chmod -Rc u=rwX,go= '${cfg.nslave.cachedir}'
+      '';
+
+      path = with pkgs; [ imagemagick pdftk ];
+      environment = {
+        PYTHONPATH = concatMapStringsSep ":"
+          (m: "${pypkgs.${m}}/lib/${python.libPrefix}/site-packages")
+          [ "mwlib-rl" "mwlib-ext" "pygments" "pyfribidi" ];
+      };
+
+      serviceConfig = {
+        ExecStart = concatStringsSep " " (
+          [
+            "${mwlib}/bin/nslave"
+            "--cachedir ${cfg.nslave.cachedir}"
+            "--numprocs ${toString cfg.nslave.numprocs}"
+            "--url ${cfg.nslave.http.url}"
+          ] ++ (
+            if cfg.nslave.http.enable then
+            [
+              "--serve-files-port ${toString cfg.nslave.http.port}"
+              "--serve-files-address ${cfg.nslave.http.address}"
+            ] else
+            [
+              "--no-serve-files"
+            ]
+          ));
+        User = cfg.nslave.user;
+        PermissionsStartOnly = true;
+      };
+    }; # systemd.services.mwlib-nslave
+
+  }; # config
+}
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 6d25fef45768..b5a8a7df9fca 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -47,6 +47,8 @@ let
         ${optionalString cfg.requireSignedBinaryCaches ''
           signed-binary-caches = *
         ''}
+        trusted-users = ${toString cfg.trustedUsers}
+        allowed-users = ${toString cfg.allowedUsers}
         $extraOptions
         END
       '';
@@ -141,7 +143,7 @@ in
         default = 0;
         description = ''
           Nix daemon process priority. This priority propagates to build processes.
-          0 is the default Unix process priority, 20 is the lowest.
+          0 is the default Unix process priority, 19 is the lowest.
         '';
       };
 
@@ -277,6 +279,36 @@ in
         '';
       };
 
+      trustedUsers = mkOption {
+        type = types.listOf types.str;
+        default = [ "root" ];
+        example = [ "root" "alice" "@wheel" ];
+        description = ''
+          A list of names of users that have additional rights when
+          connecting to the Nix daemon, such as the ability to specify
+          additional binary caches, or to import unsigned NARs. You
+          can also specify groups by prefixing them with
+          <literal>@</literal>; for instance,
+          <literal>@wheel</literal> means all users in the wheel
+          group.
+        '';
+      };
+
+      allowedUsers = mkOption {
+        type = types.listOf types.str;
+        default = [ "*" ];
+        example = [ "@wheel" "@builders" "alice" "bob" ];
+        description = ''
+          A list of names of users (separated by whitespace) that are
+          allowed to connect to the Nix daemon. As with
+          <option>nix.trustedUsers</option>, you can specify groups by
+          prefixing them with <literal>@</literal>. Also, you can
+          allow all users by specifying <literal>*</literal>. The
+          default is <literal>*</literal>. Note that trusted users are
+          always allowed to connect.
+        '';
+      };
+
     };
 
   };
@@ -296,14 +328,14 @@ in
       { enable = cfg.buildMachines != [];
         text =
           concatMapStrings (machine:
-            "${machine.sshUser}@${machine.hostName} "
-            + (if machine ? system then machine.system else concatStringsSep "," machine.systems)
-            + " ${machine.sshKey} ${toString machine.maxJobs} "
-            + (if machine ? speedFactor then toString machine.speedFactor else "1" )
+            "${if machine ? sshUser then "${machine.sshUser}@" else ""}${machine.hostName} "
+            + machine.system or (concatStringsSep "," machine.systems)
+            + " ${machine.sshKey or "-"} ${toString machine.maxJobs or 1} "
+            + toString (machine.speedFactor or 1)
             + " "
-            + (if machine ? supportedFeatures then concatStringsSep "," machine.supportedFeatures else "" )
+            + concatStringsSep "," (machine.mandatoryFeatures or [] ++ machine.supportedFeatures or [])
             + " "
-            + (if machine ? mandatoryFeatures then concatStringsSep "," machine.mandatoryFeatures else "" )
+            + concatStringsSep "," machine.mandatoryFeatures or []
             + "\n"
           ) cfg.buildMachines;
       };
@@ -313,7 +345,7 @@ in
     systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ];
 
     systemd.services.nix-daemon =
-      { path = [ nix pkgs.openssl pkgs.utillinux pkgs.openssh ]
+      { path = [ nix pkgs.openssl pkgs.utillinux config.programs.ssh.package ]
           ++ optionals cfg.distributedBuilds [ pkgs.gzip ];
 
         environment = cfg.envVars
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index f5f0a8c18161..de8bc71a2712 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -9,7 +9,7 @@ in
 {
   options = {
     services.plex = {
-      enable = mkEnableOption "Enable Plex Media Server";
+      enable = mkEnableOption "Plex Media Server";
 
       # FIXME: In order for this config option to work, symlinks in the Plex
       # package in the Nix store have to be changed to point to this directory.
diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix
index 059cc18733bb..eb6575887d58 100644
--- a/nixos/modules/services/misc/redmine.nix
+++ b/nixos/modules/services/misc/redmine.nix
@@ -154,7 +154,7 @@ in {
       environment.HOME = "${pkgs.redmine}/share/redmine";
       environment.REDMINE_LANG = "en";
       environment.GEM_HOME = "${pkgs.redmine}/share/redmine/vendor/bundle/ruby/1.9.1";
-      environment.GEM_PATH = "${bundler}/${bundler.ruby.gemPath}";
+      environment.GEM_PATH = "${pkgs.bundler}/${pkgs.bundler.ruby.gemPath}";
       path = with pkgs; [
         imagemagickBig
         subversion
diff --git a/nixos/modules/services/misc/ripple-data-api.nix b/nixos/modules/services/misc/ripple-data-api.nix
index 3b281449a256..dbca56b13335 100644
--- a/nixos/modules/services/misc/ripple-data-api.nix
+++ b/nixos/modules/services/misc/ripple-data-api.nix
@@ -35,7 +35,7 @@ let
 in {
   options = {
     services.rippleDataApi = {
-      enable = mkEnableOption "Whether to enable ripple data api.";
+      enable = mkEnableOption "ripple data api";
 
       port = mkOption {
         description = "Ripple data api port";
diff --git a/nixos/modules/services/misc/ripple-rest.nix b/nixos/modules/services/misc/ripple-rest.nix
new file mode 100644
index 000000000000..49520f68a50a
--- /dev/null
+++ b/nixos/modules/services/misc/ripple-rest.nix
@@ -0,0 +1,110 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.rippleRest;
+
+  configFile = pkgs.writeText "ripple-rest-config.json" (builtins.toJSON {
+    config_version = "2.0.3";
+    debug = cfg.debug;
+    port = cfg.port;
+    host = cfg.host;
+    ssl_enabled = cfg.ssl.enable;
+    ssl = {
+      key_path = cfg.ssl.keyPath;
+      cert_path = cfg.ssl.certPath;
+      reject_unathorized = cfg.ssl.rejectUnathorized;
+    };
+    db_path = cfg.dbPath;
+    max_transaction_fee = cfg.maxTransactionFee;
+    rippled_servers = cfg.rippleds;
+  });
+
+in {
+  options.services.rippleRest = {
+    enable = mkEnableOption "ripple rest";
+
+    debug = mkEnableOption "debug for ripple-rest";
+
+    host = mkOption {
+      description = "Ripple rest host.";
+      default = "localhost";
+      type = types.str;
+    };
+
+    port = mkOption {
+      description = "Ripple rest port.";
+      default = 5990;
+      type = types.int;
+    };
+
+    ssl = {
+      enable = mkEnableOption "ssl";
+
+      keyPath = mkOption {
+        description = "Path to the ripple rest key file.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+
+      certPath = mkOption {
+        description = "Path to the ripple rest cert file.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      rejectUnathorized = mkOption {
+        description = "Whether to reject unatohroized.";
+        default = true;
+        type = types.bool;
+      };
+    };
+
+    dbPath = mkOption {
+      description = "Ripple rest database path.";
+      default = "${cfg.dataDir}/ripple-rest.db";
+      type = types.path;
+    };
+
+    maxTransactionFee = mkOption {
+      description = "Ripple rest max transaction fee.";
+      default = 1000000;
+      type = types.int;
+    };
+
+    rippleds = mkOption {
+      description = "List of rippled servers.";
+      default = [
+        "wss://s1.ripple.com:443"
+      ];
+      type = types.listOf types.str;
+    };
+
+    dataDir = mkOption {
+      description = "Ripple rest data directory.";
+      default = "/var/lib/ripple-rest";
+      type = types.path;
+    };
+  };
+
+  config = mkIf (cfg.enable) {
+    systemd.services.ripple-rest = {
+      wantedBy = [ "multi-user.target"];
+      after = ["network.target" ];
+      environment.NODE_PATH="${pkgs.ripple-rest}/lib/node_modules/ripple-rest/node_modules";
+      serviceConfig = {
+        ExecStart = "${pkgs.nodejs}/bin/node ${pkgs.ripple-rest}/lib/node_modules/ripple-rest/server/server.js --config ${configFile}";
+        User = "ripple-rest";
+      };
+    };
+
+    users.extraUsers.postgres = {
+      name = "ripple-rest";
+      uid = config.ids.uids.ripple-rest;
+      createHome = true;
+      home = cfg.dataDir;
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix
index 03fcc003a404..d940c1bc900e 100644
--- a/nixos/modules/services/misc/rippled.nix
+++ b/nixos/modules/services/misc/rippled.nix
@@ -27,7 +27,7 @@ let
     protocol=${concatStringsSep "," p.protocol}
     ${optionalString (p.user != "") "user=${p.user}"}
     ${optionalString (p.password != "") "user=${p.password}"}
-    admin=${if p.admin then "allow" else "no"}
+    admin=${concatStringsSep "," p.admin}
     ${optionalString (p.ssl.key != null) "ssl_key=${p.ssl.key}"}
     ${optionalString (p.ssl.cert != null) "ssl_cert=${p.ssl.cert}"}
     ${optionalString (p.ssl.chain != null) "ssl_chain=${p.ssl.chain}"}
@@ -118,9 +118,9 @@ let
       };
 
       admin = mkOption {
-	description = "Controls whether or not administrative commands are allowed.";
-	type = types.bool;
-	default = false;
+	description = "A comma-separated list of admin IP addresses.";
+	type = types.listOf types.str;
+	default = ["127.0.0.1"];
       };
 
       ssl = {
@@ -156,7 +156,7 @@ let
   dbOptions = {
     type = mkOption {
       description = "Rippled database type.";
-      type = types.enum ["rocksdb" "nudb" "sqlite" "hyperleveldb"];
+      type = types.enum ["rocksdb" "nudb"];
       default = "rocksdb";
     };
 
@@ -202,7 +202,7 @@ in
 
   options = {
     services.rippled = {
-      enable = mkEnableOption "Whether to enable rippled";
+      enable = mkEnableOption "rippled";
 
       package = mkOption {
 	description = "Which rippled package to use.";
@@ -217,7 +217,7 @@ in
 	default = {
 	  rpc = {
 	    port = 5005;
-	    admin = true;
+	    admin = ["127.0.0.1"];
 	    protocol = ["http"];
 	  };
 
@@ -373,7 +373,7 @@ in
       };
 
       statsd = {
-        enable = mkEnableOption "Whether enable statsd monitoring for rippled";
+        enable = mkEnableOption "statsd monitoring for rippled";
 
         address = mkOption {
           description = "The UDP address and port of the listening StatsD server.";
diff --git a/nixos/modules/services/misc/subsonic.nix b/nixos/modules/services/misc/subsonic.nix
new file mode 100644
index 000000000000..3e1a2e8fbb51
--- /dev/null
+++ b/nixos/modules/services/misc/subsonic.nix
@@ -0,0 +1,157 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.subsonic;
+  homeDir = "/var/subsonic";
+
+in
+{
+  options = {
+    services.subsonic = {
+      enable = mkEnableOption "Subsonic daemon";
+
+      home = mkOption {
+        type = types.path;
+        default = "${homeDir}";
+        description = ''
+          The directory where Subsonic will create files.
+          Make sure it is writable.
+        '';
+      };
+
+      host = mkOption {
+        type = types.string;
+        default = "0.0.0.0";
+        description = ''
+          The host name or IP address on which to bind Subsonic.
+          Only relevant if you have multiple network interfaces and want
+          to make Subsonic available on only one of them. The default value
+          will bind Subsonic to all available network interfaces.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 4040;
+        description = ''
+          The port on which Subsonic will listen for
+          incoming HTTP traffic. Set to 0 to disable.
+        '';
+      };
+
+      httpsPort = mkOption {
+        type = types.int;
+        default = 0;
+        description = ''
+          The port on which Subsonic will listen for
+          incoming HTTPS traffic. Set to 0 to disable.
+        '';
+      };
+
+      contextPath = mkOption {
+        type = types.path;
+        default = "/";
+        description = ''
+          The context path, i.e., the last part of the Subsonic
+          URL. Typically '/' or '/subsonic'. Default '/'
+        '';
+      };
+
+      maxMemory = mkOption {
+        type = types.int;
+        default = 100;
+        description = ''
+          The memory limit (max Java heap size) in megabytes.
+          Default: 100
+        '';
+      };
+
+      defaultMusicFolder = mkOption {
+        type = types.path;
+        default = "/var/music";
+        description = ''
+          Configure Subsonic to use this folder for music.  This option
+          only has effect the first time Subsonic is started.
+        '';
+      };
+
+      defaultPodcastFolder = mkOption {
+        type = types.path;
+        default = "/var/music/Podcast";
+        description = ''
+          Configure Subsonic to use this folder for Podcasts.  This option
+          only has effect the first time Subsonic is started.
+        '';
+      };
+
+      defaultPlaylistFolder = mkOption {
+        type = types.path;
+        default = "/var/playlists";
+        description = ''
+          Configure Subsonic to use this folder for playlists.  This option
+          only has effect the first time Subsonic is started.
+        '';
+      };
+
+      transcoders = mkOption {
+        type = types.listOf types.path;
+        default = [ "${pkgs.ffmpeg}/bin/ffmpeg" ];
+        description = ''
+          List of paths to transcoder executables that should be accessible
+          from Subsonic. Symlinks will be created to each executable inside
+          ${cfg.home}/transcoders.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.subsonic = {
+      description = "Personal media streamer";
+      after = [ "local-fs.target" "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = ''
+          ${pkgs.jre}/bin/java -Xmx${toString cfg.maxMemory}m \
+            -Dsubsonic.home=${cfg.home} \
+            -Dsubsonic.host=${cfg.host} \
+            -Dsubsonic.port=${toString cfg.port} \
+            -Dsubsonic.httpsPort=${toString cfg.httpsPort} \
+            -Dsubsonic.contextPath=${cfg.contextPath} \
+            -Dsubsonic.defaultMusicFolder=${cfg.defaultMusicFolder} \
+            -Dsubsonic.defaultPodcastFolder=${cfg.defaultPodcastFolder} \
+            -Dsubsonic.defaultPlaylistFolder=${cfg.defaultPlaylistFolder} \
+            -Djava.awt.headless=true \
+            -verbose:gc \
+            -jar ${pkgs.subsonic}/subsonic-booter-jar-with-dependencies.jar
+        '';
+        # Install transcoders.
+        ExecStartPre = ''
+          ${pkgs.coreutils}/bin/rm -rf ${cfg.home}/transcode ; \
+          ${pkgs.coreutils}/bin/mkdir -p ${cfg.home}/transcode ; \
+          ${pkgs.bash}/bin/bash -c ' \
+            for exe in "$@"; do \
+              ${pkgs.coreutils}/bin/ln -sf "$exe" ${cfg.home}/transcode; \
+            done' IGNORED_FIRST_ARG ${toString cfg.transcoders}
+        '';
+        # Needed for Subsonic to find subsonic.war.
+        WorkingDirectory = "${pkgs.subsonic}";
+        Restart = "always";
+        User = "subsonic";
+        UMask = "0022";
+      };
+    };
+
+    users.extraUsers.subsonic = {
+      description = "Subsonic daemon user";
+      home = homeDir;
+      createHome = true;
+      group = "subsonic";
+      uid = config.ids.uids.subsonic;
+    };
+
+    users.extraGroups.subsonic.gid = config.ids.gids.subsonic;
+  };
+}
diff --git a/nixos/modules/services/misc/sundtek.nix b/nixos/modules/services/misc/sundtek.nix
new file mode 100644
index 000000000000..8438ef79904f
--- /dev/null
+++ b/nixos/modules/services/misc/sundtek.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.sundtek;
+
+in
+{
+  options.services.sundtek = {
+    enable = mkEnableOption "Sundtek driver";
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.sundtek ];
+
+    systemd.services.sundtek = {
+      description = "Sundtek driver";
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        Type = "oneshot";
+        ExecStart = ''
+          ${pkgs.sundtek}/bin/mediasrv -d -v -p ${pkgs.sundtek}/bin ;\
+          ${pkgs.sundtek}/bin/mediaclient --start=5 --wait-for-devices
+          '';
+        ExecStop = "${pkgs.sundtek}/bin/mediaclient --shutdown";
+        RemainAfterExit = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/zookeeper.nix b/nixos/modules/services/misc/zookeeper.nix
index 47675b8876cc..4ce692b6f6a5 100644
--- a/nixos/modules/services/misc/zookeeper.nix
+++ b/nixos/modules/services/misc/zookeeper.nix
@@ -27,7 +27,7 @@ in {
     enable = mkOption {
       description = "Whether to enable Zookeeper.";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
     };
 
     port = mkOption {
@@ -94,7 +94,7 @@ in {
     extraCmdLineOptions = mkOption {
       description = "Extra command line options for the Zookeeper launcher.";
       default = [ "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       example = [ "-Djava.net.preferIPv4Stack=true" "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ];
     };
 
diff --git a/nixos/modules/services/monitoring/apcupsd.nix b/nixos/modules/services/monitoring/apcupsd.nix
index ffa7be7dd301..9abd6e9ab641 100644
--- a/nixos/modules/services/monitoring/apcupsd.nix
+++ b/nixos/modules/services/monitoring/apcupsd.nix
@@ -39,7 +39,7 @@ let
 
   shellCmdsForEventScript = eventname: commands: ''
     echo "#!${pkgs.stdenv.shell}" > "$out/${eventname}"
-    echo "${commands}" >> "$out/${eventname}"
+    echo '${commands}' >> "$out/${eventname}"
     chmod a+x "$out/${eventname}"
   '';
 
@@ -74,7 +74,7 @@ in
 
       enable = mkOption {
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
         description = ''
           Whether to enable the APC UPS daemon. apcupsd monitors your UPS and
           permits orderly shutdown of your computer in the event of a power
diff --git a/nixos/modules/services/monitoring/das_watchdog.nix b/nixos/modules/services/monitoring/das_watchdog.nix
new file mode 100644
index 000000000000..6e2653836d5e
--- /dev/null
+++ b/nixos/modules/services/monitoring/das_watchdog.nix
@@ -0,0 +1,34 @@
+# A general watchdog for the linux operating system that should run in the
+# background at all times to ensure a realtime process won't hang the machine
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inherit (pkgs) das_watchdog;
+
+in {
+  ###### interface
+
+  options = {
+    services.das_watchdog.enable = mkEnableOption "realtime watchdog";
+  };
+
+  ###### implementation
+
+  config = mkIf config.services.das_watchdog.enable {
+    environment.systemPackages = [ das_watchdog ];
+    systemd.services.das_watchdog = {
+      description = "Watchdog to ensure a realtime process won't hang the machine";
+      after = [ "multi-user.target" "sound.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "root";
+        Type = "oneshot";
+        ExecStart = "${das_watchdog}/bin/das_watchdog";
+        RemainAfterExit = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/dd-agent.nix b/nixos/modules/services/monitoring/dd-agent.nix
index dc51a7c74866..3e90393a662d 100644
--- a/nixos/modules/services/monitoring/dd-agent.nix
+++ b/nixos/modules/services/monitoring/dd-agent.nix
@@ -23,6 +23,7 @@ let
     # proxy_password: password
 
     # tags: mytag0, mytag1
+    ${optionalString (cfg.tags != null ) "tags: ${concatStringsSep "," cfg.tags }"}
 
     # collect_ec2_tags: no
     # recent_point_threshold: 30
@@ -80,6 +81,13 @@ in {
       type = types.str;
     };
 
+    tags = mkOption {
+      description = "The tags to mark this Datadog agent";
+      example = [ "test" "service" ];
+      default = null;
+      type = types.nullOr (types.listOf types.str);
+    };
+
     hostname = mkOption {
       description = "The hostname to show in the Datadog dashboard (optional)";
       default = null;
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
new file mode 100644
index 000000000000..6a1799dedc8e
--- /dev/null
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -0,0 +1,335 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.grafana;
+
+  b2s = val: if val then "true" else "false";
+
+  cfgFile = pkgs.writeText "grafana.ini" ''
+    app_name = grafana
+    app_mode = production
+
+    [server]
+    ; protocol (http or https)
+    protocol = ${cfg.protocol}
+    ; the ip address to bind to, empty will bind to all interfaces
+    http_addr = ${cfg.addr}
+    ; the http port  to use
+    http_port = ${toString cfg.port}
+    ; The public facing domain name used to access grafana from a browser
+    domain = ${cfg.domain}
+    ; the full public facing url
+    root_url = ${cfg.rootUrl}
+    router_logging = false
+    ; the path relative to the binary where the static (html/js/css) files are placed
+    static_root_path = ${cfg.staticRootPath}
+    ; enable gzip
+    enable_gzip = false
+    ; https certs & key file
+    cert_file = ${cfg.certFile}
+    cert_key = ${cfg.certKey}
+
+    [analytics]
+    # Server reporting, sends usage counters to stats.grafana.org every 24 hours.
+    # No ip addresses are being tracked, only simple counters to track
+    # running instances, dashboard and error counts. It is very helpful to us.
+    # Change this option to false to disable reporting.
+    reporting_enabled = true
+    ; Google Analytics universal tracking code, only enabled if you specify an id here
+    google_analytics_ua_id =
+
+    [database]
+    ; Either "mysql", "postgres" or "sqlite3", it's your choice
+    type = ${cfg.database.type}
+    host = ${cfg.database.host}
+    name = ${cfg.database.name}
+    user = ${cfg.database.user}
+    password = ${cfg.database.password}
+    ; For "postgres" only, either "disable", "require" or "verify-full"
+    ssl_mode = disable
+    ; For "sqlite3" only
+    path = ${cfg.database.path}
+
+    [session]
+    ; Either "memory", "file", "redis", "mysql", default is "memory"
+    provider = file
+    ; Provider config options
+    ; memory: not have any config yet
+    ; file: session file path, e.g. `data/sessions`
+    ; redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
+    ; mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
+    provider_config = data/sessions
+    ; Session cookie name
+    cookie_name = grafana_sess
+    ; If you use session in https only, default is false
+    cookie_secure = false
+    ; Session life time, default is 86400
+    session_life_time = 86400
+    ; session id hash func, Either "sha1", "sha256" or "md5" default is sha1
+    session_id_hashfunc = sha1
+    ; Session hash key, default is use random string
+    session_id_hashkey =
+
+    [security]
+    ; default admin user, created on startup
+    admin_user = ${cfg.security.adminUser}
+    ; default admin password, can be changed before first start of grafana,  or in profile settings
+    admin_password = ${cfg.security.adminPassword}
+    ; used for signing
+    secret_key = ${cfg.security.secretKey}
+    ; Auto-login remember days
+    login_remember_days = 7
+    cookie_username = grafana_user
+    cookie_remember_name = grafana_remember
+
+    [users]
+    ; disable user signup / registration
+    allow_sign_up = ${b2s cfg.users.allowSignUp}
+    ; Allow non admin users to create organizations
+    allow_org_create = ${b2s cfg.users.allowOrgCreate}
+    # Set to true to automatically assign new users to the default organization (id 1)
+    auto_assign_org = ${b2s cfg.users.autoAssignOrg}
+    ; Default role new users will be automatically assigned (if disabled above is set to true)
+    auto_assign_org_role = ${cfg.users.autoAssignOrgRole}
+
+    [auth.anonymous]
+    ; enable anonymous access
+    enabled = ${b2s cfg.auth.anonymous.enable}
+    ; specify organization name that should be used for unauthenticated users
+    org_name = Main Org.
+    ; specify role for unauthenticated users
+    org_role = Viewer
+
+    [auth.github]
+    enabled = false
+    client_id = some_id
+    client_secret = some_secret
+    scopes = user:email
+    auth_url = https://github.com/login/oauth/authorize
+    token_url = https://github.com/login/oauth/access_token
+
+    [auth.google]
+    enabled = false
+    client_id = some_client_id
+    client_secret = some_client_secret
+    scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
+    auth_url = https://accounts.google.com/o/oauth2/auth
+    token_url = https://accounts.google.com/o/oauth2/token
+
+    [log]
+    root_path = data/log
+    ; Either "console", "file", default is "console"
+    ; Use comma to separate multiple modes, e.g. "console, file"
+    mode = console
+    ; Buffer length of channel, keep it as it is if you don't know what it is.
+    buffer_len = 10000
+    ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
+    level = Info
+
+    ; For "console" mode only
+    [log.console]
+    level =
+
+    ; For "file" mode only
+    [log.file]
+    level =
+    ; This enables automated log rotate(switch of following options), default is true
+    log_rotate = true
+    ; Max line number of single file, default is 1000000
+    max_lines = 1000000
+    ; Max size shift of single file, default is 28 means 1 << 28, 256MB
+    max_lines_shift = 28
+    ; Segment log daily, default is true
+    daily_rotate = true
+    ; Expired days of log file(delete after max days), default is 7
+    max_days = 7
+
+    [event_publisher]
+    enabled = false
+    rabbitmq_url = amqp://localhost/
+    exchange = grafana_events
+  '';
+
+in {
+  options.services.grafana = {
+    enable = mkEnableOption "grafana";
+
+    protocol = mkOption {
+      description = "Which protocol to listen.";
+      default = "http";
+      type = types.enum ["http" "https"];
+    };
+
+    addr = mkOption {
+      description = "Listening address.";
+      default = "127.0.0.1";
+      type = types.str;
+    };
+
+    port = mkOption {
+      description = "Listening port.";
+      default = 3000;
+      type = types.int;
+    };
+
+    domain = mkOption {
+      description = "The public facing domain name used to access grafana from a browser.";
+      default = "localhost";
+      type = types.str;
+    };
+
+    rootUrl = mkOption {
+      description = "Full public facing url.";
+      default = "%(protocol)s://%(domain)s:%(http_port)s/";
+      type = types.str;
+    };
+
+    certFile = mkOption {
+      description = "Cert file for ssl.";
+      default = "";
+      type = types.str;
+    };
+
+    certKey = mkOption {
+      description = "Cert key for ssl.";
+      default = "";
+      type = types.str;
+    };
+
+    staticRootPath = mkOption {
+      description = "Root path for static assets.";
+      default = "${cfg.package}/share/go/src/github.com/grafana/grafana/public";
+      type = types.str;
+    };
+
+    package = mkOption {
+      description = "Package to use.";
+      default = pkgs.goPackages.grafana;
+      type = types.package;
+    };
+
+    dataDir = mkOption {
+      description = "Data directory.";
+      default = "/var/lib/grafana";
+      type = types.path;
+    };
+
+    database = {
+      type = mkOption {
+        description = "Database type.";
+        default = "sqlite3";
+        type = types.enum ["mysql" "sqlite3" "postgresql"];
+      };
+
+      host = mkOption {
+        description = "Database host.";
+        default = "127.0.0.1:3306";
+        type = types.str;
+      };
+
+      name = mkOption {
+        description = "Database name.";
+        default = "grafana";
+        type = types.str;
+      };
+
+      user = mkOption {
+        description = "Database user.";
+        default = "root";
+        type = types.str;
+      };
+
+      password = mkOption {
+        description = "Database password.";
+        default = "";
+        type = types.str;
+      };
+
+      path = mkOption {
+        description = "Database path.";
+        default = "${cfg.dataDir}/data/grafana.db";
+        type = types.path;
+      };
+    };
+
+    security = {
+      adminUser = mkOption {
+        description = "Default admin username.";
+        default = "admin";
+        type = types.str;
+      };
+
+      adminPassword = mkOption {
+        description = "Default admin password.";
+        default = "admin";
+        type = types.str;
+      };
+
+      secretKey = mkOption {
+        description = "Secret key used for signing.";
+        default = "SW2YcwTIb9zpOOhoPsMm";
+        type = types.str;
+      };
+    };
+
+    users = {
+      allowSignUp = mkOption {
+        description = "Disable user signup / registration";
+        default = false;
+        type = types.bool;
+      };
+
+      allowOrgCreate = mkOption {
+        description = "Whether user is allowed to create organizations.";
+        default = false;
+        type = types.bool;
+      };
+
+      autoAssignOrg = mkOption {
+        description = "Whether to automatically assign new users to default org.";
+        default = true;
+        type = types.bool;
+      };
+
+      autoAssignOrgRole = mkOption {
+        description = "Default role new users will be auto assigned.";
+        default = "Viewer";
+        type = types.enum ["Viewer" "Editor"];
+      };
+    };
+
+    auth.anonymous = {
+      enable = mkOption {
+        description = "Whether to allow anonymous access";
+        default = false;
+        type = types.bool;
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    warnings = [
+      "Grafana passwords will be stored as plaintext in nix store!"
+    ];
+
+    systemd.services.grafana = {
+      description = "Grafana Service Daemon";
+      wantedBy = ["multi-user.target"];
+      after = ["networking.target"];
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/grafana --config ${cfgFile} web";
+        WorkingDirectory = cfg.dataDir;
+        User = "grafana";
+      };
+    };
+
+    users.extraUsers.grafana = {
+      uid = config.ids.uids.grafana;
+      description = "Grafana user";
+      home = cfg.dataDir;
+      createHome = true;
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index bbbbcbccb9be..ac0fba597a04 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -67,7 +67,7 @@ in {
       enable = mkOption {
         description = "Whether to enable graphite web frontend.";
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       host = mkOption {
@@ -95,7 +95,7 @@ in {
           <link xlink:href="http://graphite-api.readthedocs.org/en/latest/"/>
         '';
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       finders = mkOption {
@@ -177,7 +177,7 @@ in {
       enableCache = mkOption {
         description = "Whether to enable carbon cache, the graphite storage daemon.";
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       storageAggregation = mkOption {
@@ -234,7 +234,7 @@ in {
       enableRelay = mkOption {
         description = "Whether to enable carbon relay, the carbon replication and sharding service.";
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       relayRules = mkOption {
@@ -251,7 +251,7 @@ in {
       enableAggregator = mkOption {
         description = "Whether to enable carbon agregator, the carbon buffering service.";
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       aggregationRules = mkOption {
@@ -269,7 +269,7 @@ in {
       enable = mkOption {
         description = "Whether to enable seyren service.";
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       port = mkOption {
@@ -319,7 +319,7 @@ in {
           <link xlink:href="https://github.com/seatgeek/graphite-pager"/>
         '';
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
       };
 
       redisUrl = mkOption {
@@ -354,6 +354,16 @@ in {
         type = types.lines;
       };
     };
+
+    beacon = {
+      enable = mkEnableOption "graphite beacon";
+
+      config = mkOption {
+        description = "Graphite beacon configuration.";
+        default = {};
+        type = types.attrs;
+      };
+    };
   };
 
   ###### implementation
@@ -535,10 +545,25 @@ in {
       environment.systemPackages = [ pkgs.pythonPackages.graphite_pager ];
     })
 
+    (mkIf cfg.beacon.enable {
+      systemd.services.graphite-beacon = {
+        description = "Grpahite Beacon Alerting Daemon";
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          ExecStart = ''
+            ${pkgs.pythonPackages.graphite_beacon}/bin/graphite-beacon \
+              --config ${pkgs.writeText "graphite-beacon.json" (builtins.toJSON cfg.beacon.config)}
+          '';
+          User = "graphite";
+          Group = "graphite";
+        };
+      };
+    })
+
     (mkIf (
       cfg.carbon.enableCache || cfg.carbon.enableAggregator || cfg.carbon.enableRelay ||
       cfg.web.enable || cfg.api.enable ||
-      cfg.seyren.enable || cfg.pager.enable
+      cfg.seyren.enable || cfg.pager.enable || cfg.beacon.enable
      ) {
       users.extraUsers = singleton {
         name = "graphite";
diff --git a/nixos/modules/services/monitoring/riemann-tools.nix b/nixos/modules/services/monitoring/riemann-tools.nix
new file mode 100644
index 000000000000..ce277f09464a
--- /dev/null
+++ b/nixos/modules/services/monitoring/riemann-tools.nix
@@ -0,0 +1,62 @@
+{ config, pkgs, lib, ... }:
+
+with pkgs;
+with lib;
+
+let
+
+  cfg = config.services.riemann-tools;
+
+  riemannHost = "${cfg.riemannHost}";
+
+  healthLauncher = writeScriptBin "riemann-health" ''
+    #!/bin/sh
+    exec ${pkgs.riemann-tools}/bin/riemann-health --host ${riemannHost}
+  '';
+
+
+in {
+
+  options = {
+
+    services.riemann-tools = {
+      enableHealth = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the riemann-health daemon.
+        '';
+      };
+      riemannHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = ''
+          Address of the host riemann node. Defaults to localhost.
+        '';
+      };
+    };
+
+  };
+
+  config = mkIf cfg.enableHealth {
+
+    users.extraGroups.riemanntools.gid = config.ids.gids.riemanntools;
+
+    users.extraUsers.riemanntools = {
+      description = "riemann-tools daemon user";
+      uid = config.ids.uids.riemanntools;
+      group = "riemanntools";
+    };
+
+    systemd.services.riemann-health = {
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "riemanntools";
+        ExecStart = "${healthLauncher}/bin/riemann-health";
+        PermissionsStartOnly = true;
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/monitoring/scollector.nix b/nixos/modules/services/monitoring/scollector.nix
index 0143d2e327bd..179c587431ea 100644
--- a/nixos/modules/services/monitoring/scollector.nix
+++ b/nixos/modules/services/monitoring/scollector.nix
@@ -73,7 +73,7 @@ in {
       };
 
       collectors = mkOption {
-        type = types.attrs;
+        type = with types; attrsOf (listOf path);
         default = {};
         example = literalExample "{ 0 = [ \"\${postgresStats}/bin/collect-stats\" ]; }";
         description = ''
diff --git a/nixos/modules/services/monitoring/statsd.nix b/nixos/modules/services/monitoring/statsd.nix
index 7d7ca27bb2f0..d9e0b83e2389 100644
--- a/nixos/modules/services/monitoring/statsd.nix
+++ b/nixos/modules/services/monitoring/statsd.nix
@@ -37,7 +37,7 @@ in
     enable = mkOption {
       description = "Whether to enable statsd stats aggregation service";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
     };
 
     host = mkOption {
@@ -49,7 +49,7 @@ in
     port = mkOption {
       description = "Port that stats listens for messages on over UDP";
       default = 8125;
-      type = types.uniq types.int;
+      type = types.int;
     };
 
     mgmt_address = mkOption {
@@ -61,7 +61,7 @@ in
     mgmt_port = mkOption {
       description = "Port to run the management TCP interface on";
       default = 8126;
-      type = types.uniq types.int;
+      type = types.int;
     };
 
     backends = mkOption {
diff --git a/nixos/modules/services/monitoring/ups.nix b/nixos/modules/services/monitoring/ups.nix
index cc9026f768a8..eb478f7da65d 100644
--- a/nixos/modules/services/monitoring/ups.nix
+++ b/nixos/modules/services/monitoring/ups.nix
@@ -32,7 +32,7 @@ let
 
       shutdownOrder = mkOption {
         default = 0;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           When you have multiple UPSes on your system, you usually need to
           turn them off in a certain order.  upsdrvctl shuts down all the
@@ -63,7 +63,7 @@ let
 
       directives = mkOption {
         default = [];
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         description = ''
           List of configuration directives for this UPS.
         '';
@@ -151,7 +151,7 @@ in
 
       maxStartDelay = mkOption {
         default = 45;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           This can be set as a global variable above your first UPS
           definition and it can also be set in a UPS section.  This value
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 8b3741bca0af..bbf21634c368 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -137,7 +137,7 @@ in
 
       nsswins = mkOption {
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
         description = ''
           Whether to enable the WINS NSS (Name Service Switch) plug-in.
           Enabling it allows applications to resolve WINS/NetBIOS names (a.k.a.
diff --git a/nixos/modules/services/networking/atftpd.nix b/nixos/modules/services/networking/atftpd.nix
index 47465ba948a9..d875ddc63528 100644
--- a/nixos/modules/services/networking/atftpd.nix
+++ b/nixos/modules/services/networking/atftpd.nix
@@ -18,7 +18,7 @@ in
 
       enable = mkOption {
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
         description = ''
           Whenever to enable the atftpd TFTP server.
         '';
@@ -26,7 +26,7 @@ in
 
       root = mkOption {
         default = "/var/empty";
-        type = types.uniq types.string;
+        type = types.str;
         description = ''
           Document root directory for the atftpd.
         '';
diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix
index 7276603da16f..27b7dd71d9e5 100644
--- a/nixos/modules/services/networking/bitlbee.nix
+++ b/nixos/modules/services/networking/bitlbee.nix
@@ -17,10 +17,12 @@ let
     [settings]
     RunMode = Daemon
     User = bitlbee  
-    ConfigDir = /var/lib/bitlbee      
+    ConfigDir = ${cfg.configDir}
     DaemonInterface = ${cfg.interface}
     DaemonPort = ${toString cfg.portNumber}
     AuthMode = ${cfg.authMode}
+    ${lib.optionalString (cfg.hostName != "") "HostName = ${cfg.hostName}"}
+    ${lib.optionalString (cfg.protocols != "") "Protocols = ${cfg.protocols}"}
     ${cfg.extraSettings}
 
     [defaults]
@@ -73,6 +75,34 @@ in
         ''; 
       };
 
+      hostName = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Normally, BitlBee gets a hostname using getsockname(). If you have a nicer
+          alias for your BitlBee daemon, you can set it here and BitlBee will identify
+          itself with that name instead.
+        '';
+      };
+
+      configDir = mkOption {
+        default = "/var/lib/bitlbee";
+        type = types.path;
+        description = ''
+          Specify an alternative directory to store all the per-user configuration
+          files.
+        '';
+      };
+
+      protocols = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          This option allows to remove the support of protocol, even if compiled
+          in. If nothing is given, there are no restrictions.
+        '';
+      };
+
       extraSettings = mkOption {
         default = "";
         description = ''
diff --git a/nixos/modules/services/networking/btsync.nix b/nixos/modules/services/networking/btsync.nix
index d0123b79e3f8..bd7a5bcebe68 100644
--- a/nixos/modules/services/networking/btsync.nix
+++ b/nixos/modules/services/networking/btsync.nix
@@ -208,8 +208,8 @@ in
 
       storagePath = mkOption {
         type = types.path;
-        default = "/var/lib/btsync";
-        example = "/var/lib/btsync";
+        default = "/var/lib/btsync/";
+        example = "/var/lib/btsync/";
         description = ''
           Where to store the bittorrent sync files.
         '';
diff --git a/nixos/modules/services/networking/charybdis.nix b/nixos/modules/services/networking/charybdis.nix
index 91729ebd60a5..2f7d006b8816 100644
--- a/nixos/modules/services/networking/charybdis.nix
+++ b/nixos/modules/services/networking/charybdis.nix
@@ -85,10 +85,8 @@ in
         PermissionsStartOnly = true; # preStart needs to run with root permissions
       };
       preStart = ''
-        if ! test -d /var/lib/charybdis; then
-          ${coreutils}/bin/mkdir -p ${cfg.statedir}
-          ${coreutils}/bin/chown ${cfg.user}:${cfg.group} ${cfg.statedir}
-        fi
+        ${coreutils}/bin/mkdir -p ${cfg.statedir}
+        ${coreutils}/bin/chown ${cfg.user}:${cfg.group} ${cfg.statedir}
       '';
 
     };
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 53a9f4626254..66838735c4da 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -104,7 +104,13 @@ in
       };
 
       alerts = {
-        enable = mkEnableOption "Whether to enable consul-alerts";
+        enable = mkEnableOption "consul-alerts";
+
+        package = mkOption {
+          description = "Package to use for consul-alerts.";
+          default = pkgs.consul-alerts;
+          type = types.package;
+        };
 
         listenAddr = mkOption {
           description = "Api listening address.";
@@ -135,96 +141,101 @@ in
 
   };
 
-  config = mkIf cfg.enable {
+  config = mkIf cfg.enable (
+    mkMerge [{
 
-    users.extraUsers."consul" = {
-      description = "Consul agent daemon user";
-      uid = config.ids.uids.consul;
-      # The shell is needed for health checks
-      shell = "/run/current-system/sw/bin/bash";
-    };
+      users.extraUsers."consul" = {
+        description = "Consul agent daemon user";
+        uid = config.ids.uids.consul;
+        # The shell is needed for health checks
+        shell = "/run/current-system/sw/bin/bash";
+      };
 
-    environment = {
-      etc."consul.json".text = builtins.toJSON configOptions;
-      # We need consul.d to exist for consul to start
-      etc."consul.d/dummy.json".text = "{ }";
-      systemPackages = with pkgs; [ consul ];
-    };
+      environment = {
+        etc."consul.json".text = builtins.toJSON configOptions;
+        # We need consul.d to exist for consul to start
+        etc."consul.d/dummy.json".text = "{ }";
+        systemPackages = with pkgs; [ consul ];
+      };
 
-    systemd.services.consul = {
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ] ++ systemdDevices;
-      bindsTo = systemdDevices;
-      restartTriggers = [ config.environment.etc."consul.json".source ]
-        ++ mapAttrsToList (_: d: d.source)
-          (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc);
-
-      serviceConfig = {
-        ExecStart = "@${pkgs.consul}/bin/consul consul agent -config-dir /etc/consul.d"
-          + concatMapStrings (n: " -config-file ${n}") configFiles;
-        ExecReload = "${pkgs.consul}/bin/consul reload";
-        PermissionsStartOnly = true;
-        User = if cfg.dropPrivileges then "consul" else null;
-        TimeoutStartSec = "0";
-      } // (optionalAttrs (cfg.leaveOnStop) {
-        ExecStop = "${pkgs.consul}/bin/consul leave";
-      });
-
-      path = with pkgs; [ iproute gnugrep gawk consul ];
-      preStart = ''
-        mkdir -m 0700 -p ${dataDir}
-        chown -R consul ${dataDir}
-
-        # Determine interface addresses
-        getAddrOnce () {
-          ip addr show dev "$1" \
-            | grep 'inet${optionalString (cfg.forceIpv4) " "}.*scope global' \
-            | awk -F '[ /\t]*' '{print $3}' | head -n 1
-        }
-        getAddr () {
-          ADDR="$(getAddrOnce $1)"
-          LEFT=60 # Die after 1 minute
-          while [ -z "$ADDR" ]; do
-            sleep 1
-            LEFT=$(expr $LEFT - 1)
-            if [ "$LEFT" -eq "0" ]; then
-              echo "Address lookup timed out"
-              exit 1
-            fi
+      systemd.services.consul = {
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ] ++ systemdDevices;
+        bindsTo = systemdDevices;
+        restartTriggers = [ config.environment.etc."consul.json".source ]
+          ++ mapAttrsToList (_: d: d.source)
+            (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc);
+
+        serviceConfig = {
+          ExecStart = "@${pkgs.consul}/bin/consul consul agent -config-dir /etc/consul.d"
+            + concatMapStrings (n: " -config-file ${n}") configFiles;
+          ExecReload = "${pkgs.consul}/bin/consul reload";
+          PermissionsStartOnly = true;
+          User = if cfg.dropPrivileges then "consul" else null;
+          TimeoutStartSec = "0";
+        } // (optionalAttrs (cfg.leaveOnStop) {
+          ExecStop = "${pkgs.consul}/bin/consul leave";
+        });
+
+        path = with pkgs; [ iproute gnugrep gawk consul ];
+        preStart = ''
+          mkdir -m 0700 -p ${dataDir}
+          chown -R consul ${dataDir}
+
+          # Determine interface addresses
+          getAddrOnce () {
+            ip addr show dev "$1" \
+              | grep 'inet${optionalString (cfg.forceIpv4) " "}.*scope global' \
+              | awk -F '[ /\t]*' '{print $3}' | head -n 1
+          }
+          getAddr () {
             ADDR="$(getAddrOnce $1)"
-          done
-          echo "$ADDR"
-        }
-        echo "{" > /etc/consul-addrs.json
-        delim=" "
-      ''
-      + concatStrings (flip mapAttrsToList cfg.interface (name: i:
-        optionalString (i != null) ''
-          echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json
-          delim=","
-        ''))
-      + ''
-        echo "}" >> /etc/consul-addrs.json
-      '';
-    };
-
-    systemd.services.consul-alerts = mkIf (cfg.alerts.enable) {
-      wantedBy = [ "multi-user.target" ];
-      after = [ "consul.service" ];
-
-      path = [ pkgs.consul ];
-
-      serviceConfig = {
-        ExecStart = ''
-          ${pkgs.consul-alerts}/bin/consul-alerts start \
-            --alert-addr=${cfg.alerts.listenAddr} \
-            --consul-addr=${cfg.alerts.consulAddr} \
-            ${optionalString cfg.alerts.watchChecks "--watch-checks"} \
-            ${optionalString cfg.alerts.watchEvents "--watch-events"}
+            LEFT=60 # Die after 1 minute
+            while [ -z "$ADDR" ]; do
+              sleep 1
+              LEFT=$(expr $LEFT - 1)
+              if [ "$LEFT" -eq "0" ]; then
+                echo "Address lookup timed out"
+                exit 1
+              fi
+              ADDR="$(getAddrOnce $1)"
+            done
+            echo "$ADDR"
+          }
+          echo "{" > /etc/consul-addrs.json
+          delim=" "
+        ''
+        + concatStrings (flip mapAttrsToList cfg.interface (name: i:
+          optionalString (i != null) ''
+            echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json
+            delim=","
+          ''))
+        + ''
+          echo "}" >> /etc/consul-addrs.json
         '';
-        User = if cfg.dropPrivileges then "consul" else null;
       };
-    };
+    }
+
+    (mkIf (cfg.alerts.enable) {
+      systemd.services.consul-alerts = {
+        wantedBy = [ "multi-user.target" ];
+        after = [ "consul.service" ];
+
+        path = [ pkgs.consul ];
+
+        serviceConfig = {
+          ExecStart = ''
+            ${cfg.alerts.package}/bin/consul-alerts start \
+              --alert-addr=${cfg.alerts.listenAddr} \
+              --consul-addr=${cfg.alerts.consulAddr} \
+              ${optionalString cfg.alerts.watchChecks "--watch-checks"} \
+              ${optionalString cfg.alerts.watchEvents "--watch-events"}
+          '';
+          User = if cfg.dropPrivileges then "consul" else null;
+          Restart = "on-failure";
+        };
+      };
+    })
 
-  };
+  ]);
 }
diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix
index 92f6396b3588..5802d8b95b38 100644
--- a/nixos/modules/services/networking/ddclient.nix
+++ b/nixos/modules/services/networking/ddclient.nix
@@ -126,6 +126,8 @@ in
       description = "Dynamic DNS Client";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
+
+      environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
       serviceConfig = {
         # Uncomment this if too many problems occur:
         # Type = "forking";
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index 5cc33f35adb2..c724ee979c2d 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -5,38 +5,35 @@ let
   apparmorEnabled = config.security.apparmor.enable;
   dnscrypt-proxy = pkgs.dnscrypt-proxy;
   cfg = config.services.dnscrypt-proxy;
-  uid = config.ids.uids.dnscrypt-proxy;
+  resolverListFile = "${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv";
+  localAddress = "${cfg.localAddress}:${toString cfg.localPort}";
   daemonArgs =
-    [ "--daemonize"
-      "--user=dnscrypt-proxy"
-      "--local-address=${cfg.localAddress}:${toString cfg.port}"
+    [ "--local-address=${localAddress}"
       (optionalString cfg.tcpOnly "--tcp-only")
-      "--resolvers-list=${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv"
-      "--resolver-name=${cfg.resolverName}"
-    ];
+    ]
+    ++ resolverArgs;
+  resolverArgs = if (cfg.customResolver != null)
+    then
+      [ "--resolver-address=${cfg.customResolver.address}:${toString cfg.customResolver.port}"
+        "--provider-name=${cfg.customResolver.name}"
+        "--provider-key=${cfg.customResolver.key}"
+      ]
+    else
+      [ "--resolvers-list=${resolverListFile}"
+        "--resolver-name=${toString cfg.resolverName}"
+      ];
 in
 
 {
-  ##### interface
-
   options = {
-
     services.dnscrypt-proxy = {
-
-      enable = mkOption {
-        default = false;
-        type = types.bool;
-        description = ''
-          Enable dnscrypt-proxy.
-          The proxy relays regular DNS queries to a DNSCrypt enabled
-          upstream resolver.
-          The traffic between the client and the upstream resolver is
-          encrypted and authenticated, which may mitigate the risk of MITM
-          attacks and third-party snooping (assuming the upstream is
-          trustworthy).
-        '';
-      };
-
+      enable = mkEnableOption ''
+        Enable dnscrypt-proxy. The proxy relays regular DNS queries to a
+        DNSCrypt enabled upstream resolver. The traffic between the
+        client and the upstream resolver is encrypted and authenticated,
+        which may mitigate the risk of MITM attacks and third-party
+        snooping (assuming the upstream is trustworthy).
+      '';
       localAddress = mkOption {
         default = "127.0.0.1";
         type = types.string;
@@ -44,96 +41,128 @@ in
           Listen for DNS queries on this address.
         '';
       };
-
-      port = mkOption {
+      localPort = mkOption {
         default = 53;
         type = types.int;
         description = ''
           Listen on this port.
         '';
       };
-
       resolverName = mkOption {
         default = "opendns";
-        type = types.string;
+        type = types.nullOr types.string;
         description = ''
-          The name of the upstream DNSCrypt resolver to use.
-          See <literal>${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv</literal>
-          for alternative resolvers (e.g., if you are concerned about logging
-          and/or server location).
+          The name of the upstream DNSCrypt resolver to use. See
+          <literal>${resolverListFile}</literal> for alternative resolvers
+          (e.g., if you are concerned about logging and/or server
+          location).
         '';
       };
-
+      customResolver = mkOption {
+        default = null;
+        description = ''
+          Use a resolver not listed in the upstream list (e.g.,
+          a private DNSCrypt provider). For advanced users only.
+          If specified, this option takes precedence.
+        '';
+        type = types.nullOr (types.submodule ({ ... }: { options = {
+          address = mkOption {
+            type = types.str;
+            description = "Resolver IP address";
+            example = "208.67.220.220";
+          };
+          port = mkOption {
+            type = types.int;
+            description = "Resolver port";
+            default = 443;
+          };
+          name = mkOption {
+            type = types.str;
+            description = "Provider fully qualified domain name";
+            example = "2.dnscrypt-cert.opendns.com";
+         };
+         key = mkOption {
+           type = types.str;
+           description = "Provider 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;
         description = ''
           Force sending encrypted DNS queries to the upstream resolver
-          over TCP instead of UDP (on port 443).
-          Enabling this option may help circumvent filtering, but should
-          not be used otherwise.
+          over TCP instead of UDP (on port 443). Enabling this option may
+          help circumvent filtering, but should not be used otherwise.
         '';
       };
-
     };
-
   };
 
-  ##### implementation
-
   config = mkIf cfg.enable {
 
-    ### AppArmor profile
-
-    security.apparmor.profiles = mkIf apparmorEnabled [
-      (pkgs.writeText "apparmor-dnscrypt-proxy" ''
+    assertions = [
+      { assertion = (cfg.customResolver != null) || (cfg.resolverName != null);
+        message   = "please configure upstream DNSCrypt resolver";
+      }
+    ];
 
-        ${dnscrypt-proxy}/bin/dnscrypt-proxy {
-          network inet stream,
-          network inet6 stream,
-          network inet dgram,
-          network inet6 dgram,
+    security.apparmor.profiles = mkIf apparmorEnabled (singleton (pkgs.writeText "apparmor-dnscrypt-proxy" ''
+      ${dnscrypt-proxy}/bin/dnscrypt-proxy {
+        /dev/null rw,
+        /dev/urandom r,
 
-          capability ipc_lock,
-          capability net_bind_service,
-          capability net_admin,
-          capability sys_chroot,
-          capability setgid,
-          capability setuid,
+        /etc/passwd r,
+        /etc/group r,
+        ${config.environment.etc."nsswitch.conf".source} r,
 
-          /dev/null rw,
-          /dev/urandom r,
+        ${pkgs.glibc}/lib/*.so mr,
+        ${pkgs.tzdata}/share/zoneinfo/** r,
 
-          ${pkgs.glibc}/lib/*.so mr,
-          ${pkgs.tzdata}/share/zoneinfo/** r,
+        network inet stream,
+        network inet6 stream,
+        network inet dgram,
+        network inet6 dgram,
 
-          ${dnscrypt-proxy}/share/dnscrypt-proxy/** r,
-          ${pkgs.gcc.cc}/lib/libssp.so.* mr,
-          ${pkgs.libsodium}/lib/libsodium.so.* mr,
-        }
-      '')
-    ];
+        ${pkgs.gcc.cc}/lib/libssp.so.* mr,
+        ${pkgs.libsodium}/lib/libsodium.so.* mr,
+        ${pkgs.systemd}/lib/libsystemd.so.* mr,
+        ${pkgs.xz}/lib/liblzma.so.* mr,
+        ${pkgs.libgcrypt}/lib/libgcrypt.so.* mr,
+        ${pkgs.libgpgerror}/lib/libgpg-error.so.* mr,
 
-    ### User
+        ${resolverListFile} r,
+      }
+    ''));
 
-    users.extraUsers = singleton {
-      inherit uid;
-      name = "dnscrypt-proxy";
+    users.extraUsers.dnscrypt-proxy = {
+      uid = config.ids.uids.dnscrypt-proxy;
       description = "dnscrypt-proxy daemon user";
     };
+    users.extraGroups.dnscrypt-proxy.gid = config.ids.gids.dnscrypt-proxy;
 
-    ### Service definition
+    systemd.sockets.dnscrypt-proxy = {
+      description = "dnscrypt-proxy listening socket";
+      socketConfig = {
+        ListenStream = "${localAddress}";
+        ListenDatagram = "${localAddress}";
+      };
+      wantedBy = [ "sockets.target" ];
+    };
 
     systemd.services.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon";
       after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service";
-      requires = mkIf apparmorEnabled [ "apparmor.service" ];
-      wantedBy = [ "multi-user.target" ];
+      requires = [ "dnscrypt-proxy.socket "] ++ optional apparmorEnabled "apparmor.service";
       serviceConfig = {
-        Type = "forking";
+        Type = "simple";
+        NonBlocking = "true";
         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/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix
index 18086154b6b0..4a812167bb5f 100644
--- a/nixos/modules/services/networking/dnsmasq.nix
+++ b/nixos/modules/services/networking/dnsmasq.nix
@@ -45,7 +45,7 @@ in
       };
 
       servers = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [];
         example = [ "8.8.8.8" "8.8.4.4" ];
         description = ''
diff --git a/nixos/modules/services/networking/docker-registry-server.nix b/nixos/modules/services/networking/docker-registry-server.nix
new file mode 100644
index 000000000000..d21bbb6a86c3
--- /dev/null
+++ b/nixos/modules/services/networking/docker-registry-server.nix
@@ -0,0 +1,98 @@
+{ 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/firefox/sync-server.nix b/nixos/modules/services/networking/firefox/sync-server.nix
index 79f32f3358cb..70d2d72ca8b7 100644
--- a/nixos/modules/services/networking/firefox/sync-server.nix
+++ b/nixos/modules/services/networking/firefox/sync-server.nix
@@ -135,7 +135,7 @@ in
           echo >> ${cfg.privateConfig} "secret = $(head -c 20 /dev/urandom | sha1sum | tr -d ' -')"
         fi
       '';
-      serviceConfig.ExecStart = "paster serve ${syncServerIni}";
+      serviceConfig.ExecStart = "${pkgs.pythonPackages.pasteScript}/bin/paster serve ${syncServerIni}";
     };
 
   };
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index b05a640e11fd..40681f5b957a 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -287,7 +287,7 @@ in
     };
 
     networking.firewall.trustedInterfaces = mkOption {
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       description =
         ''
           Traffic coming in from these interfaces will be accepted
@@ -379,7 +379,7 @@ in
     networking.firewall.connectionTrackingModules = mkOption {
       default = [ "ftp" ];
       example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       description =
         ''
           List of connection-tracking helpers that are auto-loaded.
diff --git a/nixos/modules/services/networking/freenet.nix b/nixos/modules/services/networking/freenet.nix
index e9cacf4a16e8..3903a2c708cb 100644
--- a/nixos/modules/services/networking/freenet.nix
+++ b/nixos/modules/services/networking/freenet.nix
@@ -20,13 +20,13 @@ in
     services.freenet = {
 
       enable = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = "Enable the Freenet daemon";
       };
 
       nice = mkOption {
-        type = types.uniq types.int;
+        type = types.int;
         default = 10;
         description = "Set the nice level for the Freenet daemon";
       };
diff --git a/nixos/modules/services/networking/iodined.nix b/nixos/modules/services/networking/iodined.nix
index bc0fbb42c99d..6bfe62e6261c 100644
--- a/nixos/modules/services/networking/iodined.nix
+++ b/nixos/modules/services/networking/iodined.nix
@@ -20,13 +20,13 @@ in
     services.iodined = {
 
       enable = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = "Enable iodine, ip over dns daemon";
       };
 
       client = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = "Start iodine in client mode";
       };
diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix
index d2045c9efc58..68f26eefe27e 100644
--- a/nixos/modules/services/networking/kippo.nix
+++ b/nixos/modules/services/networking/kippo.nix
@@ -16,12 +16,12 @@ rec {
     services.kippo = {
       enable = mkOption {
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
         description = ''Enable the kippo honeypot ssh server.'';
       };
       port = mkOption {
         default = 2222;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''TCP port number for kippo to bind to.'';
       };
       hostname = mkOption {
diff --git a/nixos/modules/services/networking/minidlna.nix b/nixos/modules/services/networking/minidlna.nix
index 989ee4d91af9..aa28502a12c4 100644
--- a/nixos/modules/services/networking/minidlna.nix
+++ b/nixos/modules/services/networking/minidlna.nix
@@ -30,7 +30,7 @@ in
     };
 
     services.minidlna.mediaDirs = mkOption {
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       default = [];
       example = [ "/data/media" "V,/home/alice/video" ];
       description =
@@ -97,7 +97,7 @@ in
             Type = "forking";
             PIDFile = "/run/minidlna/pid";
             ExecStart =
-              "@${pkgs.minidlna}/sbin/minidlna minidlna -P /run/minidlna/pid" +
+              "@${pkgs.minidlna}/sbin/minidlnad minidlnad -P /run/minidlna/pid" +
               " -f ${pkgs.writeText "minidlna.conf" cfg.config}";
           };
       };
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 60f380f024ba..adbc6099c95a 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -118,7 +118,7 @@ in {
       };
 
       appendNameservers = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [];
         description = ''
           A list of name servers that should be appended
@@ -127,7 +127,7 @@ in {
       };
 
       insertNameservers = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [];
         description = ''
           A list of name servers that should be inserted before
diff --git a/nixos/modules/services/networking/nix-serve.nix b/nixos/modules/services/networking/nix-serve.nix
index c2c579c3177e..4f8b9357a828 100644
--- a/nixos/modules/services/networking/nix-serve.nix
+++ b/nixos/modules/services/networking/nix-serve.nix
@@ -26,6 +26,14 @@ in
         '';
       };
 
+      secretKeyFile = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          The path to the file used for signing derivation data.
+        '';
+      };
+
       extraParams = mkOption {
         type = types.string;
         default = "";
@@ -44,13 +52,19 @@ in
 
       path = [ config.nix.package pkgs.bzip2 ];
       environment.NIX_REMOTE = "daemon";
+      environment.NIX_SECRET_KEY_FILE = cfg.secretKeyFile;
 
       serviceConfig = {
         ExecStart = "${pkgs.nix-serve}/bin/nix-serve " +
           "--port ${cfg.bindAddress}:${toString cfg.port} ${cfg.extraParams}";
-        User = "nobody";
+        User = "nix-serve";
         Group = "nogroup";
       };
     };
+
+    users.extraUsers.nix-serve = {
+      description = "Nix-serve user";
+      uid = config.ids.uids.nix-serve;
+    };
   };
 }
diff --git a/nixos/modules/services/networking/notbit.nix b/nixos/modules/services/networking/notbit.nix
index 2e1412ff7c83..a96e181cb808 100644
--- a/nixos/modules/services/networking/notbit.nix
+++ b/nixos/modules/services/networking/notbit.nix
@@ -31,7 +31,7 @@ with lib;
     services.notbit = {
 
       enable = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = ''
           Enables the notbit daemon and provides a sendmail binary named `notbit-system-sendmail` for sending mail over the system instance of notbit. Users must be in the notbit group in order to send mail over the system notbit instance. Currently mail recipt is not supported.
@@ -39,13 +39,13 @@ with lib;
       };
 
       port = mkOption {
-        type = types.uniq types.int;
+        type = types.int;
         default = 8444;
         description = "The port which the daemon listens for other bitmessage clients";
       };
 
       nice = mkOption {
-        type = types.uniq types.int;
+        type = types.int;
         default = 10;
         description = "Set the nice level for the notbit daemon";
       };
@@ -65,19 +65,19 @@ with lib;
       };
 
       specifiedPeersOnly = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = "If true, notbit will only connect to peers specified by the peers option.";
       };
 
       allowPrivateAddresses = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = "If true, notbit will allow connections to to RFC 1918 addresses.";
       };
 
       noBootstrap = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = "If true, notbit will not bootstrap an initial peerlist from bitmessage.org servers";
       };
diff --git a/nixos/modules/services/networking/ntopng.nix b/nixos/modules/services/networking/ntopng.nix
index ab86f1a5b2b4..c15257117137 100644
--- a/nixos/modules/services/networking/ntopng.nix
+++ b/nixos/modules/services/networking/ntopng.nix
@@ -57,7 +57,7 @@ in
 
       http-port = mkOption {
         default = 3000;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           Sets the HTTP port of the embedded web server.
         '';
diff --git a/nixos/modules/services/networking/polipo.nix b/nixos/modules/services/networking/polipo.nix
index 51179d9120fe..847fc88ead4c 100644
--- a/nixos/modules/services/networking/polipo.nix
+++ b/nixos/modules/services/networking/polipo.nix
@@ -42,7 +42,7 @@ in
       };
 
       allowedClients = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [ "127.0.0.1" "::1" ];
         example = [ "127.0.0.1" "::1" "134.157.168.0/24" "2001:660:116::/48" ];
         description = ''
diff --git a/nixos/modules/services/networking/racoon.nix b/nixos/modules/services/networking/racoon.nix
new file mode 100644
index 000000000000..9428d9112a1b
--- /dev/null
+++ b/nixos/modules/services/networking/racoon.nix
@@ -0,0 +1,42 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.racoon;
+in {
+  options.services.racoon = {
+    enable = mkEnableOption "racoon";
+
+    config = mkOption {
+      description = "Contents of racoon configuration file.";
+      default = "";
+      type = types.str;
+    };
+
+    configPath = mkOption {
+      description = "Location of racoon config if config is not provided.";
+      default = "/etc/racoon/racoon.conf";
+      type = types.path;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.racoon = {
+      description = "Racoon Daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.ipsecTools}/bin/racoon -f ${
+          if (cfg.config != "") then pkgs.writeText "racoon.conf" cfg.config
+          else cfg.configPath
+        }";
+        ExecReload = "${pkgs.ipsecTools}/bin/racoonctl reload-config";
+        PIDFile = "/var/run/racoon.pid";
+        Type = "forking";
+        Restart = "always";
+      };
+      preStart = "rm /var/run/racoon.pid || true";
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
new file mode 100644
index 000000000000..3b9390914891
--- /dev/null
+++ b/nixos/modules/services/networking/skydns.nix
@@ -0,0 +1,91 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.skydns;
+
+in {
+  options.services.skydns = {
+    enable = mkEnableOption "skydns service";
+
+    etcd = {
+      machines = mkOption {
+        default = [ "http://localhost:4001" ];
+        type = types.listOf types.str;
+        description = "Skydns list of etcd endpoints to connect to.";
+      };
+
+      tlsKey = mkOption {
+        default = null;
+        type = types.nullOr types.path;
+        description = "Skydns path of TLS client certificate - private key.";
+      };
+
+      tlsPem = mkOption {
+        default = null;
+        type = types.nullOr types.path;
+        description = "Skydns path of TLS client certificate - public key.";
+      };
+
+      caCert = mkOption {
+        default = null;
+        type = types.nullOr types.path;
+        description = "Skydns path of TLS certificate authority public key.";
+      };
+    };
+
+    address = mkOption {
+      default = "0.0.0.0:53";
+      type = types.str;
+      description = "Skydns address to bind to.";
+    };
+
+    domain = mkOption {
+      default = "skydns.local.";
+      type = types.str;
+      description = "Skydns default domain if not specified by etcd config.";
+    };
+
+    nameservers = mkOption {
+      default = map (n: n + ":53") config.networking.nameservers;
+      type = types.listOf types.str;
+      description = "Skydns list of nameservers to forward DNS requests to when not authoritative for a domain.";
+      example = ["8.8.8.8:53" "8.8.4.4:53"];
+    };
+
+    package = mkOption {
+      default = pkgs.skydns;
+      type = types.package;
+      description = "Skydns package to use.";
+    };
+
+    extraConfig = mkOption {
+      default = {};
+      type = types.attrsOf types.str;
+      description = "Skydns attribute set of extra config options passed as environemnt variables.";
+    };
+  };
+
+  config = mkIf (cfg.enable) {
+    systemd.services.skydns = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "etcd.service" ];
+      description = "Skydns Service";
+      environment = {
+        ETCD_MACHINES = concatStringsSep "," cfg.etcd.machines;
+        ETCD_TLSKEY = cfg.etcd.tlsKey;
+        ETCD_TLSPEM = cfg.etcd.tlsPem;
+        ETCD_CACERT = cfg.etcd.caCert;
+        SKYDNS_ADDR = cfg.address;
+        SKYDNS_DOMAIN = cfg.domain;
+        SKYDNS_NAMESERVER = concatStringsSep "," cfg.nameservers;
+      };
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/skydns";
+      };
+    };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index 6cc86b4e4b5a..4be2b5fe0c0c 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -234,7 +234,7 @@ in
         ];
         options = {
           hostNames = mkOption {
-            type = types.listOf types.string;
+            type = types.listOf types.str;
             default = [];
             description = ''
               A list of host names and/or IP numbers used for accessing
@@ -244,13 +244,12 @@ in
           publicKey = mkOption {
             default = null;
             type = types.nullOr types.str;
+            example = "ecdsa-sha2-nistp521 AAAAE2VjZHN...UEPg==";
             description = ''
               The public key data for the host. You can fetch a public key
               from a running SSH server with the <command>ssh-keyscan</command>
               command. The public key should not include any host names, only
-              the key type and the key itself. It is allowed to add several
-              lines here, each line will be treated as type/key pair and the
-              host names will be prepended to each line.
+              the key type and the key itself.
             '';
           };
           publicKeyFile = mkOption {
@@ -268,6 +267,16 @@ in
         };
       };
 
+      moduliFile = mkOption {
+        example = "services.openssh.moduliFile = /etc/my-local-ssh-moduli;";
+        type = types.path;
+        description = ''
+          Path to <literal>moduli</literal> file to install in
+          <literal>/etc/ssh/moduli</literal>. If this option is unset, then
+          the <literal>moduli</literal> file shipped with OpenSSH will be used.
+        '';
+      };
+
     };
 
     users.extraUsers = mkOption {
@@ -286,8 +295,10 @@ in
         description = "SSH privilege separation user";
       };
 
+    services.openssh.moduliFile = mkDefault "${cfgc.package}/etc/ssh/moduli";
+
     environment.etc = authKeysFiles ++ [
-      { source = "${cfgc.package}/etc/ssh/moduli";
+      { source = cfg.moduliFile;
         target = "ssh/moduli";
       }
       { text = knownHostsText;
diff --git a/nixos/modules/services/networking/tvheadend.nix b/nixos/modules/services/networking/tvheadend.nix
new file mode 100644
index 000000000000..cdd8747ba898
--- /dev/null
+++ b/nixos/modules/services/networking/tvheadend.nix
@@ -0,0 +1,61 @@
+{ config, coreutils, lib, pkgs, ... }:
+
+with lib;
+
+let cfg     = config.services.tvheadend;
+    pidFile = "${config.users.extraUsers.tvheadend.home}/tvheadend.pid";
+in
+
+{
+  options = {
+    services.tvheadend = {
+      enable = mkEnableOption "Tvheadend";
+      httpPort = mkOption {
+        type        = types.int;
+        default     = 9981;
+        description = "Port to bind HTTP to.";
+      };
+
+      htspPort = mkOption {
+        type        = types.int;
+        default     = 9982;
+        description = "Port to bind HTSP to.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers.tvheadend = {
+      description = "Tvheadend Service user";
+      home        = "/var/lib/tvheadend";
+      createHome  = true;
+      uid         = config.ids.uids.tvheadend;
+    };
+
+    systemd.services.tvheadend = {
+      description = "Tvheadend TV streaming server";
+      wantedBy    = [ "multi-user.target" ];
+      after       = [ "network.target" ];
+
+      serviceConfig = {
+        Type         = "forking";
+        PIDFile      = pidFile;
+        Restart      = "always";
+        RestartSec   = 5;
+        User         = "tvheadend";
+        Group        = "video";
+        ExecStart    = ''
+                       ${pkgs.tvheadend}/bin/tvheadend \
+                       --http_port ${toString cfg.httpPort} \
+                       --htsp_port ${toString cfg.htspPort} \
+                       -f \
+                       -C \
+                       -p ${pidFile} \
+                       -u tvheadend \
+                       -g video
+                       '';
+        ExecStop     = "${pkgs.coreutils}/bin/rm ${pidFile}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
index d6c8e0dc7a5c..be8f12ecd32d 100644
--- a/nixos/modules/services/networking/unifi.nix
+++ b/nixos/modules/services/networking/unifi.nix
@@ -25,7 +25,7 @@ in
   options = {
 
     services.unifi.enable = mkOption {
-      type = types.uniq types.bool;
+      type = types.bool;
       default = false;
       description = ''
         Whether or not to enable the unifi controller service.
@@ -71,7 +71,7 @@ in
         rm -rf "${stateDir}/webapps"
         mkdir -p "${stateDir}/webapps"
         chown unifi "${stateDir}/webapps"
-        ln -s "${pkgs.unifi}/webapps/ROOT.war" "${stateDir}/webapps/ROOT.war"
+        ln -s "${pkgs.unifi}/webapps/ROOT" "${stateDir}/webapps/ROOT"
       '';
 
       postStop = ''
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index e2d34ea079c5..9e04bd401906 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -43,7 +43,7 @@ in
       };
 
       interfaces = mkOption {
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         default = [];
         example = [ "wlan0" "wlan1" ];
         description = ''
diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix
new file mode 100644
index 000000000000..886ea18d9809
--- /dev/null
+++ b/nixos/modules/services/networking/zerotierone.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.zerotierone;
+in
+{
+  options.services.zerotierone.enable = mkEnableOption "ZeroTierOne";
+  
+  config = mkIf cfg.enable {
+    systemd.services.zerotierone = {
+      description = "ZeroTierOne";
+      path = [ pkgs.zerotierone ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      preStart =
+        ''
+        mkdir -p /var/lib/zerotier-one
+        chmod 700 /var/lib/zerotier-one
+        chown -R root:root /var/lib/zerotier-one
+        '';
+      serviceConfig = {
+        Type = "forking";
+        User = "root";
+        PIDFile = "/var/lib/zerotier-one/zerotier-one.pid";
+        ExecStart = "${pkgs.zerotierone}/bin/zerotier-one -d";
+      };
+    };
+  environment.systemPackages = [ pkgs.zerotierone ];
+  };
+}
diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix
index b39aea04521b..196a14dd40ed 100644
--- a/nixos/modules/services/networking/znc.nix
+++ b/nixos/modules/services/networking/znc.nix
@@ -144,7 +144,7 @@ in
       */
       confOptions = {
         modules = mkOption {
-          type = types.listOf types.string;
+          type = types.listOf types.str;
           default = [ "partyline" "webadmin" "adminlog" "log" ];
           example = [ "partyline" "webadmin" "adminlog" "log" ];
           description = ''
@@ -153,7 +153,7 @@ in
         };
 
         userModules = mkOption {
-          type = types.listOf types.string;
+          type = types.listOf types.str;
           default = [ ];
           example = [ "fish" "push" ];
           description = ''
diff --git a/nixos/modules/services/scheduling/chronos.nix b/nixos/modules/services/scheduling/chronos.nix
index f36b886a744b..db1f0f5f00c9 100644
--- a/nixos/modules/services/scheduling/chronos.nix
+++ b/nixos/modules/services/scheduling/chronos.nix
@@ -13,7 +13,7 @@ in {
     enable = mkOption {
       description = "Whether to enable graphite web frontend.";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
     };
 
     httpPort = mkOption {
diff --git a/nixos/modules/services/scheduling/marathon.nix b/nixos/modules/services/scheduling/marathon.nix
index ab93334f5fc9..4e837c62dc11 100644
--- a/nixos/modules/services/scheduling/marathon.nix
+++ b/nixos/modules/services/scheduling/marathon.nix
@@ -12,21 +12,13 @@ in {
 
   options.services.marathon = {
     enable = mkOption {
-      type = types.uniq types.bool;
+      type = types.bool;
       default = false;
       description = ''
 	Whether to enable the marathon mesos framework.
       '';
     };
 
-    httpPort = mkOption {
-      type = types.int;
-      default = 8080;
-      description = ''
-	Marathon listening port for HTTP connections.
-      '';
-    };
-
     master = mkOption {
       type = types.str;
       default = "zk://${concatStringsSep "," cfg.zookeeperHosts}/mesos";
@@ -45,6 +37,25 @@ in {
       '';
     };
 
+    user = mkOption {
+      type = types.str;
+      default = "marathon";
+      example = "root";
+      description = ''
+	The user that the Marathon framework will be launched as. If the user doesn't exist it will be created.
+	If you want to run apps that require root access or you want to launch apps using arbitrary users, that
+	is using the `--mesos_user` flag then you need to change this to `root`.
+      '';
+    };
+
+    httpPort = mkOption {
+      type = types.int;
+      default = 8080;
+      description = ''
+	Marathon listening port for HTTP connections.
+      '';
+    };
+
     extraCmdLineOptions = mkOption {
       type = types.listOf types.str;
       default = [ ];
@@ -76,14 +87,12 @@ in {
 
       serviceConfig = {
         ExecStart = "${pkgs.marathon}/bin/marathon --master ${cfg.master} --zk zk://${concatStringsSep "," cfg.zookeeperHosts}/marathon --http_port ${toString cfg.httpPort} ${concatStringsSep " " cfg.extraCmdLineOptions}";
-        User = "marathon";
+        User = cfg.user;
         Restart = "always";
         RestartSec = "2";
       };
     };
 
-    users.extraUsers.marathon = {
-      description = "Marathon mesos framework user";
-    };
+    users.extraUsers.${cfg.user} = { };
   };
 }
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index 12f163db463d..64620bf16041 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -34,7 +34,7 @@ in {
     enable = mkOption {
       description = "Whether to enable elasticsearch.";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
     };
 
     host = mkOption {
@@ -102,7 +102,7 @@ in {
     extraCmdLineOptions = mkOption {
       description = "Extra command line options for the elasticsearch launcher.";
       default = [];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       example = [ "-Djava.net.preferIPv4Stack=true" ];
     };
 
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index 853b458cf589..5c20901427cb 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -12,7 +12,10 @@ let
 
   configDir = pkgs.stdenv.mkDerivation {
     name = "dbus-conf";
+
     preferLocalBuild = true;
+    allowSubstitutes = false;
+
     buildCommand = ''
       mkdir -p $out
 
diff --git a/nixos/modules/services/torrent/peerflix.nix b/nixos/modules/services/torrent/peerflix.nix
index 0360deac08bb..38fbd3b226cd 100644
--- a/nixos/modules/services/torrent/peerflix.nix
+++ b/nixos/modules/services/torrent/peerflix.nix
@@ -20,7 +20,7 @@ in {
     enable = mkOption {
       description = "Whether to enable peerflix service.";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
     };
 
     stateDir = mkOption {
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 135113b3ceb1..cf548bc696ca 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -27,7 +27,7 @@ in
   options = {
     services.transmission = {
       enable = mkOption {
-        type = types.uniq types.bool;
+        type = types.bool;
         default = false;
         description = ''
           Whether or not to enable the headless Transmission BitTorrent daemon.
@@ -66,7 +66,7 @@ in
       };
 
       port = mkOption {
-        type = types.uniq types.int;
+        type = types.int;
         default = 9091;
         description = "TCP port number to run the RPC/web interface.";
       };
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 2885fd396525..7350a6a68c70 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -187,9 +187,6 @@ let
     <IfModule mod_mime_magic.c>
         MIMEMagicFile ${httpd}/conf/magic
     </IfModule>
-
-    AddEncoding x-compress Z
-    AddEncoding x-gzip gz tgz
   '';
 
 
diff --git a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
index 01b6cfc62afb..8884569c7bc8 100644
--- a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
@@ -1,22 +1,12 @@
 { config, lib, pkgs, serverInfo, php, ... }:
+# http://codex.wordpress.org/Hardening_WordPress
 
 with lib;
 
 let
-  # https://wordpress.org/plugins/postgresql-for-wordpress/
-  # Wordpress plugin 'postgresql-for-wordpress' installation example
-  postgresqlForWordpressPlugin = pkgs.stdenv.mkDerivation {
-    name = "postgresql-for-wordpress-plugin";
-    # Download the theme from the wordpress site
-    src = pkgs.fetchurl {
-      url = https://downloads.wordpress.org/plugin/postgresql-for-wordpress.1.3.1.zip;
-      sha256 = "f11a5d76af884c7bec2bc653ed5bd29d3ede9a8657bd67ab7824e329e5d809e8";
-    };
-    # We need unzip to build this package
-    buildInputs = [ pkgs.unzip ];
-    # Installing simply means copying all files to the output directory
-    installPhase = "mkdir -p $out; cp -R * $out/";
-  };
+
+  version = "4.2";
+  fullversion = "${version}.2";
 
   # Our bare-bones wp-config.php file using the above settings
   wordpressConfig = pkgs.writeText "wp-config.php" ''
@@ -38,38 +28,77 @@ let
     <IfModule mod_rewrite.c>
     RewriteEngine On
     RewriteBase /
-    RewriteCond %{REQUEST_FILENAME} !-f
-    RewriteCond %{REQUEST_FILENAME} !-d
-    RewriteRule . /index.php [L]
+    RewriteRule ^index\.php$ - [L]
+
+    # add a trailing slash to /wp-admin
+    RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
+
+    RewriteCond %{REQUEST_FILENAME} -f [OR]
+    RewriteCond %{REQUEST_FILENAME} -d
+    RewriteRule ^ - [L]
+    RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
+    RewriteRule ^(.*\.php)$ $1 [L]
+    RewriteRule . index.php [L]
     </IfModule>
   '';
 
+  # WP translation can be found here:
+  #   https://github.com/nixcloud/wordpress-translations
+  supportedLanguages = {
+    en_GB = { revision="d6c005372a5318fd758b710b77a800c86518be13"; sha256="0qbbsi87k47q4rgczxx541xz4z4f4fr49hw4lnaxkdsf5maz8p9p"; };
+    de_DE = { revision="3c62955c27baaae98fd99feb35593d46562f4736"; sha256="1shndgd11dk836dakrjlg2arwv08vqx6j4xjh4jshvwmjab6ng6p"; };
+    zh_ZN = { revision="12b9f811e8cae4b6ee41de343d35deb0a8fdda6d"; sha256="1339ggsxh0g6lab37jmfxicsax4h702rc3fsvv5azs7mcznvwh47"; };
+    fr_FR = { revision="688c8b1543e3d38d9e8f57e0a6f2a2c3c8b588bd"; sha256="1j41iak0i6k7a4wzyav0yrllkdjjskvs45w53db8vfm8phq1n014"; };
+  };
+
+  downloadLanguagePack = language: revision: sha256s:
+    pkgs.stdenv.mkDerivation rec {
+      name = "wp_${language}";
+      src = pkgs.fetchFromGitHub {
+        owner = "nixcloud";
+        repo = "wordpress-translations";
+        rev = revision;
+        sha256 = sha256s;
+      };
+      installPhase = "mkdir -p $out; cp -R * $out/";
+    };
+
+  selectedLanguages = map (lang: downloadLanguagePack lang supportedLanguages.${lang}.revision supportedLanguages.${lang}.sha256) (config.languages);
+
   # The wordpress package itself
   wordpressRoot = pkgs.stdenv.mkDerivation rec {
     name = "wordpress";
-    # Fetch directly from the wordpress site, want to upgrade?
-    # Just change the version URL and update the hash
-    src = pkgs.fetchurl {
-      url = http://wordpress.org/wordpress-4.1.1.tar.gz;
-      sha256 = "1s9y0i9ms3m6dswb9gqrr95plnx6imahc07fyhvrp5g35f6c12k1";
+    src = pkgs.fetchFromGitHub {
+      owner = "WordPress";
+      repo = "WordPress";
+      rev = "${fullversion}";
+      sha256 = "0gq1j9b0d0rykql3jzdb2yn4adj0rrcsvqrmj3dzx11ir57ilsgc";
     };
     installPhase = ''
       mkdir -p $out
-      # Copy all the wordpress files we downloaded
+      # copy all the wordpress files we downloaded
       cp -R * $out/
-      # We'll symlink the wordpress config
+
+      # symlink the wordpress config
       ln -s ${wordpressConfig} $out/wp-config.php
-      # As well as our custom .htaccess
+      # symlink custom .htaccess
       ln -s ${htaccess} $out/.htaccess
-      # And the uploads directory
+      # symlink uploads directory
       ln -s ${config.wordpressUploads} $out/wp-content/uploads
-      # And the theme(s)
+
+      # remove bundled plugins(s) coming with wordpress
+      rm -Rf $out/wp-content/plugins/*
+      # remove bundled themes(s) coming with wordpress
+      rm -Rf $out/wp-content/themes/*
+
+      # symlink additional theme(s)
       ${concatMapStrings (theme: "ln -s ${theme} $out/wp-content/themes/${theme.name}\n") config.themes}
-      # And the plugin(s)
-      # remove bundled plugin(s) coming with wordpress
-      rm -Rf $out/wp-content/plugins/akismet
-      # install plugins
-      ${concatMapStrings (plugin: "ln -s ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins ++ [ postgresqlForWordpressPlugin]) }
+      # symlink additional plugin(s)
+      ${concatMapStrings (plugin: "ln -s ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins) }
+
+      # symlink additional translation(s) 
+      mkdir -p $out/wp-content/languages
+      ${concatMapStrings (language: "ln -s ${language}/*.mo ${language}/*.po $out/wp-content/languages/\n") (selectedLanguages) }
     '';
   };
 
@@ -102,12 +131,12 @@ in
     };
     dbUser = mkOption {
       default = "wordpress";
-      description = "The dbUser, read the username, for the database.";
+      description = "The dbUser, read: the username, for the database.";
       example = "wordpress";
     };
     dbPassword = mkOption {
       default = "wordpress";
-      description = "The password to the respective dbUser.";
+      description = "The mysql password to the respective dbUser.";
       example = "wordpress";
     };
     tablePrefix = mkOption {
@@ -127,7 +156,7 @@ in
       type = types.listOf types.path;
       description =
         ''
-          List of path(s) to respective plugin(s) which are symlinked from the 'plugins' directory. Note: These plugins need to be packaged before use.
+          List of path(s) to respective plugin(s) which are symlinked from the 'plugins' directory. Note: These plugins need to be packaged before use, see example.
         '';
       example = ''
         # Wordpress plugin 'akismet' installation example
@@ -153,7 +182,7 @@ in
       type = types.listOf types.path;
       description =
         ''
-          List of path(s) to respective theme(s) which are symlinked from the 'theme' directory. Note: These themes need to be packaged before use.
+          List of path(s) to respective theme(s) which are symlinked from the 'theme' directory. Note: These themes need to be packaged before use, see example.
         '';
       example = ''
         # For shits and giggles, let's package the responsive theme
@@ -174,6 +203,11 @@ in
           themes = [ responsiveTheme ];
       '';
     };
+    languages = mkOption {
+          default = [];
+          description = "Installs wordpress language packs based on the list, see wordpress.nix for possible translations.";
+          example = "[ \"en_GB\" \"de_DE\" ];";
+    };
     extraConfig = mkOption {
       default = "";
       example =
@@ -190,6 +224,7 @@ in
 
   documentRoot = wordpressRoot;
 
+  # FIXME adding the user has to be done manually for the time being
   startupScript = pkgs.writeScript "init-wordpress.sh" ''
     #!/bin/sh
     mkdir -p ${config.wordpressUploads}
@@ -198,12 +233,15 @@ in
     # we should use systemd dependencies here
     #waitForUnit("network-interfaces.target");
     if [ ! -d ${serverInfo.fullConfig.services.mysql.dataDir}/${config.dbName} ]; then
+      echo "Need to create the database '${config.dbName}' and grant permissions to user named '${config.dbUser}'."
       # Wait until MySQL is up
       while [ ! -e /var/run/mysql/mysqld.pid ]; do
         sleep 1
       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 
+      echo "Good, no need to do anything database related."
     fi
   '';
 }
diff --git a/nixos/modules/services/web-servers/lighttpd/cgit.nix b/nixos/modules/services/web-servers/lighttpd/cgit.nix
index 34b2fa600ad9..c8590e6a54e1 100644
--- a/nixos/modules/services/web-servers/lighttpd/cgit.nix
+++ b/nixos/modules/services/web-servers/lighttpd/cgit.nix
@@ -15,7 +15,7 @@ in
 
     enable = mkOption {
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
       description = ''
         If true, enable cgit (fast web interface for git repositories) as a
         sub-service in lighttpd. cgit will be accessible at
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index 06f310eeb933..2c662c0aead9 100644
--- a/nixos/modules/services/web-servers/lighttpd/default.nix
+++ b/nixos/modules/services/web-servers/lighttpd/default.nix
@@ -122,7 +122,7 @@ in
 
       enable = mkOption {
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
         description = ''
           Enable the lighttpd web server.
         '';
@@ -130,7 +130,7 @@ in
 
       port = mkOption {
         default = 80;
-        type = types.uniq types.int;
+        type = types.int;
         description = ''
           TCP port number for lighttpd to bind to.
         '';
@@ -146,7 +146,7 @@ in
 
       mod_userdir = mkOption {
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
         description = ''
           If true, requests in the form /~user/page.html are rewritten to take
           the file public_html/page.html from the home directory of the user.
@@ -168,7 +168,7 @@ in
 
       mod_status = mkOption {
         default = false;
-        type = types.uniq types.bool;
+        type = types.bool;
         description = ''
           Show server status overview at /server-status, statistics at
           /server-statistics and list of loaded modules at /server-config.
diff --git a/nixos/modules/services/web-servers/lighttpd/gitweb.nix b/nixos/modules/services/web-servers/lighttpd/gitweb.nix
index ef7072ecba3a..f12cc9734465 100644
--- a/nixos/modules/services/web-servers/lighttpd/gitweb.nix
+++ b/nixos/modules/services/web-servers/lighttpd/gitweb.nix
@@ -17,7 +17,7 @@ in
 
     enable = mkOption {
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
       description = ''
         If true, enable gitweb in lighttpd. Access it at http://yourserver/gitweb
       '';
diff --git a/nixos/modules/services/web-servers/phpfpm.nix b/nixos/modules/services/web-servers/phpfpm.nix
index 8551e3ccdeb2..41dbfff41cfe 100644
--- a/nixos/modules/services/web-servers/phpfpm.nix
+++ b/nixos/modules/services/web-servers/phpfpm.nix
@@ -36,7 +36,7 @@ in {
       };
 
       phpPackage = mkOption {
-        default = pkgs.php54;
+        default = pkgs.php;
         description = ''
           The PHP package to use for running the FPM service.
         '';
diff --git a/nixos/modules/services/web-servers/shellinabox.nix b/nixos/modules/services/web-servers/shellinabox.nix
new file mode 100644
index 000000000000..58a02ac59c35
--- /dev/null
+++ b/nixos/modules/services/web-servers/shellinabox.nix
@@ -0,0 +1,122 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.shellinabox;
+
+  # If a certificate file is specified, shellinaboxd requires
+  # a file descriptor to retrieve it
+  fd = "3";
+  createFd = optionalString (cfg.certFile != null) "${fd}<${cfg.certFile}";
+
+  # Command line arguments for the shellinabox daemon
+  args = [ "--background" ]
+   ++ optional (! cfg.enableSSL) "--disable-ssl"
+   ++ optional (cfg.certFile != null) "--cert-fd=${fd}"
+   ++ optional (cfg.certDirectory != null) "--cert=${cfg.certDirectory}"
+   ++ cfg.extraOptions;
+
+  # Command to start shellinaboxd
+  cmd = "${pkgs.shellinabox}/bin/shellinaboxd ${concatStringsSep " " args}";
+
+  # Command to start shellinaboxd if certFile is specified
+  wrappedCmd = "${pkgs.bash}/bin/bash -c 'exec ${createFd} && ${cmd}'";
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+    services.shellinabox = {
+      enable = mkEnableOption "shellinabox daemon";
+
+      user = mkOption {
+        type = types.str;
+        default = "root";
+        description = ''
+          User to run shellinaboxd as. If started as root, the server drops
+          privileges by changing to nobody, unless overridden by the
+          <literal>--user</literal> option.
+        '';
+      };
+
+      enableSSL = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether or not to enable SSL (https) support.
+        '';
+      };
+        
+      certDirectory = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/var/certs";
+        description = ''
+          The daemon will look in this directory far any certificates.
+          If the browser negotiated a Server Name Identification the daemon
+          will look for a matching certificate-SERVERNAME.pem file. If no SNI
+          handshake takes place, it will fall back on using the certificate in the
+          certificate.pem file.
+
+          If no suitable certificate is installed, shellinaboxd will attempt to
+          create a new self-signed certificate. This will only succeed if, after
+          dropping privileges, shellinaboxd has write permissions for this
+          directory.
+        '';
+      };
+
+      certFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/var/certificate.pem";
+        description = "Path to server SSL certificate.";
+      };
+
+      extraOptions = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "--port=443" "--service /:LOGIN" ];
+        description = ''
+          A list of strings to be appended to the command line arguments
+          for shellinaboxd. Please see the manual page
+          <link xlink:href="https://code.google.com/p/shellinabox/wiki/shellinaboxd_man"/>
+          for a full list of available arguments.
+        '';
+      };
+
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    assertions =
+      [ { assertion = cfg.enableSSL == true
+            -> cfg.certDirectory != null || cfg.certFile != null;
+          message = "SSL is enabled for shellinabox, but no certDirectory or certFile has been specefied."; }
+        { assertion = ! (cfg.certDirectory != null && cfg.certFile != null);
+          message = "Cannot set both certDirectory and certFile for shellinabox."; }
+      ];
+
+    systemd.services.shellinaboxd = {
+      description = "Shellinabox Web Server Daemon";
+
+      wantedBy = [ "multi-user.target" ];
+      requires = [ "sshd.service" ];
+      after = [ "sshd.service" ];
+
+      serviceConfig = {
+        Type = "forking";
+        User = "${cfg.user}";
+        ExecStart = "${if cfg.certFile == null then "${cmd}" else "${wrappedCmd}"}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix
index 6e454a2dacd7..3e18a6f0e986 100644
--- a/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixos/modules/services/web-servers/uwsgi.nix
@@ -47,13 +47,19 @@ in {
 
   options = {
     services.uwsgi = {
-      
+
       enable = mkOption {
         type = types.bool;
         default = false;
         description = "Enable uWSGI";
       };
 
+      runDir = mkOption {
+        type = types.string;
+        default = "/run/uwsgi";
+        description = "Where uWSGI communication sockets can live";
+      };
+
       instance = mkOption {
         type = types.attrs;
         default = {
@@ -66,7 +72,7 @@ in {
               moin = {
                 type = "normal";
                 python2Packages = self: with self; [ moinmoin ];
-                socket = "/run/uwsgi.sock";
+                socket = "${config.services.uwsgi.runDir}/uwsgi.sock";
               };
             };
           }
@@ -89,24 +95,46 @@ in {
         description = "Plugins used with uWSGI";
       };
 
-    };
+      user = mkOption {
+        type = types.str;
+        default = "uwsgi";
+        description = "User account under which uwsgi runs.";
+      };
 
+      group = mkOption {
+        type = types.str;
+        default = "uwsgi";
+        description = "Group account under which uwsgi runs.";
+      };
+    };
   };
 
   config = mkIf cfg.enable {
-
     systemd.services.uwsgi = {
       wantedBy = [ "multi-user.target" ];
-      
+      preStart = ''
+        mkdir -p ${cfg.runDir}
+        chown ${cfg.user}:${cfg.group} ${cfg.runDir}
+      '';
       serviceConfig = {
         Type = "notify";
-        ExecStart = "${uwsgi}/bin/uwsgi --json ${pkgs.writeText "uwsgi.json" (buildCfg cfg.instance)}";
+        ExecStart = "${uwsgi}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${pkgs.writeText "uwsgi.json" (buildCfg cfg.instance)}";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
         NotifyAccess = "main";
         KillSignal = "SIGQUIT";
       };
-
     };
+
+    users.extraUsers = optionalAttrs (cfg.user == "uwsgi") (singleton
+      { name = "uwsgi";
+        group = cfg.group;
+        uid = config.ids.uids.uwsgi;
+      });
+
+    users.extraGroups = optionalAttrs (cfg.group == "uwsgi") (singleton
+      { name = "uwsgi";
+        gid = config.ids.gids.uwsgi;
+      });
   };
 }
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 7c8cd8aeb855..5061d59b7c7f 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -35,11 +35,11 @@ let
   phononBackendPackages = flip concatMap cfg.phononBackends
     (name: attrByPath [name] (throw "unknown phonon backend `${name}'") phononBackends);
 
-  kf5 = plasma5.kf5;
+  kf5 = pkgs.kf5_stable;
 
-  plasma5 = pkgs.plasma5_stable;
+  plasma5 = pkgs.plasma5_stable.override { inherit kf5; };
 
-  kdeApps = pkgs.kdeApps_stable;
+  kdeApps = pkgs.kdeApps_stable.override { inherit kf5; };
 
 in
 
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index c5012dbb5e30..7e05cd84be64 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -50,13 +50,19 @@ let
         exec > ~/.xsession-errors 2>&1
       ''}
 
+      ${optionalString cfg.startDbusSession ''
+        if test -z "$DBUS_SESSION_BUS_ADDRESS"; then
+          exec ${pkgs.dbus.tools}/bin/dbus-launch --exit-with-session "$0" "$sessionType"
+        fi
+      ''}
+
       ${optionalString cfg.displayManager.desktopManagerHandlesLidAndPower ''
         # Stop systemd from handling the power button and lid switch,
         # since presumably the desktop environment will handle these.
         if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then
           export _INHIBITION_LOCK_TAKEN=1
           if ! ${config.systemd.package}/bin/loginctl show-session $XDG_SESSION_ID | grep -q '^RemoteHost='; then
-            exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key "$0" "$sessionType"
+            exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key --why="See NixOS configuration option 'services.xserver.displayManager.desktopManagerHandlesLidAndPower' for more information." "$0" "$sessionType"
           fi
         fi
 
@@ -165,6 +171,7 @@ let
         Type=XSession
         TryExec=${cfg.displayManager.session.script}
         Exec=${cfg.displayManager.session.script} '${n}'
+        X-GDM-BypassXsession=true
         Name=${n}
         Comment=
         EODESKTOP
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index f6de8c02b186..bc8f478c7d83 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -33,7 +33,7 @@ let
       makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
         $out/greeter \
         --prefix PATH : "${pkgs.glibc}/bin" \
-        --set GDK_PIXBUF_MODULE_FILE "$(find ${theme} -name loaders.cache)" \
+        --set GDK_PIXBUF_MODULE_FILE "${pkgs.gdk_pixbuf}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \
         --set GTK_PATH "${theme}:${pkgs.gtk3}" \
         --set GTK_EXE_PREFIX "${theme}" \
         --set GTK_DATA_PREFIX "${theme}" \
@@ -104,7 +104,7 @@ in
       };
 
       background = mkOption {
-        default = "${pkgs.nixos-artwork}/gnome/Gnome_Dark.png";
+        default = "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png";
         description = ''
           The background image or color to use.
         '';
diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix
index c7fbfa85e335..545f4283828a 100644
--- a/nixos/modules/services/x11/display-managers/slim.nix
+++ b/nixos/modules/services/x11/display-managers/slim.nix
@@ -56,7 +56,10 @@ in
 
       theme = mkOption {
         type = types.nullOr types.path;
-        default = null;
+        default = pkgs.fetchurl {
+          url    = https://github.com/jagajaga/nixos-slim-theme/archive/1.1.tar.gz;
+          sha256 = "66c3020a6716130a20c3898567339b990fbd7888a3b7bbcb688f6544d1c05c31";
+        };
         example = literalExample ''
           pkgs.fetchurl {
             url = "mirror://sourceforge/slim.berlios/slim-wave.tar.gz";
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
index 9e44ce811c3e..e967dc911411 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -63,12 +63,30 @@ in {
       twoFingerScroll = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether to enable two-finger drag-scrolling.";
+        description = "Whether to enable two-finger drag-scrolling. Overridden by horizTwoFingerScroll and vertTwoFingerScroll.";
+      };
+
+      horizTwoFingerScroll = mkOption {
+        type = types.bool;
+        default = cfg.twoFingerScroll;
+        description = "Whether to enable horizontal two-finger drag-scrolling.";
+      };
+
+      vertTwoFingerScroll = mkOption {
+        type = types.bool;
+        default = cfg.twoFingerScroll;
+        description = "Whether to enable vertical two-finger drag-scrolling.";
+      };
+
+      horizEdgeScroll = mkOption {
+        type = types.bool;
+        default = ! cfg.horizTwoFingerScroll;
+        description = "Whether to enable horizontal edge drag-scrolling.";
       };
 
       vertEdgeScroll = mkOption {
         type = types.bool;
-        default = ! cfg.twoFingerScroll;
+        default = ! cfg.vertTwoFingerScroll;
         description = "Whether to enable vertical edge drag-scrolling.";
       };
 
@@ -147,9 +165,10 @@ in {
           Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}"
           Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}"
           Option "ClickFinger3" "${builtins.elemAt cfg.buttonsMap 2}"
-          Option "VertTwoFingerScroll" "${if cfg.twoFingerScroll then "1" else "0"}"
-          Option "HorizTwoFingerScroll" "${if cfg.twoFingerScroll then "1" else "0"}"
+          Option "VertTwoFingerScroll" "${if cfg.vertTwoFingerScroll then "1" else "0"}"
+          Option "HorizTwoFingerScroll" "${if cfg.horizTwoFingerScroll then "1" else "0"}"
           Option "VertEdgeScroll" "${if cfg.vertEdgeScroll then "1" else "0"}"
+          Option "HorizEdgeScroll" "${if cfg.horizEdgeScroll then "1" else "0"}"
           ${if cfg.palmDetect then ''Option "PalmDetect" "1"'' else ""}
           ${if cfg.horizontalScroll then "" else ''Option "HorizScrollDelta" "0"''}
           ${cfg.additionalOptions}
diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix
index d73b58de6c08..99d19f6ab151 100644
--- a/nixos/modules/services/x11/redshift.nix
+++ b/nixos/modules/services/x11/redshift.nix
@@ -14,24 +14,24 @@ in {
 
     services.redshift.latitude = mkOption {
       description = "Your current latitude";
-      type = types.uniq types.string;
+      type = types.str;
     };
 
     services.redshift.longitude = mkOption {
       description = "Your current longitude";
-      type = types.uniq types.string;
+      type = types.str;
     };
 
     services.redshift.temperature = {
       day = mkOption {
         description = "Colour temperature to use during day time";
         default = 5500;
-        type = types.uniq types.int;
+        type = types.int;
       };
       night = mkOption {
         description = "Colour temperature to use during night time";
         default = 3700;
-        type = types.uniq types.int;
+        type = types.int;
       };
     };
 
@@ -39,12 +39,12 @@ in {
       day = mkOption {
         description = "Screen brightness to apply during the day (between 0.1 and 1.0)";
         default = "1";
-        type = types.uniq types.string;
+        type = types.str;
       };
       night = mkOption {
         description = "Screen brightness to apply during the night (between 0.1 and 1.0)";
         default = "1";
-        type = types.uniq types.string;
+        type = types.str;
       };
     };
   };
diff --git a/nixos/modules/services/x11/unclutter.nix b/nixos/modules/services/x11/unclutter.nix
index 556d9e187fdd..6e8719e1053f 100644
--- a/nixos/modules/services/x11/unclutter.nix
+++ b/nixos/modules/services/x11/unclutter.nix
@@ -13,7 +13,7 @@ in {
     services.unclutter.arguments = mkOption {
       description = "Arguments to pass to unclutter command";
       default = "-idle 1";
-      type = types.uniq types.string;
+      type = types.str;
     };
   };
 
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index 097e4fe70d58..a8b1044ad365 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -16,6 +16,7 @@ in
     ./i3.nix
     ./metacity.nix
     ./openbox.nix
+    ./notion.nix
     ./ratpoison.nix
     ./sawfish.nix
     ./stumpwm.nix
diff --git a/nixos/modules/services/x11/window-managers/notion.nix b/nixos/modules/services/x11/window-managers/notion.nix
new file mode 100644
index 000000000000..1bfc2a86e965
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/notion.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.xserver.windowManager.notion;
+in
+
+{
+  options = {
+    services.xserver.windowManager.notion = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Enable the notion tiling window manager.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager = {
+      session = [{
+        name = "notion";
+        start = ''
+          ${pkgs.notion}/bin/notion &
+          waitPID=$!
+        '';
+      }];
+    };
+    environment.systemPackages = [ pkgs.notion ];
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/stumpwm.nix b/nixos/modules/services/x11/window-managers/stumpwm.nix
index a876f13fd214..eb7b8665f23c 100644
--- a/nixos/modules/services/x11/window-managers/stumpwm.nix
+++ b/nixos/modules/services/x11/window-managers/stumpwm.nix
@@ -21,9 +21,10 @@ in
   config = mkIf cfg.enable {
     services.xserver.windowManager.session = singleton {
       name = "stumpwm";
-      start = "
-        ${pkgs.stumpwm}/bin/stumpwm
-      ";
+      start = ''
+        ${pkgs.stumpwm}/bin/stumpwm &
+        waitPID=$!
+      '';
     };
     environment.systemPackages = [ pkgs.stumpwm ];
   };
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 5198864ef6ef..1ec098fded6e 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -238,6 +238,14 @@ in
         '';
       };
 
+      startDbusSession = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to start a new DBus session when you log in with dbus-launch.
+        '';
+      };
+
       layout = mkOption {
         type = types.str;
         default = "us";
@@ -469,6 +477,11 @@ in
     environment.pathsToLink =
       [ "/etc/xdg" "/share/xdg" "/share/applications" "/share/icons" "/share/pixmaps" ];
 
+    # The default max inotify watches is 8192.
+    # Nowadays most apps require a good number of inotify watches,
+    # the value below is used by default on several other distros.
+    boot.kernel.sysctl."fs.inotify.max_user_watches" = mkDefault 524288;
+
     systemd.defaultUnit = mkIf cfg.autorun "graphical.target";
 
     systemd.services.display-manager =
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index d7a1e205b4d4..839300798167 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -81,6 +81,8 @@ let
       substituteAll ${./switch-to-configuration.pl} $out/bin/switch-to-configuration
       chmod +x $out/bin/switch-to-configuration
 
+      echo -n "${toString config.system.extraDependencies}" > $out/extra-dependencies
+
       ${config.system.extraSystemBuilderCmds}
     '';
 
@@ -99,6 +101,7 @@ let
     if [] == failed then pkgs.stdenv.mkDerivation {
       name = "nixos-${config.system.nixosVersion}";
       preferLocalBuild = true;
+      allowSubstitutes = false;
       buildCommand = systemBuilder;
 
       inherit (pkgs) utillinux coreutils;
@@ -188,6 +191,16 @@ in
       '';
     };
 
+    system.extraDependencies = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      description = ''
+        A list of packages that should be included in the system
+        closure but not otherwise made available to users. This is
+        primarily used by the installation tests.
+      '';
+    };
+
     system.replaceRuntimeDependencies = mkOption {
       default = [];
       example = lib.literalExample "[ ({ original = pkgs.openssl; replacement = pkgs.callPackage /path/to/openssl { ... }; }) ]";
diff --git a/nixos/modules/system/boot/coredump.nix b/nixos/modules/system/boot/coredump.nix
new file mode 100644
index 000000000000..25b11ed9c8a9
--- /dev/null
+++ b/nixos/modules/system/boot/coredump.nix
@@ -0,0 +1,51 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  options = {
+
+    systemd.coredump = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enables storing core dumps in systemd.
+          Note that this alone is not enough to enable core dumps. The maximum
+          file size for core dumps must be specified in limits.conf as well. See
+          <option>security.pam.loginLimits</option> as well as the limits.conf(5)
+          man page.
+        '';
+      };
+
+      extraConfig = mkOption {
+        default = "";
+        type = types.lines;
+        example = "Storage=journal";
+        description = ''
+          Extra config options for systemd-coredump. See coredump.conf(5) man page
+          for available options.
+        '';
+      };
+    };
+
+  };
+
+  config = mkIf config.systemd.coredump.enable {
+
+    environment.etc."systemd/coredump.conf".text =
+      ''
+        [Coredump]
+        ${config.systemd.coredump.extraConfig}
+      '';
+
+    # Have the kernel pass core dumps to systemd's coredump helper binary.
+    # From systemd's 50-coredump.conf file. See:
+    # <https://github.com/systemd/systemd/blob/v218/sysctl.d/50-coredump.conf.in>
+    boot.kernel.sysctl."kernel.core_pattern" = "|${pkgs.systemd}/lib/systemd/systemd-coredump %p %u %g %s %t %e";
+
+  };
+
+}
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index 0cae9cb844c8..63a095be6311 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -159,7 +159,7 @@ in
 
     boot.kernel.sysctl."kernel.printk" = config.boot.consoleLogLevel;
 
-    boot.kernelModules = [ "loop" "configs" ];
+    boot.kernelModules = [ "loop" "configs" "atkbd" ];
 
     boot.initrd.availableKernelModules =
       [ # Note: most of these (especially the SATA/PATA modules)
diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix b/nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix
new file mode 100644
index 000000000000..af39c7bb6841
--- /dev/null
+++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix
@@ -0,0 +1,44 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  blCfg = config.boot.loader;
+  cfg = blCfg.generic-extlinux-compatible;
+
+  timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout;
+
+  builder = import ./extlinux-conf-builder.nix { inherit pkgs; };
+in
+{
+  options = {
+    boot.loader.generic-extlinux-compatible = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to generate an extlinux-compatible configuration file
+          under <literal>/boot/extlinux.conf</literal>.  For instance,
+          U-Boot's generic distro boot support uses this file format.
+
+          See <link xlink:href="http://git.denx.de/?p=u-boot.git;a=blob;f=doc/README.distro;hb=refs/heads/master">U-boot's documentation</link>
+          for more information.
+        '';
+      };
+
+      configurationLimit = mkOption {
+        default = 20;
+        example = 10;
+        type = types.int;
+        description = ''
+          Maximum number of configurations in the boot menu.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    system.build.installBootLoader = "${builder} -g ${toString cfg.configurationLimit} -t ${timeoutStr} -c";
+    system.boot.loader.id = "generic-extlinux-compatible";
+  };
+}
diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix
new file mode 100644
index 000000000000..261192c6d24e
--- /dev/null
+++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix
@@ -0,0 +1,8 @@
+{ pkgs }:
+
+pkgs.substituteAll {
+  src = ./extlinux-conf-builder.sh;
+  isExecutable = true;
+  inherit (pkgs) bash;
+  path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
+}
diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh
new file mode 100644
index 000000000000..8f2a496de8b6
--- /dev/null
+++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh
@@ -0,0 +1,132 @@
+#! @bash@/bin/sh -e
+
+shopt -s nullglob
+
+export PATH=/empty
+for i in @path@; do PATH=$PATH:$i/bin; done
+
+usage() {
+    echo "usage: $0 -t <timeout> -c <path-to-default-configuration> [-d <boot-dir>] [-g <num-generations>]" >&2
+    exit 1
+}
+
+timeout=                # Timeout in centiseconds
+default=                # Default configuration
+target=/boot            # Target directory
+numGenerations=0        # Number of other generations to include in the menu
+
+while getopts "t:c:d:g:" opt; do
+    case "$opt" in
+        t) # U-Boot interprets '0' as infinite and negative as instant boot
+            if [ "$OPTARG" -lt 0 ]; then
+                timeout=0
+            elif [ "$OPTARG" = 0 ]; then
+                timeout=-10
+            else
+                timeout=$((OPTARG * 10))
+            fi
+            ;;
+        c) default="$OPTARG" ;;
+        d) target="$OPTARG" ;;
+        g) numGenerations="$OPTARG" ;;
+        \?) usage ;;
+    esac
+done
+
+[ "$timeout" = "" -o "$default" = "" ] && usage
+
+mkdir -p $target/nixos
+mkdir -p $target/extlinux
+
+# Convert a path to a file in the Nix store such as
+# /nix/store/<hash>-<name>/file to <hash>-<name>-<file>.
+cleanName() {
+    local path="$1"
+    echo "$path" | sed 's|^/nix/store/||' | sed 's|/|-|g'
+}
+
+# Copy a file from the Nix store to $target/nixos.
+declare -A filesCopied
+
+copyToKernelsDir() {
+    local src=$(readlink -f "$1")
+    local dst="$target/nixos/$(cleanName $src)"
+    # Don't copy the file if $dst already exists.  This means that we
+    # have to create $dst atomically to prevent partially copied
+    # kernels or initrd if this script is ever interrupted.
+    if ! test -e $dst; then
+        local dstTmp=$dst.tmp.$$
+        cp -r $src $dstTmp
+        mv $dstTmp $dst
+    fi
+    filesCopied[$dst]=1
+    result=$dst
+}
+
+# Copy its kernel, initrd and dtbs to $target/nixos, and echo out an
+# extlinux menu entry
+addEntry() {
+    local path=$(readlink -f "$1")
+    local tag="$2" # Generation number or 'default'
+
+    if ! test -e $path/kernel -a -e $path/initrd; then
+        return
+    fi
+
+    copyToKernelsDir "$path/kernel"; kernel=$result
+    copyToKernelsDir "$path/initrd"; initrd=$result
+    # XXX UGLY: maybe the system config should have a top-level "dtbs" entry?
+    copyToKernelsDir $(readlink -m "$path/kernel/../dtbs"); dtbs=$result
+
+    timestampEpoch=$(stat -L -c '%Z' $path)
+
+    timestamp=$(date "+%Y-%m-%d %H:%M" -d @$timestampEpoch)
+    nixosVersion="$(cat $path/nixos-version)"
+    extraParams="$(cat $path/kernel-params)"
+
+    echo
+    echo "LABEL nixos-$tag"
+    if [ "$tag" = "default" ]; then
+        echo "  MENU LABEL NixOS - Default"
+    else
+        echo "  MENU LABEL NixOS - Configuration $tag ($timestamp - $nixosVersion)"
+    fi
+    echo "  LINUX ../nixos/$(basename $kernel)"
+    echo "  INITRD ../nixos/$(basename $initrd)"
+    echo "  FDTDIR ../nixos/$(basename $dtbs)"
+    echo "  APPEND systemConfig=$path init=$path/init $extraParams"
+}
+
+tmpFile="$target/extlinux/extlinux.conf.tmp.$$"
+
+cat > $tmpFile <<EOF
+# Generated file, all changes will be lost on nixos-rebuild!
+
+# Change this to e.g. nixos-42 to temporarily boot to an older configuration.
+DEFAULT nixos-default
+
+TIMEOUT $timeout
+$(addEntry $default default)
+EOF
+
+# Add up to $numGenerations generations of the system profile to the menu,
+# in reverse (most recent to least recent) order.
+for generation in $(
+        (cd /nix/var/nix/profiles && ls -d system-*-link) \
+        | sed 's/system-\([0-9]\+\)-link/\1/' \
+        | sort -n -r \
+        | head -n $numGenerations); do
+    link=/nix/var/nix/profiles/system-$generation-link
+    addEntry $link $generation
+done >> $tmpFile
+
+mv -f $tmpFile $target/extlinux/extlinux.conf
+
+# Remove obsolete files from $target/nixos.
+for fn in $target/nixos/*; do
+    if ! test "${filesCopied[$fn]}" = 1; then
+        echo "Removing no longer needed boot file: $fn"
+        chmod +w -- "$fn"
+        rm -rf -- "$fn"
+    fi
+done
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 585c8854feec..c7cf712e3c2b 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -10,7 +10,8 @@ let
 
   realGrub = if cfg.version == 1 then pkgs.grub
     else if cfg.zfsSupport then pkgs.grub2.override { zfsSupport = true; }
-    else pkgs.grub2;
+    else if cfg.enableTrustedboot then pkgs.trustedGrub
+           else pkgs.grub2;
 
   grub =
     # Don't include GRUB if we're only generating a GRUB menu (e.g.,
@@ -21,25 +22,36 @@ let
 
   grubEfi =
     # EFI version of Grub v2
-    if (cfg.devices != ["nodev"]) && cfg.efiSupport && (cfg.version == 2)
+    if cfg.efiSupport && (cfg.version == 2)
     then realGrub.override { efiSupport = cfg.efiSupport; }
     else null;
 
   f = x: if x == null then "" else "" + x;
 
-  grubConfig = pkgs.writeText "grub-config.xml" (builtins.toXML
-    { splashImage = f config.boot.loader.grub.splashImage;
+  grubConfig = args:
+    let
+      efiSysMountPoint = if args.efiSysMountPoint == null then args.path else args.efiSysMountPoint;
+      efiSysMountPoint' = replaceChars [ "/" ] [ "-" ] efiSysMountPoint;
+    in
+    pkgs.writeText "grub-config.xml" (builtins.toXML
+    { splashImage = f cfg.splashImage;
       grub = f grub;
       grubTarget = f (grub.grubTarget or "");
       shell = "${pkgs.stdenv.shell}";
+      fullName = (builtins.parseDrvName realGrub.name).name;
       fullVersion = (builtins.parseDrvName realGrub.name).version;
       grubEfi = f grubEfi;
       grubTargetEfi = if cfg.efiSupport && (cfg.version == 2) then f (grubEfi.grubTarget or "") else "";
-      inherit (efi) efiSysMountPoint canTouchEfiVariables;
+      bootPath = args.path;
+      storePath = config.boot.loader.grub.storePath;
+      bootloaderId = if args.efiBootloaderId == null then "NixOS${efiSysMountPoint'}" else args.efiBootloaderId;
+      inherit efiSysMountPoint;
+      inherit (args) devices;
+      inherit (efi) canTouchEfiVariables;
       inherit (cfg)
         version extraConfig extraPerEntryConfig extraEntries
         extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
-        default devices fsIdentifier efiSupport;
+        default fsIdentifier efiSupport gfxmodeEfi gfxmodeBios;
       path = (makeSearchPath "bin" ([
         pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs
         pkgs.utillinux ] ++ (if cfg.efiSupport && (cfg.version == 2) then [pkgs.efibootmgr ] else [])
@@ -48,6 +60,9 @@ let
       ]);
     });
 
+  bootDeviceCounters = fold (device: attr: attr // { "${device}" = (attr."${device}" or 0) + 1; }) {}
+    (concatMap (args: args.devices) cfg.mirroredBoots);
+
 in
 
 {
@@ -101,6 +116,64 @@ in
         '';
       };
 
+      mirroredBoots = mkOption {
+        default = [ ];
+        example = [
+          { path = "/boot1"; devices = [ "/dev/sda" ]; }
+          { path = "/boot2"; devices = [ "/dev/sdb" ]; }
+        ];
+        description = ''
+          Mirror the boot configuration to multiple partitions and install grub
+          to the respective devices corresponding to those partitions.
+        '';
+
+        type = types.listOf types.optionSet;
+
+        options = {
+
+          path = mkOption {
+            example = "/boot1";
+            type = types.str;
+            description = ''
+              The path to the boot directory where grub will be written. Generally
+              this boot parth should double as an efi path.
+            '';
+          };
+
+          efiSysMountPoint = mkOption {
+            default = null;
+            example = "/boot1/efi";
+            type = types.nullOr types.str;
+            description = ''
+              The path to the efi system mount point. Usually this is the same
+              partition as the above path and can be left as null.
+            '';
+          };
+
+          efiBootloaderId = mkOption {
+            default = null;
+            example = "NixOS-fsid";
+            type = types.nullOr types.str;
+            description = ''
+              The id of the bootloader to store in efi nvram.
+              The default is to name it NixOS and append the path or efiSysMountPoint.
+              This is only used if <literal>boot.loader.efi.canTouchEfiVariables</literal> is true.
+            '';
+          };
+
+          devices = mkOption {
+            default = [ ];
+            example = [ "/dev/sda" "/dev/sdb" ];
+            type = types.listOf types.str;
+            description = ''
+              The path to the devices which will have the grub mbr written.
+              Note these are typically device paths and not paths to partitions.
+            '';
+          };
+
+        };
+      };
+
       configurationName = mkOption {
         default = "";
         example = "Stable 2.6.21";
@@ -110,6 +183,15 @@ in
         '';
       };
 
+      storePath = mkOption {
+        default = "/nix/store";
+        type = types.str;
+        description = ''
+          Path to the Nix store when looking for kernels at boot.
+          Only makes sense when copyKernels is false.
+        '';
+      };
+
       extraPrepareConfig = mkOption {
         default = "";
         type = types.lines;
@@ -189,6 +271,24 @@ in
         '';
       };
 
+      gfxmodeEfi = mkOption {
+        default = "auto";
+        example = "1024x768";
+        type = types.str;
+        description = ''
+          The gfxmode to pass to grub when loading a graphical boot interface under efi.
+        '';
+      };
+
+      gfxmodeBios = mkOption {
+        default = "1024x768";
+        example = "auto";
+        type = types.str;
+        description = ''
+          The gfxmode to pass to grub when loading a graphical boot interface under bios.
+        '';
+      };
+
       configurationLimit = mkOption {
         default = 100;
         example = 120;
@@ -269,6 +369,15 @@ in
         '';
       };
 
+      enableTrustedboot = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable trusted boot. Grub will measure all critical components during
+          the boot process to offer TCG (TPM) support.
+        '';
+      };
+
     };
 
   };
@@ -284,20 +393,25 @@ in
           sha256 = "14kqdx2lfqvh40h6fjjzqgff1mwk74dmbjvmqphi6azzra7z8d59";
         }
         # GRUB 1.97 doesn't support gzipped XPMs.
-        else ./winkler-gnu-blue-640x480.png);
+        else "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png");
     }
 
     (mkIf cfg.enable {
 
       boot.loader.grub.devices = optional (cfg.device != "") cfg.device;
 
-      system.build.installBootLoader =
-        if cfg.devices == [] then
-          throw "You must set the option ‘boot.loader.grub.device’ to make the system bootable."
-        else
-          "PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX ListCompare ])} " +
-          (if cfg.enableCryptodisk then "GRUB_ENABLE_CRYPTODISK=y " else "") +
-          "${pkgs.perl}/bin/perl ${./install-grub.pl} ${grubConfig}";
+      boot.loader.grub.mirroredBoots = optionals (cfg.devices != [ ]) [
+        { path = "/boot"; inherit (cfg) devices; inherit (efi) efiSysMountPoint; }
+      ];
+
+      system.build.installBootLoader = 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} $@
+      ''));
 
       system.build.grub = grub;
 
@@ -312,13 +426,53 @@ in
           ${pkgs.coreutils}/bin/cp -pf "${v}" "/boot/${n}"
         '') config.boot.loader.grub.extraFiles);
 
-    assertions = [{ assertion = !cfg.zfsSupport || cfg.version == 2;
-                    message = "Only grub version 2 provides zfs support";}]
-      ++ flip map cfg.devices (dev: {
-        assertion = dev == "nodev" || hasPrefix "/" dev;
-        message = "Grub devices must be absolute paths, not ${dev}";
-      });
-
+      assertions = [
+        {
+          assertion = !cfg.zfsSupport || cfg.version == 2;
+          message = "Only grub version 2 provides zfs support";
+        }
+        {
+          assertion = cfg.mirroredBoots != [ ];
+          message = "You must set the option ‘boot.loader.grub.devices’ or "
+            + "'boot.loader.grub.mirroredBoots' to make the system bootable.";
+        }
+        {
+          assertion = all (c: c < 2) (mapAttrsToList (_: c: c) bootDeviceCounters);
+          message = "You cannot have duplicated devices in mirroredBoots";
+        }
+        {
+          assertion = !cfg.enableTrustedboot || cfg.version == 2;
+          message = "Trusted GRUB is only available for GRUB 2";
+        }
+        {
+          assertion = !cfg.efiSupport || !cfg.enableTrustedboot;
+          message = "Trusted GRUB does not have EFI support";
+        }
+        {
+          assertion = !cfg.zfsSupport || !cfg.enableTrustedboot;
+          message = "Trusted GRUB does not have ZFS support";
+        }
+        {
+          assertion = !cfg.enableTrustedboot;
+          message = "Trusted GRUB can break your system. Remove assertion if you want to test trustedGRUB nevertheless.";
+        }
+      ] ++ flip concatMap cfg.mirroredBoots (args: [
+        {
+          assertion = args.devices != [ ];
+          message = "A boot path cannot have an empty devices string in ${arg.path}";
+        }
+        {
+          assertion = hasPrefix "/" args.path;
+          message = "Boot paths must be absolute, not ${args.path}";
+        }
+        {
+          assertion = if args.efiSysMountPoint == null then true else hasPrefix "/" args.efiSysMountPoint;
+          message = "Efi paths must be absolute, not ${args.efiSysMountPoint}";
+        }
+      ] ++ flip map args.devices (device: {
+        assertion = device == "nodev" || hasPrefix "/" device;
+        message = "Grub devices must be absolute paths, not ${dev} in ${args.path}";
+      }));
     })
 
   ];
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index 81009e9fb821..34bff727b73a 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -7,6 +7,7 @@ use File::Path;
 use File::stat;
 use File::Copy;
 use File::Slurp;
+use File::Temp;
 require List::Compare;
 use POSIX;
 use Cwd;
@@ -54,24 +55,29 @@ my $defaultEntry = int(get("default"));
 my $fsIdentifier = get("fsIdentifier");
 my $grubEfi = get("grubEfi");
 my $grubTargetEfi = get("grubTargetEfi");
+my $bootPath = get("bootPath");
+my $storePath = get("storePath");
 my $canTouchEfiVariables = get("canTouchEfiVariables");
 my $efiSysMountPoint = get("efiSysMountPoint");
+my $gfxmodeEfi = get("gfxmodeEfi");
+my $gfxmodeBios = get("gfxmodeBios");
+my $bootloaderId = get("bootloaderId");
 $ENV{'PATH'} = get("path");
 
 die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;
 
 print STDERR "updating GRUB $grubVersion menu...\n";
 
-mkpath("/boot/grub", 0, 0700);
+mkpath("$bootPath/grub", 0, 0700);
 
-# Discover whether /boot is on the same filesystem as / and
+# Discover whether the bootPath is on the same filesystem as / and
 # /nix/store.  If not, then all kernels and initrds must be copied to
-# /boot.
-if (stat("/boot")->dev != stat("/nix/store")->dev) {
+# the bootPath.
+if (stat($bootPath)->dev != stat("/nix/store")->dev) {
     $copyKernels = 1;
 }
 
-# Discover information about the location of /boot
+# Discover information about the location of the bootPath
 struct(Fs => {
     device => '$',
     type => '$',
@@ -180,7 +186,7 @@ sub GrubFs {
                 if ($status != 0) {
                     die "Failed to retrieve subvolume info for @{[$fs->mount]}\n";
                 }
-                my @ids = join("", @id_info) =~ m/Object ID:[ \t\n]*([^ \t\n]*)/;
+                my @ids = join("", @id_info) =~ m/Subvolume ID:[ \t\n]*([^ \t\n]*)/;
                 if ($#ids > 0) {
                     die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
                 } elsif ($#ids == 0) {
@@ -206,10 +212,10 @@ sub GrubFs {
     }
     return Grub->new(path => $path, search => $search);
 }
-my $grubBoot = GrubFs("/boot");
+my $grubBoot = GrubFs($bootPath);
 my $grubStore;
 if ($copyKernels == 0) {
-    $grubStore = GrubFs("/nix/store");
+    $grubStore = GrubFs($storePath);
 }
 
 # Generate the header.
@@ -221,7 +227,7 @@ if ($grubVersion == 1) {
         timeout $timeout
     ";
     if ($splashImage) {
-        copy $splashImage, "/boot/background.xpm.gz" or die "cannot copy $splashImage to /boot\n";
+        copy $splashImage, "$bootPath/background.xpm.gz" or die "cannot copy $splashImage to $bootPath\n";
         $conf .= "splashimage " . $grubBoot->path . "/background.xpm.gz\n";
     }
 }
@@ -253,10 +259,23 @@ else {
           set timeout=$timeout
         fi
 
+        # Setup the graphics stack for bios and efi systems
+        if [ \"\${grub_platform}\" = \"efi\" ]; then
+          insmod efi_gop
+          insmod efi_uga
+        else
+          insmod vbe
+        fi
+        insmod font
         if loadfont " . $grubBoot->path . "/grub/fonts/unicode.pf2; then
-          set gfxmode=640x480
           insmod gfxterm
-          insmod vbe
+          if [ \"\${grub_platform}\" = \"efi\" ]; then
+            set gfxmode=$gfxmodeEfi
+            set gfxpayload=keep
+          else
+            set gfxmode=$gfxmodeBios
+            set gfxpayload=text
+          fi
           terminal_output gfxterm
         fi
     ";
@@ -264,7 +283,7 @@ else {
     if ($splashImage) {
         # FIXME: GRUB 1.97 doesn't resize the background image if it
         # doesn't match the video resolution.
-        copy $splashImage, "/boot/background.png" or die "cannot copy $splashImage to /boot\n";
+        copy $splashImage, "$bootPath/background.png" or die "cannot copy $splashImage to $bootPath\n";
         $conf .= "
             insmod png
             if background_image " . $grubBoot->path . "/background.png; then
@@ -285,14 +304,14 @@ $conf .= "$extraConfig\n";
 $conf .= "\n";
 
 my %copied;
-mkpath("/boot/kernels", 0, 0755) if $copyKernels;
+mkpath("$bootPath/kernels", 0, 0755) if $copyKernels;
 
 sub copyToKernelsDir {
     my ($path) = @_;
     return $grubStore->path . substr($path, length("/nix/store")) unless $copyKernels;
     $path =~ /\/nix\/store\/(.*)/ or die;
     my $name = $1; $name =~ s/\//-/g;
-    my $dst = "/boot/kernels/$name";
+    my $dst = "$bootPath/kernels/$name";
     # Don't copy the file if $dst already exists.  This means that we
     # have to create $dst atomically to prevent partially copied
     # kernels or initrd if this script is ever interrupted.
@@ -396,14 +415,14 @@ if ($extraPrepareConfig ne "") {
 }
 
 # Atomically update the GRUB config.
-my $confFile = $grubVersion == 1 ? "/boot/grub/menu.lst" : "/boot/grub/grub.cfg";
+my $confFile = $grubVersion == 1 ? "$bootPath/grub/menu.lst" : "$bootPath/grub/grub.cfg";
 my $tmpFile = $confFile . ".tmp";
 writeFile($tmpFile, $conf);
 rename $tmpFile, $confFile or die "cannot rename $tmpFile to $confFile\n";
 
 
-# Remove obsolete files from /boot/kernels.
-foreach my $fn (glob "/boot/kernels/*") {
+# Remove obsolete files from $bootPath/kernels.
+foreach my $fn (glob "$bootPath/kernels/*") {
     next if defined $copied{$fn};
     print STDERR "removing obsolete file $fn\n";
     unlink $fn;
@@ -415,15 +434,18 @@ foreach my $fn (glob "/boot/kernels/*") {
 #
 
 struct(GrubState => {
+    name => '$',
     version => '$',
     efi => '$',
     devices => '$',
     efiMountPoint => '$',
 });
 sub readGrubState {
-    my $defaultGrubState = GrubState->new(version => "", efi => "", devices => "", efiMountPoint => "" );
-    open FILE, "</boot/grub/state" or return $defaultGrubState;
+    my $defaultGrubState = GrubState->new(name => "", version => "", efi => "", devices => "", efiMountPoint => "" );
+    open FILE, "<$bootPath/grub/state" or return $defaultGrubState;
     local $/ = "\n";
+    my $name = <FILE>;
+    chomp($name);
     my $version = <FILE>;
     chomp($version);
     my $efi = <FILE>;
@@ -433,7 +455,7 @@ sub readGrubState {
     my $efiMountPoint = <FILE>;
     chomp($efiMountPoint);
     close FILE;
-    my $grubState = GrubState->new(version => $version, efi => $efi, devices => $devices, efiMountPoint => $efiMountPoint );
+    my $grubState = GrubState->new(name => $name, version => $version, efi => $efi, devices => $devices, efiMountPoint => $efiMountPoint );
     return $grubState
 }
 
@@ -478,12 +500,16 @@ my $efiTarget = getEfiTarget();
 my $prevGrubState = readGrubState();
 my @prevDeviceTargets = split/:/, $prevGrubState->devices;
 
-my $devicesDiffer = scalar (List::Compare->new( '-u', '-a', \@deviceTargets, \@prevDeviceTargets)->get_symmetric_difference() );
-my $versionDiffer = (get("fullVersion") eq \$prevGrubState->version);
-my $efiDiffer = ($efiTarget eq \$prevGrubState->efi);
-my $efiMountPointDiffer = ($efiSysMountPoint eq \$prevGrubState->efiMountPoint);
-my $requireNewInstall = $devicesDiffer || $versionDiffer || $efiDiffer || $efiMountPointDiffer || (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1");
+my $devicesDiffer = scalar (List::Compare->new( '-u', '-a', \@deviceTargets, \@prevDeviceTargets)->get_symmetric_difference());
+my $nameDiffer = get("fullName") ne $prevGrubState->name;
+my $versionDiffer = get("fullVersion") ne $prevGrubState->version;
+my $efiDiffer = $efiTarget ne $prevGrubState->efi;
+my $efiMountPointDiffer = $efiSysMountPoint ne $prevGrubState->efiMountPoint;
+my $requireNewInstall = $devicesDiffer || $nameDiffer || $versionDiffer || $efiDiffer || $efiMountPointDiffer || (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1");
 
+# install a symlink so that grub can detect the boot drive
+my $tmpDir = File::Temp::tempdir(CLEANUP => 1) or die "Failed to create temporary space";
+symlink "$bootPath", "$tmpDir/boot" or die "Failed to symlink $tmpDir/boot";
 
 # install non-EFI GRUB
 if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) {
@@ -491,10 +517,10 @@ if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) {
         next if $dev eq "nodev";
         print STDERR "installing the GRUB $grubVersion boot loader on $dev...\n";
         if ($grubTarget eq "") {
-            system("$grub/sbin/grub-install", "--recheck", Cwd::abs_path($dev)) == 0
+            system("$grub/sbin/grub-install", "--recheck", "--root-directory=$tmpDir", Cwd::abs_path($dev)) == 0
                 or die "$0: installation of GRUB on $dev failed\n";
         } else {
-            system("$grub/sbin/grub-install", "--recheck", "--target=$grubTarget", Cwd::abs_path($dev)) == 0
+            system("$grub/sbin/grub-install", "--recheck", "--root-directory=$tmpDir", "--target=$grubTarget", Cwd::abs_path($dev)) == 0
                 or die "$0: installation of GRUB on $dev failed\n";
         }
     }
@@ -505,10 +531,10 @@ if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) {
 if (($requireNewInstall != 0) && ($efiTarget eq "only" || $efiTarget eq "both")) {
     print STDERR "installing the GRUB $grubVersion EFI boot loader into $efiSysMountPoint...\n";
     if ($canTouchEfiVariables eq "true") {
-        system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--efi-directory=$efiSysMountPoint") == 0
+        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";
     } else {
-        system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--efi-directory=$efiSysMountPoint", "--no-nvram") == 0
+        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";
     }
 }
@@ -516,7 +542,8 @@ if (($requireNewInstall != 0) && ($efiTarget eq "only" || $efiTarget eq "both"))
 
 # update GRUB state file
 if ($requireNewInstall != 0) {
-    open FILE, ">/boot/grub/state" or die "cannot create /boot/grub/state: $!\n";
+    open FILE, ">$bootPath/grub/state" or die "cannot create $bootPath/grub/state: $!\n";
+    print FILE get("fullName"), "\n" or die;
     print FILE get("fullVersion"), "\n" or die;
     print FILE $efiTarget, "\n" or die;
     print FILE join( ":", @deviceTargets ), "\n" or die;
diff --git a/nixos/modules/system/boot/loader/grub/winkler-gnu-blue-640x480.png b/nixos/modules/system/boot/loader/grub/winkler-gnu-blue-640x480.png
deleted file mode 100644
index 35bbb57b51ee..000000000000
--- a/nixos/modules/system/boot/loader/grub/winkler-gnu-blue-640x480.png
+++ /dev/null
Binary files differdiff --git a/nixos/modules/system/boot/loader/grub/winkler-gnu-blue.README b/nixos/modules/system/boot/loader/grub/winkler-gnu-blue.README
deleted file mode 100644
index 9616362dce2a..000000000000
--- a/nixos/modules/system/boot/loader/grub/winkler-gnu-blue.README
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a resized version of
-
-  http://www.gnu.org/graphics/winkler-gnu-blue.png
-
-by Kyle Winkler and released under the Free Art License
-(http://artlibre.org/licence.php/lalgb.html).
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 03070bef483a..1b4f0d401e6d 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -5,7 +5,7 @@ with lib;
 let
   luks = config.boot.initrd.luks;
 
-  openCommand = { name, device, keyFile, keyFileSize, allowDiscards, yubikey, ... }: ''
+  openCommand = { name, device, header, keyFile, keyFileSize, allowDiscards, yubikey, ... }: ''
     # Wait for luksRoot to appear, e.g. if on a usb drive.
     # XXX: copied and adapted from stage-1-init.sh - should be
     # available as a function.
@@ -33,6 +33,7 @@ let
 
     open_normally() {
         cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} \
+          ${optionalString (header != null) "--header=${header}"} \
           ${optionalString (keyFile != null) "--key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}"}
     }
 
@@ -211,7 +212,7 @@ in
     };
 
     boot.initrd.luks.cryptoModules = mkOption {
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       default =
         [ "aes" "aes_generic" "blowfish" "twofish"
           "serpent" "cbc" "xts" "lrw" "sha1" "sha256" "sha512"
@@ -251,6 +252,16 @@ in
           description = "Path of the underlying block device.";
         };
 
+        header = mkOption {
+          default = null;
+          example = "/root/header.img";
+          type = types.nullOr types.string;
+          description = ''
+            The name of the file or block device that
+            should be used as header for the encrypted device.
+          '';
+        };
+
         keyFile = mkOption {
           default = null;
           example = "/dev/sdb1";
diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix
index a1feaad6132d..a3b616ff3eff 100644
--- a/nixos/modules/system/boot/modprobe.nix
+++ b/nixos/modules/system/boot/modprobe.nix
@@ -101,7 +101,7 @@ with lib;
         echo ${config.system.sbin.modprobe}/sbin/modprobe > /proc/sys/kernel/modprobe
       '';
 
-    environment.variables.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules";
+    environment.sessionVariables.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules";
 
   };
 
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index a6df6216ddb4..26cf7f06c9ed 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -317,7 +317,7 @@ mountFS() {
 
 
 # Try to find and mount the root device.
-mkdir /mnt-root
+mkdir -p $targetRoot
 
 exec 3< @fsInfo@
 
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 8b58eccdcec7..893861a2eed2 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -358,7 +358,7 @@ in
     boot.initrd.supportedFilesystems = mkOption {
       default = [ ];
       example = [ "btrfs" ];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       description = "Names of supported filesystem types in the initial ramdisk.";
     };
 
diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix
index 873fff15d384..8acaa5212f5f 100644
--- a/nixos/modules/system/boot/systemd-lib.nix
+++ b/nixos/modules/system/boot/systemd-lib.nix
@@ -13,13 +13,20 @@ rec {
       pathSafeName = lib.replaceChars ["@" ":" "\\"] ["-" "-" "-"] name;
     in
     if unit.enable then
-      pkgs.runCommand "unit-${pathSafeName}" { preferLocalBuild = true; inherit (unit) text; }
+      pkgs.runCommand "unit-${pathSafeName}"
+        { preferLocalBuild = true;
+          allowSubstitutes = false;
+          inherit (unit) text;
+        }
         ''
           mkdir -p $out
           echo -n "$text" > $out/${shellEscape name}
         ''
     else
-      pkgs.runCommand "unit-${pathSafeName}-disabled" { preferLocalBuild = true; }
+      pkgs.runCommand "unit-${pathSafeName}-disabled"
+        { preferLocalBuild = true;
+          allowSubstitutes = false;
+        }
         ''
           mkdir -p $out
           ln -s /dev/null $out/${shellEscape name}
@@ -89,7 +96,10 @@ rec {
         as));
 
   generateUnits = type: units: upstreamUnits: upstreamWants:
-    pkgs.runCommand "${type}-units" { preferLocalBuild = true; } ''
+    pkgs.runCommand "${type}-units"
+      { preferLocalBuild = true;
+        allowSubstitutes = false;
+      } ''
       mkdir -p $out
 
       # Copy the upstream systemd units we're interested in.
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index 57831a5e6ef3..a7a334dec285 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -42,13 +42,13 @@ in rec {
 
     requiredBy = mkOption {
       default = [];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       description = "Units that require (i.e. depend on and need to go down with) this unit.";
     };
 
     wantedBy = mkOption {
       default = [];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       description = "Units that want (i.e. depend on) this unit.";
     };
 
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 99fd2544e708..c4c84784feac 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -490,7 +490,7 @@ in
 
     services.journald.rateLimitBurst = mkOption {
       default = 100;
-      type = types.uniq types.int;
+      type = types.int;
       description = ''
         Configures the rate limiting burst limit (number of messages per
         interval) that is applied to all messages generated on the system.
diff --git a/nixos/modules/system/etc/etc.nix b/nixos/modules/system/etc/etc.nix
index b57b03bcf962..300ae0acda53 100644
--- a/nixos/modules/system/etc/etc.nix
+++ b/nixos/modules/system/etc/etc.nix
@@ -14,6 +14,7 @@ let
     builder = ./make-etc.sh;
 
     preferLocalBuild = true;
+    allowSubstitutes = false;
 
     /* !!! Use toXML. */
     sources = map (x: x.source) etc';
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index ce8d6079faac..ce21d9fe7621 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -121,7 +121,7 @@ in
     boot.supportedFilesystems = mkOption {
       default = [ ];
       example = [ "btrfs" ];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       description = "Names of supported filesystem types.";
     };
 
diff --git a/nixos/modules/tasks/filesystems/exfat.nix b/nixos/modules/tasks/filesystems/exfat.nix
new file mode 100644
index 000000000000..963bc940b4fa
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/exfat.nix
@@ -0,0 +1,11 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  config = mkIf (any (fs: fs == "exfat") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.exfat-utils pkgs.fuse_exfat ];
+
+  };
+}
diff --git a/nixos/modules/tasks/kbd.nix b/nixos/modules/tasks/kbd.nix
index 8d26998021d3..69f004888f55 100644
--- a/nixos/modules/tasks/kbd.nix
+++ b/nixos/modules/tasks/kbd.nix
@@ -22,7 +22,7 @@ in
     # FIXME: still needed?
     boot.extraTTYs = mkOption {
       default = [];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       example = ["tty8" "tty9"];
       description = ''
         Tty (virtual console) devices, in addition to the consoles on
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 71a721abba21..6361ed2cc431 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -392,7 +392,7 @@ in
 
         interfaces = mkOption {
           example = [ "eth0" "eth1" ];
-          type = types.listOf types.string;
+          type = types.listOf types.str;
           description =
             "The physical network interfaces connected by the bridge.";
         };
diff --git a/nixos/modules/tasks/trackpoint.nix b/nixos/modules/tasks/trackpoint.nix
index 778cdc5d30dd..bd340869d69f 100644
--- a/nixos/modules/tasks/trackpoint.nix
+++ b/nixos/modules/tasks/trackpoint.nix
@@ -45,6 +45,16 @@ with lib;
         '';
       };
 
+      fakeButtons = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Switch to "bare" PS/2 mouse support in case Trackpoint buttons are not recognized
+          properly. This can happen for example on models like the L430, T450, T450s, on
+          which the Trackpoint buttons are actually a part of the Synaptics touchpad.
+        '';
+      };
+
     };
 
   };
@@ -52,11 +62,13 @@ with lib;
 
   ###### implementation
 
-  config = mkMerge [
-    (mkIf config.hardware.trackpoint.enable {
+  config =
+  let cfg = config.hardware.trackpoint; in
+  mkMerge [
+    (mkIf cfg.enable {
       services.udev.extraRules =
       ''
-        ACTION=="add|change", SUBSYSTEM=="input", ATTR{name}=="TPPS/2 IBM TrackPoint", ATTR{device/speed}="${toString config.hardware.trackpoint.speed}", ATTR{device/sensitivity}="${toString config.hardware.trackpoint.sensitivity}"
+        ACTION=="add|change", SUBSYSTEM=="input", ATTR{name}=="TPPS/2 IBM TrackPoint", ATTR{device/speed}="${toString cfg.speed}", ATTR{device/sensitivity}="${toString cfg.sensitivity}"
       '';
 
       system.activationScripts.trackpoint =
@@ -65,20 +77,22 @@ with lib;
         '';
     })
 
-    (mkIf config.hardware.trackpoint.emulateWheel {
-      services.xserver.config =
-        ''
-          Section "InputClass"
-            Identifier "Trackpoint Wheel Emulation"
-            MatchProduct "Elantech PS/2 TrackPoint|TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint"
-            MatchDevicePath "/dev/input/event*"
-            Option "EmulateWheel" "true"
-            Option "EmulateWheelButton" "2"
-            Option "Emulate3Buttons" "false"
-            Option "XAxisMapping" "6 7"
-            Option "YAxisMapping" "4 5"
-            EndSection
-        '';
+    (mkIf (cfg.emulateWheel) {
+      services.xserver.inputClassSections =
+        [''
+        Identifier "Trackpoint Wheel Emulation"
+          MatchProduct "${if cfg.fakeButtons then "PS/2 Generic Mouse" else "Elantech PS/2 TrackPoint|TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint"}"
+          MatchDevicePath "/dev/input/event*"
+          Option "EmulateWheel" "true"
+          Option "EmulateWheelButton" "2"
+          Option "Emulate3Buttons" "false"
+          Option "XAxisMapping" "6 7"
+          Option "YAxisMapping" "4 5"
+        ''];
+    })
+
+    (mkIf cfg.fakeButtons {
+      boot.extraModprobeConfig = "options psmouse proto=bare";
     })
   ];
 }
diff --git a/nixos/modules/virtualisation/amazon-init.nix b/nixos/modules/virtualisation/amazon-init.nix
new file mode 100644
index 000000000000..21cbbfda0b68
--- /dev/null
+++ b/nixos/modules/virtualisation/amazon-init.nix
@@ -0,0 +1,51 @@
+{ config, pkgs, modulesPath, ... }:
+
+# This attempts to pull a nix expression from this EC2 instance's user-data.
+
+let
+  bootScript = pkgs.writeScript "bootscript.sh" ''
+    #!${pkgs.stdenv.shell} -eux
+
+    echo "attempting to fetch configuration from user-data..."
+
+    export PATH=${config.nix.package}/bin:${pkgs.wget}/bin:${pkgs.systemd}/bin:${pkgs.gnugrep}/bin:${pkgs.gnused}/bin:${config.system.build.nixos-rebuild}/bin:$PATH
+    export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels
+
+    userData="$(mktemp)"
+    wget -q --wait=1 --tries=0 --retry-connrefused -O - http://169.254.169.254/2011-01-01/user-data > "$userData"
+
+    if [[ $? -eq 0 ]]; then
+      echo "user-data fetched"
+      # If the user-data looks like it could be a nix expression,
+      # copy it over. Also, look for a magic three-hash comment and set
+      # that as the channel.
+      if sed '/^\(#\|SSH_HOST_.*\)/d' < "$userData" | grep -q '\S'; then
+        channels="$(grep '^###' "$userData" | sed 's|###\s*||')"
+        printf "%s" "$channels" | while read channel; do
+          echo "writing channel: $channel"
+        done
+
+        if [[ -n "$channels" ]]; then
+          printf "%s" "$channels" > /root/.nix-channels
+          nix-channel --update
+        fi
+
+        echo "setting configuration"
+        cp "$userData" /etc/nixos/configuration.nix
+      else
+        echo "user-data does not appear to be a nix expression; ignoring"
+      fi
+    else
+      echo "failed to fetch user-data"
+    fi
+
+    type -f nixos-rebuild
+
+    nixos-rebuild switch
+  '';
+in {
+  imports = [ "${modulesPath}/virtualisation/amazon-image.nix" ];
+  boot.postBootCommands = ''
+    ${bootScript} &
+  '';
+}
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index 5be76b2682f5..ef9cc2280db7 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -45,7 +45,7 @@ in
       };
     extraOptions =
       mkOption {
-        type = types.str;
+        type = types.separatedString " ";
         default = "";
         description =
           ''
@@ -103,6 +103,9 @@ in
           LimitNPROC = 1048576;
         } // proxy_env;
 
+        path = [ pkgs.kmod ];
+        environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules";
+
         postStart = ''
           while ! [ -e /var/run/docker.sock ]; do
             sleep 0.1
diff --git a/nixos/modules/virtualisation/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix
index fd062237bb07..44a582ba7666 100644
--- a/nixos/modules/virtualisation/ec2-data.nix
+++ b/nixos/modules/virtualisation/ec2-data.nix
@@ -7,16 +7,6 @@
 with lib;
 
 {
-  options = {
-    ec2.metadata = mkOption {
-      type = types.bool;
-      default = false;
-      description = ''
-        Whether to allow access to EC2 metadata.
-      '';
-    };
-  };
-
   config = {
 
     systemd.services."fetch-ec2-data" =
@@ -31,8 +21,6 @@ with lib;
 
         script =
           ''
-            ip route del blackhole 169.254.169.254/32 || true
-
             wget="wget -q --retry-connrefused -O -"
 
             ${optionalString (config.networking.hostName == "") ''
@@ -67,14 +55,6 @@ with lib;
                 (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key)
                 echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub
             fi
-
-            ${optionalString (! config.ec2.metadata) ''
-              # Since the user data is sensitive, prevent it from
-              # being accessed from now on. FIXME: remove at some
-              # point, since current NixOps no longer relies on
-              # metadata secrecy.
-              ip route add blackhole 169.254.169.254/32
-            ''}
           '';
 
         serviceConfig.Type = "oneshot";
@@ -91,7 +71,7 @@ with lib;
             # can obtain it securely by parsing the output of
             # ec2-get-console-output.
             echo "-----BEGIN SSH HOST KEY FINGERPRINTS-----" > /dev/console
-            ${pkgs.openssh}/bin/ssh-keygen -l -f /etc/ssh/ssh_host_dsa_key.pub > /dev/console
+            ${config.programs.ssh.package}/bin/ssh-keygen -l -f /etc/ssh/ssh_host_dsa_key.pub > /dev/console
             echo "-----END SSH HOST KEY FINGERPRINTS-----" > /dev/console
           '';
         serviceConfig.Type = "oneshot";
diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix
index ee5485071a35..516da926f847 100644
--- a/nixos/modules/virtualisation/google-compute-image.nix
+++ b/nixos/modules/virtualisation/google-compute-image.nix
@@ -137,40 +137,50 @@ in
       after = [ "network-online.target" "ip-up.target" ];
       wants = [ "network-online.target" "ip-up.target" ];
 
-      script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; in
+      script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'";
+                   mktemp = "mktemp --tmpdir=/run"; in
         ''
           # When dealing with cryptographic keys, we want to keep things private.
           umask 077
           # Don't download the SSH key if it has already been downloaded
-          if ! [ -e /root/.ssh/authorized_keys ]; then
-                echo "obtaining SSH key..."
-                mkdir -m 0700 -p /root/.ssh
-                ${wget} -O /root/authorized-keys-metadata http://metadata.google.internal/0.1/meta-data/authorized-keys
-                if [ $? -eq 0 -a -e /root/authorized-keys-metadata ]; then
-                    cat /root/authorized-keys-metadata | cut -d: -f2- > /root/key.pub
-                    if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then
-                        cat /root/key.pub >> /root/.ssh/authorized_keys
-                        echo "new key added to authorized_keys"
-                    fi
-                    chmod 600 /root/.ssh/authorized_keys
-                fi
-                rm -f /root/key.pub /root/authorized-keys-metadata
+          if ! [ -s /root/.ssh/authorized_keys ]; then
+              echo "obtaining SSH key..."
+              mkdir -m 0700 -p /root/.ssh
+              AUTH_KEYS=$(${mktemp})
+              ${wget} -O $AUTH_KEYS http://metadata.google.internal/0.1/meta-data/authorized-keys
+              if [ -s $AUTH_KEYS ]; then
+                  KEY_PUB=$(${mktemp})
+                  cat $AUTH_KEYS | cut -d: -f2- > $KEY_PUB
+                  if ! grep -q -f $KEY_PUB /root/.ssh/authorized_keys; then
+                      cat $KEY_PUB >> /root/.ssh/authorized_keys
+                      echo "New key added to authorized_keys."
+                  fi
+                  chmod 600 /root/.ssh/authorized_keys
+                  rm -f $KEY_PUB
+              else
+                  echo "Downloading http://metadata.google.internal/0.1/meta-data/authorized-keys failed."
+                  false
+              fi
+              rm -f $AUTH_KEYS
           fi
 
           countKeys=0
           ${flip concatMapStrings config.services.openssh.hostKeys (k :
             let kName = baseNameOf k.path; in ''
+              PRIV_KEY=$(${mktemp})
               echo "trying to obtain SSH private host key ${kName}"
-              ${wget} -O /root/${kName} http://metadata.google.internal/0.1/meta-data/attributes/${kName} && :
-              if [ $? -eq 0 -a -e /root/${kName} ]; then
+              ${wget} -O $PRIV_KEY http://metadata.google.internal/0.1/meta-data/attributes/${kName} && :
+              if [ $? -eq 0 -a -s $PRIV_KEY ]; then
                   countKeys=$((countKeys+1))
-                  mv -f /root/${kName} ${k.path}
-                  echo "downloaded ${k.path}"
+                  mv -f $PRIV_KEY ${k.path}
+                  echo "Downloaded ${k.path}"
                   chmod 600 ${k.path}
                   ${config.programs.ssh.package}/bin/ssh-keygen -y -f ${k.path} > ${k.path}.pub
                   chmod 644 ${k.path}.pub
+              else
+                  echo "Downloading http://metadata.google.internal/0.1/meta-data/attributes/${kName} failed."
               fi
-              rm -f /root/${kName}
+              rm -f $PRIV_KEY
             ''
           )}
 
diff --git a/nixos/modules/virtualisation/nova-image.nix b/nixos/modules/virtualisation/nova-image.nix
index 2523dacc0b56..20ec6b024e91 100644
--- a/nixos/modules/virtualisation/nova-image.nix
+++ b/nixos/modules/virtualisation/nova-image.nix
@@ -46,16 +46,20 @@ with lib;
 
           # Register the paths in the Nix database.
           printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
-              chroot /mnt ${config.nix.package}/bin/nix-store --load-db
+              chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group ""
 
           # Create the system profile to allow nixos-rebuild to work.
-          chroot /mnt ${config.nix.package}/bin/nix-env \
+          chroot /mnt ${config.nix.package}/bin/nix-env --option build-users-group "" \
               -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel}
 
           # `nixos-rebuild' requires an /etc/NIXOS.
           mkdir -p /mnt/etc
           touch /mnt/etc/NIXOS
 
+          # `switch-to-configuration' requires a /bin/sh
+          mkdir -p /mnt/bin
+          ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
+
           # Install a configuration.nix.
           mkdir -p /mnt/etc/nixos
           cp ${./nova-config.nix} /mnt/etc/nixos/configuration.nix
@@ -104,10 +108,6 @@ with lib;
     boot.initrd.supportedFilesystems = [ "unionfs-fuse" ];
     */
 
-  # Since Nova allows VNC access to instances, it's nice to start to
-  # start a few virtual consoles.
-  services.mingetty.ttys = [ "tty1" "tty2" ];
-
   # Allow root logins only using the SSH key that the user specified
   # at instance creation time.
   services.openssh.enable = true;
diff --git a/nixos/modules/virtualisation/nova.nix b/nixos/modules/virtualisation/nova.nix
index 21e060cf2663..f356445abe46 100644
--- a/nixos/modules/virtualisation/nova.nix
+++ b/nixos/modules/virtualisation/nova.nix
@@ -100,7 +100,7 @@ in
 
         # `openssl' is required to generate the CA.  `openssh' is
         # required to generate key pairs.
-        path = [ pkgs.openssl pkgs.openssh pkgs.bash ];
+        path = [ pkgs.openssl config.programs.ssh.package pkgs.bash ];
 
         respawn = false;
 
diff --git a/nixos/modules/virtualisation/openvswitch.nix b/nixos/modules/virtualisation/openvswitch.nix
index c1579d94657c..69ca13a71479 100644
--- a/nixos/modules/virtualisation/openvswitch.nix
+++ b/nixos/modules/virtualisation/openvswitch.nix
@@ -7,35 +7,36 @@ with lib;
 let
   cfg = config.virtualisation.vswitch;
 
-in
+in {
 
-{
-
-  options = {
-
-    virtualisation.vswitch.enable = mkOption {
+  options.virtualisation.vswitch = {
+    enable = mkOption {
       type = types.bool;
       default = false;
-      description =
-        ''
-        Enable Open vSwitch. A configuration 
-        daemon (ovs-server) will be started.
+      description = ''
+        Whether to enable Open vSwitch. A configuration daemon (ovs-server)
+        will be started.
         '';
     };
 
-
-    virtualisation.vswitch.package = mkOption {
+    package = mkOption {
       type = types.package;
       default = pkgs.openvswitch;
-      description =
-        ''
+      description = ''
         Open vSwitch package to use.
-        '';
+      '';
     };
 
+    ipsec = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to start racoon service for openvswitch.
+      '';
+    };
   };
 
-  config = mkIf cfg.enable (let 
+  config = mkIf cfg.enable (let
 
     # Where the communication sockets live
     runDir = "/var/run/openvswitch";
@@ -43,7 +44,7 @@ in
     # Where the config database live (can't be in nix-store)
     stateDir = "/var/db/openvswitch";
 
-    # The path to the an initialized version of the database 
+    # The path to the an initialized version of the database
     db = pkgs.stdenv.mkDerivation {
       name = "vswitch.db";
       unpackPhase = "true";
@@ -51,15 +52,12 @@ in
       buildInputs = with pkgs; [
         cfg.package
       ];
-      installPhase = 
-        ''
-        ensureDir $out/
-        '';
+      installPhase = "mkdir -p $out";
     };
 
-  in {
+  in (mkMerge [{
 
-    environment.systemPackages = [ cfg.package ]; 
+    environment.systemPackages = [ cfg.package pkgs.ipsecTools ];
 
     boot.kernelModules = [ "tun" "openvswitch" ];
 
@@ -73,7 +71,7 @@ in
       path = [ cfg.package ];
       restartTriggers = [ db cfg.package ];
       # Create the config database
-      preStart = 
+      preStart =
         ''
         mkdir -p ${runDir}
         mkdir -p /var/db/openvswitch
@@ -85,23 +83,27 @@ in
         fi
         chmod -R +w /var/db/openvswitch
         '';
-      serviceConfig.ExecStart = 
-        ''
-        ${cfg.package}/bin/ovsdb-server \
-          --remote=punix:${runDir}/db.sock \
-          --private-key=db:Open_vSwitch,SSL,private_key \
-          --certificate=db:Open_vSwitch,SSL,certificate \
-          --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
-          --unixctl=ovsdb.ctl.sock \
-          /var/db/openvswitch/conf.db
-        '';       
-      serviceConfig.Restart = "always";
-      serviceConfig.RestartSec = 3;
-      postStart =
-        ''
+      serviceConfig = {
+        ExecStart =
+          ''
+          ${cfg.package}/bin/ovsdb-server \
+            --remote=punix:${runDir}/db.sock \
+            --private-key=db:Open_vSwitch,SSL,private_key \
+            --certificate=db:Open_vSwitch,SSL,certificate \
+            --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
+            --unixctl=ovsdb.ctl.sock \
+            --pidfile=/var/run/openvswitch/ovsdb.pid \
+            --detach \
+            /var/db/openvswitch/conf.db
+          '';
+        Restart = "always";
+        RestartSec = 3;
+        PIDFile = "/var/run/openvswitch/ovsdb.pid";
+        Type = "forking";
+      };
+      postStart = ''
         ${cfg.package}/bin/ovs-vsctl --timeout 3 --retry --no-wait init
-        '';
-
+      '';
     };
 
     systemd.services.vswitchd = {
@@ -109,9 +111,55 @@ in
       bindsTo = [ "ovsdb.service" ];
       after = [ "ovsdb.service" ];
       path = [ cfg.package ];
-      serviceConfig.ExecStart = ''${cfg.package}/bin/ovs-vswitchd'';
+      serviceConfig = {
+        ExecStart = ''
+          ${cfg.package}/bin/ovs-vswitchd \
+          --pidfile=/var/run/openvswitch/ovs-vswitchd.pid \
+          --detach
+        '';
+        PIDFile = "/var/run/openvswitch/ovs-vswitchd.pid";
+        Type = "forking";
+      };
     };
 
-  });
+  }
+  (mkIf cfg.ipsec {
+    services.racoon.enable = true;
+    services.racoon.configPath = "${runDir}/ipsec/etc/racoon/racoon.conf";
+
+    networking.firewall.extraCommands = ''
+      iptables -I INPUT -t mangle -p esp -j MARK --set-mark 1/1
+      iptables -I INPUT -t mangle -p udp --dport 4500 -j MARK --set-mark 1/1
+    '';
+
+    systemd.services.ovs-monitor-ipsec = {
+      description = "Open_vSwitch Ipsec Daemon";
+      wantedBy = [ "multi-user.target" ];
+      requires = [ "racoon.service" ];
+      after = [ "vswitchd.service" ];
+      environment.UNIXCTLPATH = "/tmp/ovsdb.ctl.sock";
+      serviceConfig = {
+        ExecStart = ''
+          ${cfg.package}/bin/ovs-monitor-ipsec \
+            --root-prefix ${runDir}/ipsec \
+            --pidfile /var/run/openvswitch/ovs-monitor-ipsec.pid \
+            --monitor --detach \
+            unix:/var/run/openvswitch/db.sock
+        '';
+        PIDFile = "/var/run/openvswitch/ovs-monitor-ipsec.pid";
+        Type = "forking";
+      };
+
+      preStart = ''
+        rm -r ${runDir}/ipsec/etc/racoon/certs || true
+        mkdir -p ${runDir}/ipsec/{etc/racoon,etc/init.d/,usr/sbin/}
+        ln -fs ${pkgs.ipsecTools}/bin/setkey ${runDir}/ipsec/usr/sbin/setkey
+        ln -fs ${pkgs.writeScript "racoon-restart" ''
+        #!${pkgs.stdenv.shell}
+        /var/run/current-system/sw/bin/systemctl $1 racoon
+        ''} ${runDir}/ipsec/etc/init.d/racoon
+      '';
+    };
+  })]));
 
 }
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 8c7e840910de..15b0da3bab74 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -61,8 +61,8 @@ let
       idx=2
       extraDisks=""
       ${flip concatMapStrings cfg.emptyDiskImages (size: ''
-        ${pkgs.qemu_kvm}/bin/qemu-img create -f raw "empty$idx" "${toString size}M"
-        extraDisks="$extraDisks -drive index=$idx,file=$(pwd)/empty$idx,if=virtio,werror=report"
+        ${pkgs.qemu_kvm}/bin/qemu-img create -f qcow2 "empty$idx.qcow2" "${toString size}M"
+        extraDisks="$extraDisks -drive index=$idx,file=$(pwd)/empty$idx.qcow2,if=${cfg.qemu.diskInterface},werror=report"
         idx=$((idx + 1))
       '')}
 
@@ -76,14 +76,14 @@ let
           -virtfs local,path=$TMPDIR/xchg,security_model=none,mount_tag=xchg \
           -virtfs local,path=''${SHARED_DIR:-$TMPDIR/xchg},security_model=none,mount_tag=shared \
           ${if cfg.useBootLoader then ''
-            -drive index=0,id=drive1,file=$NIX_DISK_IMAGE,if=virtio,cache=writeback,werror=report \
+            -drive index=0,id=drive1,file=$NIX_DISK_IMAGE,if=${cfg.qemu.diskInterface},cache=writeback,werror=report \
             -drive index=1,id=drive2,file=$TMPDIR/disk.img,media=disk \
             ${if cfg.useEFIBoot then ''
               -pflash $TMPDIR/bios.bin \
             '' else ''
             ''}
           '' else ''
-            -drive file=$NIX_DISK_IMAGE,if=virtio,cache=writeback,werror=report \
+            -drive index=0,id=drive1,file=$NIX_DISK_IMAGE,if=${cfg.qemu.diskInterface},cache=writeback,werror=report \
             -kernel ${config.system.build.toplevel}/kernel \
             -initrd ${config.system.build.toplevel}/initrd \
             -append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo} ${kernelConsole} $QEMU_KERNEL_PARAMS" \
@@ -165,7 +165,7 @@ let
           ${config.system.build.toplevel}/bin/switch-to-configuration boot
 
           umount /boot
-        ''
+        '' # */
     );
 
 in
@@ -204,17 +204,25 @@ in
           '';
       };
 
+    virtualisation.bootDevice =
+      mkOption {
+        type = types.str;
+        example = "/dev/vda";
+        description =
+          ''
+            The disk to be used for the root filesystem.
+          '';
+      };
+
     virtualisation.emptyDiskImages =
       mkOption {
         default = [];
         type = types.listOf types.int;
         description =
           ''
-            Additional disk images to provide to the VM, the value is a list of
-            sizes in megabytes the empty disk should be.
-
-            These disks are writeable by the VM and will be thrown away
-            afterwards.
+            Additional disk images to provide to the VM. The value is
+            a list of size in megabytes of each disk. These disks are
+            writeable by the VM.
           '';
       };
 
@@ -310,6 +318,17 @@ in
             to keep the default runtime behaviour.
           '';
         };
+
+      diskInterface =
+        mkOption {
+          default = "virtio";
+          example = "scsi";
+          type = types.str;
+          description = ''
+            The interface used for the virtual hard disks
+            (<literal>virtio</literal> or <literal>scsi</literal>).
+          '';
+        };
     };
 
     virtualisation.useBootLoader =
@@ -341,7 +360,7 @@ in
 
   config = {
 
-    boot.loader.grub.device = mkVMOverride "/dev/vda";
+    boot.loader.grub.device = mkVMOverride cfg.bootDevice;
 
     boot.initrd.extraUtilsCommands =
       ''
@@ -353,9 +372,9 @@ in
       ''
         # If the disk image appears to be empty, run mke2fs to
         # initialise.
-        FSTYPE=$(blkid -o value -s TYPE /dev/vda || true)
+        FSTYPE=$(blkid -o value -s TYPE ${cfg.bootDevice} || true)
         if test -z "$FSTYPE"; then
-            mke2fs -t ext4 /dev/vda
+            mke2fs -t ext4 ${cfg.bootDevice}
         fi
       '';
 
@@ -385,6 +404,12 @@ in
         fi
       '';
 
+    boot.initrd.availableKernelModules =
+      optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx";
+
+    virtualisation.bootDevice =
+      mkDefault (if cfg.qemu.diskInterface == "scsi" then "/dev/sda" else "/dev/vda");
+
     virtualisation.pathsInNixDB = [ config.system.build.toplevel ];
 
     virtualisation.qemu.options = [ "-vga std" "-usbdevice tablet" ];
@@ -396,7 +421,7 @@ in
     # attribute should be disregarded for the purpose of building a VM
     # test image (since those filesystems don't exist in the VM).
     fileSystems = mkVMOverride (
-      { "/".device = "/dev/vda";
+      { "/".device = cfg.bootDevice;
         ${if cfg.writableStore then "/nix/.ro-store" else "/nix/store"} =
           { device = "store";
             fsType = "9p";
diff --git a/nixos/modules/virtualisation/vmware-guest.nix b/nixos/modules/virtualisation/vmware-guest.nix
index 3f19f6a28b2b..ac2415a22b52 100644
--- a/nixos/modules/virtualisation/vmware-guest.nix
+++ b/nixos/modules/virtualisation/vmware-guest.nix
@@ -8,7 +8,7 @@ let
 in
 {
   options = {
-    services.vmwareGuest.enable = mkEnableOption "Enable VMWare Guest Support";
+    services.vmwareGuest.enable = mkEnableOption "VMWare Guest Support";
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix
index ea9f61aad6a6..c750286a3970 100644
--- a/nixos/modules/virtualisation/xen-dom0.nix
+++ b/nixos/modules/virtualisation/xen-dom0.nix
@@ -6,7 +6,6 @@ with lib;
 
 let
   cfg = config.virtualisation.xen;
-  xen = pkgs.xen;
 in
 
 {
@@ -48,13 +47,32 @@ in
           '';
       };
 
-    virtualisation.xen.bridge =
-      mkOption {
-        default = "xenbr0";
-        description =
-          ''
-            Create a bridge for the Xen domUs to connect to.
+    virtualisation.xen.bridge = {
+        name = mkOption {
+          default = "xenbr0";
+          description = ''
+              Name of bridge the Xen domUs connect to.
+            '';
+        };
+
+        address = mkOption {
+          type = types.str;
+          default = "172.16.0.1";
+          description = ''
+            IPv4 address of the bridge.
+          '';
+        };
+
+        prefixLength = mkOption {
+          type = types.addCheck types.int (n: n >= 0 && n <= 32);
+          default = 16;
+          description = ''
+            Subnet mask of the bridge interface, specified as the number of
+            bits in the prefix (<literal>24</literal>).
+            A DHCP server will provide IP addresses for the whole, remaining
+            subnet.
           '';
+        };
       };
 
     virtualisation.xen.stored =
@@ -88,9 +106,9 @@ in
       message = "Xen currently does not support EFI boot";
     } ];
 
-    virtualisation.xen.stored = mkDefault "${xen}/bin/oxenstored";
+    virtualisation.xen.stored = mkDefault "${pkgs.xen}/bin/oxenstored";
 
-    environment.systemPackages = [ xen ];
+    environment.systemPackages = [ pkgs.xen ];
 
     # Make sure Domain 0 gets the required configuration
     #boot.kernelPackages = pkgs.boot.kernelPackages.override { features={xen_dom0=true;}; };
@@ -122,7 +140,7 @@ in
 
     system.extraSystemBuilderCmds =
       ''
-        ln -s ${xen}/boot/xen.gz $out/xen.gz
+        ln -s ${pkgs.xen}/boot/xen.gz $out/xen.gz
         echo "${toString cfg.bootParams}" > $out/xen-params
       '';
 
@@ -158,13 +176,16 @@ in
 
 
     environment.etc =
-      [ { source = "${xen}/etc/xen/xl.conf";
+      [ { source = "${pkgs.xen}/etc/xen/xl.conf";
           target = "xen/xl.conf";
         }
+        { source = "${pkgs.xen}/etc/xen/scripts";
+          target = "xen/scripts";
+        }
       ];
 
     # Xen provides udev rules.
-    services.udev.packages = [ xen ];
+    services.udev.packages = [ pkgs.xen ];
 
     services.udev.path = [ pkgs.bridge-utils pkgs.iproute ];
 
@@ -259,17 +280,74 @@ in
       description = "Xen bridge";
       wantedBy = [ "multi-user.target" ];
       before = [ "xen-domains.service" ];
-      serviceConfig.RemainAfterExit = "yes";
-      serviceConfig.ExecStart = ''
-        ${pkgs.bridge-utils}/bin/brctl addbr ${cfg.bridge}
-        ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} up
-        '';
-      serviceConfig.ExecStop = ''
-        ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} down
-        ${pkgs.bridge-utils}/bin/brctl delbr ${cfg.bridge}
-        '';
+      preStart = ''
+        mkdir -p /var/run/xen
+        touch /var/run/xen/dnsmasq.pid
+        touch /var/run/xen/dnsmasq.etherfile
+        touch /var/run/xen/dnsmasq.leasefile
+
+        IFS='-' read -a data <<< `${pkgs.sipcalc}/bin/sipcalc ${cfg.bridge.address}/${toString cfg.bridge.prefixLength} | grep Usable\ range`
+        export XEN_BRIDGE_IP_RANGE_START="${"\${data[1]//[[:blank:]]/}"}"
+        export XEN_BRIDGE_IP_RANGE_END="${"\${data[2]//[[:blank:]]/}"}"
+
+        IFS='-' read -a data <<< `${pkgs.sipcalc}/bin/sipcalc ${cfg.bridge.address}/${toString cfg.bridge.prefixLength} | grep Network\ address`
+        export XEN_BRIDGE_NETWORK_ADDRESS="${"\${data[1]//[[:blank:]]/}"}"
+
+        echo "${cfg.bridge.address} host gw dns" > /var/run/xen/dnsmasq.hostsfile
+
+        cat <<EOF > /var/run/xen/dnsmasq.conf
+        no-daemon
+        pid-file=/var/run/xen/dnsmasq.pid
+        interface=${cfg.bridge.name}
+        except-interface=lo
+        bind-interfaces
+        auth-server=dns.xen.local,${cfg.bridge.name}
+        auth-zone=xen.local,$XEN_BRIDGE_NETWORK_ADDRESS/${toString cfg.bridge.prefixLength}
+        domain=xen.local
+        addn-hosts=/var/run/xen/dnsmasq.hostsfile
+        expand-hosts
+        strict-order
+        no-hosts
+        bogus-priv
+        no-resolv
+        no-poll
+        filterwin2k
+        clear-on-reload
+        domain-needed
+        dhcp-hostsfile=/var/run/xen/dnsmasq.etherfile
+        dhcp-authoritative
+        dhcp-range=$XEN_BRIDGE_IP_RANGE_START,$XEN_BRIDGE_IP_RANGE_END,$XEN_BRIDGE_NETWORK_ADDRESS
+        dhcp-no-override
+        no-ping
+        dhcp-leasefile=/var/run/xen/dnsmasq.leasefile
+        EOF
+
+        # DHCP
+        ${pkgs.iptables}/bin/iptables -I INPUT  -i ${cfg.bridge.name} -p tcp -s $XEN_BRIDGE_NETWORK_ADDRESS/${toString cfg.bridge.prefixLength} --sport 68 --dport 67 -j ACCEPT
+        ${pkgs.iptables}/bin/iptables -I INPUT  -i ${cfg.bridge.name} -p udp -s $XEN_BRIDGE_NETWORK_ADDRESS/${toString cfg.bridge.prefixLength} --sport 68 --dport 67 -j ACCEPT
+        # DNS
+        ${pkgs.iptables}/bin/iptables -I INPUT  -i ${cfg.bridge.name} -p tcp -d ${cfg.bridge.address} --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
+        ${pkgs.iptables}/bin/iptables -I INPUT  -i ${cfg.bridge.name} -p udp -d ${cfg.bridge.address} --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
+
+        ${pkgs.bridge-utils}/bin/brctl addbr ${cfg.bridge.name}
+        ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge.name} ${cfg.bridge.address}
+        ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge.name} up
+      '';
+      serviceConfig.ExecStart = "${pkgs.dnsmasq}/bin/dnsmasq --conf-file=/var/run/xen/dnsmasq.conf";
+      postStop = ''
+        ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge.name} down
+        ${pkgs.bridge-utils}/bin/brctl delbr ${cfg.bridge.name}
+
+        # DNS
+        ${pkgs.iptables}/bin/iptables -D INPUT  -i ${cfg.bridge.name} -p udp -d ${cfg.bridge.address} --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
+        ${pkgs.iptables}/bin/iptables -D INPUT  -i ${cfg.bridge.name} -p tcp -d ${cfg.bridge.address} --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
+        # DHCP
+        ${pkgs.iptables}/bin/iptables -D INPUT  -i ${cfg.bridge.name} -p udp --sport 68 --dport 67 -j ACCEPT
+        ${pkgs.iptables}/bin/iptables -D INPUT  -i ${cfg.bridge.name} -p tcp --sport 68 --dport 67 -j ACCEPT
+      '';
     };
 
+
     systemd.services.xen-domains = {
       description = "Xen domains - automatically starts, saves and restores Xen domains";
       wantedBy = [ "multi-user.target" ];