about summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
authorVladimír Čunát <vcunat@gmail.com>2015-10-03 13:33:13 +0200
committerVladimír Čunát <vcunat@gmail.com>2015-10-03 13:33:37 +0200
commit5227fb1dd53fcb5918b9342dff4868f4ad68427e (patch)
treed6cd521e3f67944031216a27f740f28f22b73b41 /nixos/modules
parentd6dd3b8bd1eaeeb21dfdb5051cd4732c748ce5d7 (diff)
parent33373d939a19f465228ddede6d38ce9032b5916b (diff)
downloadnixlib-5227fb1dd53fcb5918b9342dff4868f4ad68427e.tar
nixlib-5227fb1dd53fcb5918b9342dff4868f4ad68427e.tar.gz
nixlib-5227fb1dd53fcb5918b9342dff4868f4ad68427e.tar.bz2
nixlib-5227fb1dd53fcb5918b9342dff4868f4ad68427e.tar.lz
nixlib-5227fb1dd53fcb5918b9342dff4868f4ad68427e.tar.xz
nixlib-5227fb1dd53fcb5918b9342dff4868f4ad68427e.tar.zst
nixlib-5227fb1dd53fcb5918b9342dff4868f4ad68427e.zip
Merge commit staging+systemd into closure-size
Many non-conflict problems weren't (fully) resolved in this commit yet.
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/fonts/corefonts.nix4
-rw-r--r--nixos/modules/config/fonts/fontconfig.nix39
-rw-r--r--nixos/modules/config/fonts/fonts.nix1
-rw-r--r--nixos/modules/config/i18n.nix18
-rw-r--r--nixos/modules/config/krb5.nix2
-rw-r--r--nixos/modules/config/ldap.nix10
-rw-r--r--nixos/modules/config/networking.nix11
-rw-r--r--nixos/modules/config/pulseaudio.nix19
-rw-r--r--nixos/modules/config/shells-environment.nix22
-rw-r--r--nixos/modules/config/system-environment.nix15
-rw-r--r--nixos/modules/config/system-path.nix29
-rw-r--r--nixos/modules/config/timezone.nix1
-rw-r--r--nixos/modules/config/users-groups.nix62
-rw-r--r--nixos/modules/hardware/all-firmware.nix4
-rw-r--r--nixos/modules/hardware/video/bumblebee.nix4
-rw-r--r--nixos/modules/hardware/video/encoder/wis-go7007.nix8
-rw-r--r--nixos/modules/installer/cd-dvd/channel.nix19
-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.nix32
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix40
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix46
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image.nix127
-rw-r--r--nixos/modules/installer/tools/auto-upgrade.nix81
-rw-r--r--nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh2
-rw-r--r--nixos/modules/installer/tools/nixos-checkout.nix21
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl35
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh11
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh4
-rw-r--r--nixos/modules/installer/tools/tools.nix5
-rw-r--r--nixos/modules/misc/assertions.nix4
-rw-r--r--nixos/modules/misc/extra-arguments.nix9
-rw-r--r--nixos/modules/misc/ids.nix41
-rw-r--r--nixos/modules/misc/locate.nix16
-rw-r--r--nixos/modules/misc/nixpkgs.nix4
-rw-r--r--nixos/modules/misc/version.nix30
-rw-r--r--nixos/modules/module-list.nix45
-rw-r--r--nixos/modules/profiles/all-hardware.nix2
-rw-r--r--nixos/modules/profiles/base.nix7
-rw-r--r--nixos/modules/profiles/clone-config.nix2
-rw-r--r--nixos/modules/profiles/installation-device.nix23
-rw-r--r--nixos/modules/profiles/minimal.nix5
-rw-r--r--nixos/modules/profiles/qemu-guest.nix2
-rw-r--r--nixos/modules/programs/cdemu.nix17
-rw-r--r--nixos/modules/programs/command-not-found/command-not-found.nix4
-rw-r--r--nixos/modules/programs/command-not-found/command-not-found.pl6
-rw-r--r--nixos/modules/programs/environment.nix9
-rw-r--r--nixos/modules/programs/info.nix38
-rw-r--r--nixos/modules/programs/kbdlight.nix16
-rw-r--r--nixos/modules/programs/ssh.nix113
-rw-r--r--nixos/modules/programs/venus.nix19
-rw-r--r--nixos/modules/programs/wvdial.nix4
-rw-r--r--nixos/modules/programs/xfs_quota.nix110
-rw-r--r--nixos/modules/rename.nix20
-rw-r--r--nixos/modules/security/apparmor.nix8
-rw-r--r--nixos/modules/security/ca.nix8
-rw-r--r--nixos/modules/security/grsecurity.nix4
-rw-r--r--nixos/modules/security/pam.nix54
-rw-r--r--nixos/modules/security/pam_mount.nix72
-rw-r--r--nixos/modules/security/prey.nix21
-rw-r--r--nixos/modules/services/amqp/activemq/default.nix3
-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.nix21
-rw-r--r--nixos/modules/services/backup/postgresql-backup.nix6
-rw-r--r--nixos/modules/services/backup/sitecopy-backup.nix12
-rw-r--r--nixos/modules/services/backup/tarsnap.nix2
-rw-r--r--nixos/modules/services/cluster/kubernetes.nix242
-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.nix11
-rw-r--r--nixos/modules/services/databases/neo4j.nix2
-rw-r--r--nixos/modules/services/databases/opentsdb.nix16
-rw-r--r--nixos/modules/services/databases/postgresql.nix14
-rw-r--r--nixos/modules/services/databases/riak.nix148
-rw-r--r--nixos/modules/services/desktops/gnome3/gnome-keyring.nix2
-rw-r--r--nixos/modules/services/hardware/brltty.nix48
-rw-r--r--nixos/modules/services/hardware/freefall.nix57
-rw-r--r--nixos/modules/services/hardware/sane.nix3
-rw-r--r--nixos/modules/services/hardware/tcsd.nix24
-rw-r--r--nixos/modules/services/hardware/udev.nix25
-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/logstash.nix5
-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/dovecot.nix7
-rw-r--r--nixos/modules/services/mail/mlmmj.nix18
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix2
-rw-r--r--nixos/modules/services/mail/postfix.nix47
-rw-r--r--nixos/modules/services/misc/apache-kafka.nix17
-rw-r--r--nixos/modules/services/misc/confd.nix89
-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/etcd.nix8
-rw-r--r--nixos/modules/services/misc/gitit.nix724
-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/mbpfan.nix113
-rw-r--r--nixos/modules/services/misc/mediatomb.nix15
-rw-r--r--nixos/modules/services/misc/mesos-master.nix35
-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.nix72
-rw-r--r--nixos/modules/services/misc/nixos-manual.nix5
-rw-r--r--nixos/modules/services/misc/plex.nix61
-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/rogue.nix1
-rw-r--r--nixos/modules/services/misc/subsonic.nix159
-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/bosun.nix3
-rw-r--r--nixos/modules/services/monitoring/das_watchdog.nix34
-rw-r--r--nixos/modules/services/monitoring/dd-agent.nix51
-rw-r--r--nixos/modules/services/monitoring/grafana.nix337
-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.nix20
-rw-r--r--nixos/modules/services/monitoring/smartd.nix211
-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/nfsd.nix5
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix6
-rw-r--r--nixos/modules/services/network-filesystems/xtreemfs.nix469
-rw-r--r--nixos/modules/services/networking/atftpd.nix4
-rw-r--r--nixos/modules/services/networking/bind.nix9
-rw-r--r--nixos/modules/services/networking/bird.nix76
-rw-r--r--nixos/modules/services/networking/bitlbee.nix52
-rw-r--r--nixos/modules/services/networking/btsync.nix4
-rw-r--r--nixos/modules/services/networking/charybdis.nix96
-rw-r--r--nixos/modules/services/networking/connman.nix24
-rw-r--r--nixos/modules/services/networking/consul.nix214
-rw-r--r--nixos/modules/services/networking/copy-com.nix106
-rw-r--r--nixos/modules/services/networking/ddclient.nix2
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix1
-rw-r--r--nixos/modules/services/networking/dnschain.nix110
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix174
-rw-r--r--nixos/modules/services/networking/dnsmasq.nix5
-rw-r--r--nixos/modules/services/networking/docker-registry-server.nix98
-rw-r--r--nixos/modules/services/networking/fan.nix60
-rw-r--r--nixos/modules/services/networking/firefox/sync-server.nix2
-rw-r--r--nixos/modules/services/networking/firewall.nix18
-rw-r--r--nixos/modules/services/networking/freenet.nix4
-rw-r--r--nixos/modules/services/networking/gateone.nix61
-rw-r--r--nixos/modules/services/networking/heyefi.nix82
-rw-r--r--nixos/modules/services/networking/i2p.nix10
-rw-r--r--nixos/modules/services/networking/iodined.nix4
-rw-r--r--nixos/modules/services/networking/kippo.nix14
-rw-r--r--nixos/modules/services/networking/minidlna.nix4
-rw-r--r--nixos/modules/services/networking/namecoind.nix150
-rw-r--r--nixos/modules/services/networking/networkmanager.nix4
-rw-r--r--nixos/modules/services/networking/nix-serve.nix70
-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/ntpd.nix12
-rw-r--r--nixos/modules/services/networking/oidentd.nix4
-rw-r--r--nixos/modules/services/networking/openvpn.nix6
-rw-r--r--nixos/modules/services/networking/polipo.nix2
-rw-r--r--nixos/modules/services/networking/quassel.nix2
-rw-r--r--nixos/modules/services/networking/racoon.nix45
-rw-r--r--nixos/modules/services/networking/sabnzbd.nix40
-rw-r--r--nixos/modules/services/networking/seeks.nix2
-rw-r--r--nixos/modules/services/networking/shout.nix80
-rw-r--r--nixos/modules/services/networking/skydns.nix91
-rw-r--r--nixos/modules/services/networking/softether.nix150
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix105
-rw-r--r--nixos/modules/services/networking/syncthing.nix19
-rw-r--r--nixos/modules/services/networking/tinc.nix1
-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/printing/cupsd.nix57
-rw-r--r--nixos/modules/services/scheduling/chronos.nix2
-rw-r--r--nixos/modules/services/scheduling/cron.nix65
-rw-r--r--nixos/modules/services/scheduling/marathon.nix74
-rw-r--r--nixos/modules/services/search/elasticsearch.nix14
-rw-r--r--nixos/modules/services/search/kibana.nix168
-rw-r--r--nixos/modules/services/security/hologram.nix2
-rw-r--r--nixos/modules/services/security/physlock.nix114
-rw-r--r--nixos/modules/services/system/dbus.nix4
-rw-r--r--nixos/modules/services/system/nscd.nix5
-rw-r--r--nixos/modules/services/torrent/deluge.nix2
-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.nix125
-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/nginx/default.nix3
-rw-r--r--nixos/modules/services/web-servers/phpfpm.nix7
-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/gnome3.nix26
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix8
-rw-r--r--nixos/modules/services/x11/desktop-managers/kodi.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix21
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix89
-rw-r--r--nixos/modules/services/x11/display-managers/kdm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix30
-rw-r--r--nixos/modules/services/x11/display-managers/slim.nix5
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix36
-rw-r--r--nixos/modules/services/x11/redshift.nix83
-rw-r--r--nixos/modules/services/x11/unclutter.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/icewm.nix17
-rw-r--r--nixos/modules/services/x11/window-managers/notion.nix32
-rw-r--r--nixos/modules/services/x11/window-managers/oroborus.nix25
-rw-r--r--nixos/modules/services/x11/window-managers/qtile.nix25
-rw-r--r--nixos/modules/services/x11/window-managers/stumpwm.nix7
-rw-r--r--nixos/modules/services/x11/window-managers/wmii.nix28
-rw-r--r--nixos/modules/services/x11/xserver.nix14
-rw-r--r--nixos/modules/system/activation/activation-script.nix4
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl5
-rw-r--r--nixos/modules/system/activation/top-level.nix19
-rw-r--r--nixos/modules/system/boot/coredump.nix51
-rw-r--r--nixos/modules/system/boot/kernel.nix9
-rw-r--r--nixos/modules/system/boot/loader/efi.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.nix9
-rw-r--r--nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh140
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix210
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl100
-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/loader/raspberrypi/builder.sh17
-rw-r--r--nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix14
-rw-r--r--nixos/modules/system/boot/luksroot.nix67
-rw-r--r--nixos/modules/system/boot/modprobe.nix9
-rw-r--r--nixos/modules/system/boot/networkd.nix10
-rw-r--r--nixos/modules/system/boot/resolved.nix3
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh37
-rw-r--r--nixos/modules/system/boot/stage-1.nix12
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh10
-rw-r--r--nixos/modules/system/boot/systemd-lib.nix79
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix55
-rw-r--r--nixos/modules/system/boot/systemd.nix119
-rw-r--r--nixos/modules/system/etc/etc.nix1
-rw-r--r--nixos/modules/tasks/encrypted-devices.nix15
-rw-r--r--nixos/modules/tasks/filesystems.nix26
-rw-r--r--nixos/modules/tasks/filesystems/exfat.nix11
-rw-r--r--nixos/modules/tasks/filesystems/vboxsf.nix23
-rw-r--r--nixos/modules/tasks/filesystems/zfs.nix16
-rw-r--r--nixos/modules/tasks/kbd.nix2
-rw-r--r--nixos/modules/tasks/network-interfaces-scripted.nix40
-rw-r--r--nixos/modules/tasks/network-interfaces-systemd.nix3
-rw-r--r--nixos/modules/tasks/network-interfaces.nix263
-rw-r--r--nixos/modules/tasks/trackpoint.nix48
-rw-r--r--nixos/modules/virtualisation/amazon-config.nix3
-rw-r--r--nixos/modules/virtualisation/amazon-grow-partition.nix50
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix105
-rw-r--r--nixos/modules/virtualisation/amazon-init.nix51
-rw-r--r--nixos/modules/virtualisation/azure-common.nix61
-rw-r--r--nixos/modules/virtualisation/azure-image.nix34
-rw-r--r--nixos/modules/virtualisation/brightbox-config.nix5
-rw-r--r--nixos/modules/virtualisation/brightbox-image.nix166
-rw-r--r--nixos/modules/virtualisation/container-config.nix4
-rw-r--r--nixos/modules/virtualisation/containers.nix26
-rw-r--r--nixos/modules/virtualisation/docker.nix41
-rw-r--r--nixos/modules/virtualisation/ec2-data.nix41
-rw-r--r--nixos/modules/virtualisation/google-compute-image.nix50
-rw-r--r--nixos/modules/virtualisation/growpart-util-linux-2.26.patch88
-rw-r--r--nixos/modules/virtualisation/libvirtd.nix13
-rw-r--r--nixos/modules/virtualisation/lxd.nix64
-rw-r--r--nixos/modules/virtualisation/nixos-container-completion.sh33
-rw-r--r--nixos/modules/virtualisation/nixos-container.pl3
-rw-r--r--nixos/modules/virtualisation/nova-image.nix12
-rw-r--r--nixos/modules/virtualisation/nova.nix2
-rw-r--r--nixos/modules/virtualisation/openvswitch.nix145
-rw-r--r--nixos/modules/virtualisation/parallels-guest.nix2
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix53
-rw-r--r--nixos/modules/virtualisation/virtualbox-guest.nix22
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix (renamed from nixos/modules/programs/virtualbox-host.nix)6
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix119
-rw-r--r--nixos/modules/virtualisation/vmware-guest.nix47
-rw-r--r--nixos/modules/virtualisation/xen-dom0.nix130
285 files changed, 9528 insertions, 1959 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/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
index 6f17bd396a0b..be6662decea6 100644
--- a/nixos/modules/config/fonts/fontconfig.nix
+++ b/nixos/modules/config/fonts/fontconfig.nix
@@ -108,10 +108,8 @@ with lib;
         subpixel = {
 
           rgba = mkOption {
-            type = types.string // {
-              check = flip elem ["rgb" "bgr" "vrgb" "vbgr" "none"];
-            };
             default = "rgb";
+            type = types.enum ["rgb" "bgr" "vrgb" "vbgr" "none"];
             description = ''
               Subpixel order, one of <literal>none</literal>,
               <literal>rgb</literal>, <literal>bgr</literal>,
@@ -120,10 +118,8 @@ with lib;
           };
 
           lcdfilter = mkOption {
-            type = types.str // {
-              check = flip elem ["none" "default" "light" "legacy"];
-            };
             default = "default";
+            type = types.enum ["none" "default" "light" "legacy"];
             description = ''
               FreeType LCD filter, one of <literal>none</literal>,
               <literal>default</literal>, <literal>light</literal>, or
@@ -142,7 +138,7 @@ with lib;
   config =
     let fontconfig = config.fonts.fontconfig;
         fcBool = x: "<bool>" + (if x then "true" else "false") + "</bool>";
-        nixosConf = ''
+        renderConf = ''
           <?xml version='1.0'?>
           <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
           <fontconfig>
@@ -169,6 +165,21 @@ with lib;
               </edit>
             </match>
 
+            ${optionalString (fontconfig.dpi != 0) ''
+            <match target="pattern">
+              <edit name="dpi" mode="assign">
+                <double>${toString fontconfig.dpi}</double>
+              </edit>
+            </match>
+            ''}
+
+          </fontconfig>
+        '';
+        genericAliasConf = ''
+          <?xml version='1.0'?>
+          <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+          <fontconfig>
+
             <!-- Default fonts -->
             ${optionalString (fontconfig.defaultFonts.sansSerif != []) ''
             <alias>
@@ -201,14 +212,6 @@ with lib;
             </alias>
             ''}
 
-            ${optionalString (fontconfig.dpi != 0) ''
-            <match target="pattern">
-              <edit name="dpi" mode="assign">
-                <double>${toString fontconfig.dpi}</double>
-              </edit>
-            </match>
-            ''}
-
           </fontconfig>
         '';
     in mkIf fontconfig.enable {
@@ -219,7 +222,8 @@ with lib;
       environment.etc."fonts/fonts.conf".source =
         pkgs.makeFontsConf { fontconfig = pkgs.fontconfig_210; fontDirectories = config.fonts.fonts; };
 
-      environment.etc."fonts/conf.d/98-nixos.conf".text = nixosConf;
+      environment.etc."fonts/conf.d/10-nixos-rendering.conf".text = renderConf;
+      environment.etc."fonts/conf.d/60-nixos-generic-alias.conf".text = genericAliasConf;
 
       # Versioned fontconfig > 2.10. Take shared fonts.conf from fontconfig.
       # Otherwise specify only font directories.
@@ -236,7 +240,8 @@ with lib;
           </fontconfig>
         '';
 
-      environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/98-nixos.conf".text = nixosConf;
+      environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/10-nixos-rendering.conf".text = renderConf;
+      environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/60-nixos-generic-alias.conf".text = genericAliasConf;
 
       environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/99-user.conf" = {
         enable = fontconfig.includeUserConf;
diff --git a/nixos/modules/config/fonts/fonts.nix b/nixos/modules/config/fonts/fonts.nix
index a3fa4bd97783..ea0a67038572 100644
--- a/nixos/modules/config/fonts/fonts.nix
+++ b/nixos/modules/config/fonts/fonts.nix
@@ -31,6 +31,7 @@ with lib;
         pkgs.xorg.fontbh100dpi
         pkgs.xorg.fontmiscmisc
         pkgs.xorg.fontcursormisc
+        pkgs.unifont
       ];
 
   };
diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix
index f2aacf9b2924..f58e540a6e5c 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
@@ -52,6 +52,15 @@ in
         '';
       };
 
+      consoleUseXkbConfig = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If set, configure the console keymap from the xserver keyboard
+          settings.
+        '';
+      };
+
       consoleKeyMap = mkOption {
         type = mkOptionType {
           name = "string or path";
@@ -74,6 +83,13 @@ in
 
   config = {
 
+    i18n.consoleKeyMap = with config.services.xserver;
+      mkIf config.i18n.consoleUseXkbConfig
+        (pkgs.runCommand "xkb-console-keymap" { preferLocalBuild = true; } ''
+          '${pkgs.ckbcomp}/bin/ckbcomp' -model '${xkbModel}' -layout '${layout}' \
+            -option '${xkbOptions}' -variant '${xkbVariant}' > "$out"
+        '');
+
     environment.systemPackages =
       optional (config.i18n.supportedLocales != []) glibcLocales;
 
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/ldap.nix b/nixos/modules/config/ldap.nix
index 1a01533c585b..c87996df8855 100644
--- a/nixos/modules/config/ldap.nix
+++ b/nixos/modules/config/ldap.nix
@@ -108,7 +108,7 @@ in
 
         extraConfig = mkOption {
           default =  "";
-          type = types.string;
+          type = types.lines;
           description = ''
             Extra configuration options that will be added verbatim at
             the end of the nslcd configuration file (nslcd.conf).
@@ -120,7 +120,7 @@ in
         distinguishedName = mkOption {
           default = "";
           example = "cn=admin,dc=example,dc=com";
-          type = types.string;
+          type = types.str;
           description = ''
             The distinguished name to bind to the LDAP server with. If this
             is not specified, an anonymous bind will be done.
@@ -129,7 +129,7 @@ in
 
         password = mkOption {
           default = "/etc/ldap/bind.password";
-          type = types.string;
+          type = types.str;
           description = ''
             The path to a file containing the credentials to use when binding
             to the LDAP server (if not binding anonymously).
@@ -149,7 +149,7 @@ in
 
         policy = mkOption {
           default = "hard_open";
-          type = types.string;
+          type = types.enum [ "hard_open" "hard_init" "soft" ];
           description = ''
             Specifies the policy to use for reconnecting to an unavailable
             LDAP server. The default is <literal>hard_open</literal>, which
@@ -168,7 +168,7 @@ in
 
       extraConfig = mkOption {
         default = "";
-        type = types.string;
+        type = types.lines;
         description = ''
           Extra configuration options that will be added verbatim at
           the end of the ldap configuration file (ldap.conf).
diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix
index f99cea7d17b1..b49f8a156d1d 100644
--- a/nixos/modules/config/networking.nix
+++ b/nixos/modules/config/networking.nix
@@ -39,6 +39,16 @@ in
       '';
     };
 
+    networking.extraResolvconfConf = lib.mkOption {
+      type = types.lines;
+      default = "";
+      example = "libc=NO";
+      description = ''
+        Extra configuration to append to <filename>resolvconf.conf</filename>.
+      '';
+    };
+
+
     networking.proxy = {
 
       default = lib.mkOption {
@@ -150,6 +160,7 @@ in
             '' + optionalString dnsmasqResolve ''
               dnsmasq_conf=/etc/dnsmasq-conf.conf
               dnsmasq_resolv=/etc/dnsmasq-resolv.conf
+            '' + cfg.extraResolvconfConf + ''
             '';
 
       } // (optionalAttrs config.services.resolved.enable (
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..d0243f9775c5 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -41,20 +41,7 @@ in
         strings.  The latter is concatenated, interspersed with colon
         characters.
       '';
-      type = types.attrsOf (mkOptionType {
-        name = "a string or a list of strings";
-        merge = loc: defs:
-          let
-            defs' = filterOverrides defs;
-            res = (head defs').value;
-          in
-          if isList res then concatLists (getValues defs')
-          else if lessThan 1 (length defs') then
-            throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
-          else if !isString res then
-            throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
-          else res;
-      });
+      type = types.attrsOf (types.loeOf types.str);
       apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
     };
 
@@ -63,15 +50,15 @@ 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 {
       type = types.attrsOf (types.listOf types.str);
       example = { PATH = [ "/bin" "/sbin" ]; MANPATH = [ "/man" "/share/man" ]; };
       description = ''
-	Attribute set of environment variable.  Each attribute maps to a list
-	of relative paths.  Each relative path is appended to the each profile
+        Attribute set of environment variable.  Each attribute maps to a list
+        of relative paths.  Each relative path is appended to the each profile
         of <option>environment.profiles</option> to form the content of the
         corresponding environment variable.
       '';
@@ -136,6 +123,7 @@ in
         "''${pkgs.dash}/bin/dash"
       '';
       type = types.path;
+      visible = false;
       description = ''
         The shell executable that is linked system-wide to
         <literal>/bin/sh</literal>. Please note that NixOS assumes all
diff --git a/nixos/modules/config/system-environment.nix b/nixos/modules/config/system-environment.nix
index 3ab32f00fd1d..3362400326d2 100644
--- a/nixos/modules/config/system-environment.nix
+++ b/nixos/modules/config/system-environment.nix
@@ -23,20 +23,7 @@ in
         strings.  The latter is concatenated, interspersed with colon
         characters.
       '';
-      type = types.attrsOf (mkOptionType {
-        name = "a string or a list of strings";
-        merge = loc: defs:
-          let
-            defs' = filterOverrides defs;
-            res = (head defs').value;
-          in
-          if isList res then concatLists (getValues defs')
-          else if lessThan 1 (length defs') then
-            throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
-          else if !isString res then
-            throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
-          else res;
-      });
+      type = types.attrsOf (types.loeOf types.str);
       apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
     };
 
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 58ebea1dabc2..26f4ba5fd706 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -38,13 +38,14 @@ let
       pkgs.nano
       pkgs.ncurses
       pkgs.netcat
-      pkgs.openssh
+      config.programs.ssh.package
       pkgs.perl
       pkgs.procps
       pkgs.rsync
       pkgs.strace
       pkgs.su
       pkgs.time
+      pkgs.texinfoInteractive
       pkgs.utillinux
       extraManpages
     ];
@@ -57,7 +58,7 @@ in
     environment = {
 
       systemPackages = mkOption {
-        type = types.listOf types.path;
+        type = types.listOf types.package;
         default = [];
         example = literalExample "[ pkgs.firefox pkgs.thunderbird ]";
         description = ''
@@ -102,15 +103,24 @@ in
       [ "/bin"
         "/etc/xdg"
         "/info"
-        "/lib"
+        "/lib" # FIXME: remove
+        #"/lib/debug/.build-id" # enables GDB to find separated debug info
         "/man"
         "/sbin"
+        "/share/applications"
+        "/share/desktop-directories"
+        "/share/doc"
         "/share/emacs"
-        "/share/vim-plugins"
-        "/share/org"
+        "/share/icons"
         "/share/info"
-        "/share/terminfo"
         "/share/man"
+        "/share/menus"
+        "/share/mime"
+        "/share/nano"
+        "/share/org"
+        "/share/terminfo"
+        "/share/themes"
+        "/share/vim-plugins"
       ];
 
     system.path = pkgs.buildEnv {
@@ -144,6 +154,13 @@ in
           if [ -x $out/bin/update-desktop-database -a -w $out/share/applications ]; then
               $out/bin/update-desktop-database $out/share/applications
           fi
+
+          if [ -x $out/bin/install-info -a -w $out/share/info ]; then
+            shopt -s nullglob
+            for i in $out/share/info/*.info $out/share/info/*.info.gz; do
+                $out/bin/install-info $i $out/share/info/dir
+            done
+          fi
         '';
     };
 
diff --git a/nixos/modules/config/timezone.nix b/nixos/modules/config/timezone.nix
index 068571393116..b9844b4adade 100644
--- a/nixos/modules/config/timezone.nix
+++ b/nixos/modules/config/timezone.nix
@@ -26,6 +26,7 @@ in
 
       hardwareClockInLocalTime = mkOption {
         default = false;
+        type = types.bool;
         description = "If set, keep the hardware clock in local time instead of UTC.";
       };
 
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 9d48edf2f26c..adc014eed415 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";
@@ -207,7 +216,7 @@ let
           exist. If <option>users.mutableUsers</option> is true, the
           password can be changed subsequently using the
           <command>passwd</command> command. Otherwise, it's
-          equivalent to setting the <option>password</option> option.
+          equivalent to setting the <option>hashedPassword</option> option.
 
           ${hashedPasswordDescription}
         '';
@@ -327,13 +336,13 @@ let
     map (range: "${user.name}:${toString range.startUid}:${toString range.count}\n")
       user.subUidRanges);
 
-  subuidFile = concatStrings (map mkSubuidEntry (attrValues cfg.extraUsers));
+  subuidFile = concatStrings (map mkSubuidEntry (attrValues cfg.users));
 
   mkSubgidEntry = user: concatStrings (
     map (range: "${user.name}:${toString range.startGid}:${toString range.count}\n")
         user.subGidRanges);
 
-  subgidFile = concatStrings (map mkSubgidEntry (attrValues cfg.extraUsers));
+  subgidFile = concatStrings (map mkSubgidEntry (attrValues cfg.users));
 
   idsAreUnique = set: idAttr: !(fold (name: args@{ dup, acc }:
     let
@@ -345,8 +354,8 @@ let
       else { dup = false; acc = newAcc; }
     ) { dup = false; acc = {}; } (builtins.attrNames set)).dup;
 
-  uidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) cfg.extraUsers) "uid";
-  gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.extraGroups) "gid";
+  uidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) cfg.users) "uid";
+  gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.groups) "gid";
 
   spec = pkgs.writeText "users-groups.json" (builtins.toJSON {
     inherit (cfg) mutableUsers;
@@ -355,13 +364,13 @@ let
           name uid group description home shell createHome isSystemUser
           password passwordFile hashedPassword
           initialPassword initialHashedPassword;
-      }) cfg.extraUsers;
+      }) cfg.users;
     groups = mapAttrsToList (n: g:
       { inherit (g) name gid;
         members = g.members ++ (mapAttrsToList (n: u: u.name) (
-          filterAttrs (n: u: elem g.name u.extraGroups) cfg.extraUsers
+          filterAttrs (n: u: elem g.name u.extraGroups) cfg.users
         ));
-      }) cfg.extraGroups;
+      }) cfg.groups;
   });
 
 in {
@@ -379,10 +388,10 @@ in {
         <literal>groupadd</literal> commands. On system activation, the
         existing contents of the <literal>/etc/passwd</literal> and
         <literal>/etc/group</literal> files will be merged with the
-        contents generated from the <literal>users.extraUsers</literal> and
-        <literal>users.extraGroups</literal> options.
+        contents generated from the <literal>users.users</literal> and
+        <literal>users.groups</literal> options.
         The initial password for a user will be set
-        according to <literal>users.extraUsers</literal>, but existing passwords
+        according to <literal>users.users</literal>, but existing passwords
         will not be changed.
 
         <warning><para>
@@ -390,7 +399,7 @@ in {
         group files will simply be replaced on system activation. This also
         holds for the user passwords; all changed
         passwords will be reset according to the
-        <literal>users.extraUsers</literal> configuration on activation.
+        <literal>users.users</literal> configuration on activation.
         </para></warning>
       '';
     };
@@ -403,7 +412,7 @@ in {
       '';
     };
 
-    users.extraUsers = mkOption {
+    users.users = mkOption {
       default = {};
       type = types.loaOf types.optionSet;
       example = {
@@ -424,7 +433,7 @@ in {
       options = [ userOpts ];
     };
 
-    users.extraGroups = mkOption {
+    users.groups = mkOption {
       default = {};
       example =
         { students.gid = 1001;
@@ -452,7 +461,7 @@ in {
 
   config = {
 
-    users.extraUsers = {
+    users.users = {
       root = {
         uid = ids.uids.root;
         description = "System administrator";
@@ -469,7 +478,7 @@ in {
       };
     };
 
-    users.extraGroups = {
+    users.groups = {
       root.gid = ids.gids.root;
       wheel.gid = ids.gids.wheel;
       disk.gid = ids.gids.disk;
@@ -516,6 +525,27 @@ in {
       { assertion = !cfg.enforceIdUniqueness || (uidsAreUnique && gidsAreUnique);
         message = "UIDs and GIDs must be unique!";
       }
+      { # If mutableUsers is false, to prevent users creating a
+        # configuration that locks them out of the system, ensure that
+        # there is at least one "privileged" account that has a
+        # password or an SSH authorized key. Privileged accounts are
+        # root and users in the wheel group.
+        assertion = !cfg.mutableUsers ->
+          any id (mapAttrsToList (name: cfg:
+            (name == "root"
+             || cfg.group == "wheel"
+             || elem "wheel" cfg.extraGroups)
+            &&
+            ((cfg.hashedPassword != null && cfg.hashedPassword != "!")
+             || cfg.password != null
+             || cfg.passwordFile != null
+             || cfg.openssh.authorizedKeys.keys != []
+             || cfg.openssh.authorizedKeys.keyFiles != [])
+          ) cfg.users);
+        message = ''
+          Neither the root account nor any wheel user has a password or SSH authorized key.
+          You must set one to prevent being locked out of your system.'';
+      }
     ];
 
   };
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index e4bdeb55cadc..1a04baef1930 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -22,9 +22,7 @@ with lib;
   ###### implementation
 
   config = mkIf config.hardware.enableAllFirmware {
-    hardware.firmware = [
-      "${pkgs.firmwareLinuxNonfree}/lib/firmware"
-    ];
+    hardware.firmware = [ pkgs.firmwareLinuxNonfree ];
   };
 
 }
diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix
index e20ebc3041e7..e2202e1e17df 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 {
@@ -52,9 +52,9 @@ in
     systemd.services.bumblebeed = {
       description = "Bumblebee Hybrid Graphics Switcher";
       wantedBy = [ "display-manager.service" ];
-      script = "bumblebeed --use-syslog -g ${config.hardware.bumblebee.group}";
       path = [ kernel.bbswitch bumblebee ];
       serviceConfig = {
+        ExecStart = "${bumblebee}/bin/bumblebeed --use-syslog -g ${config.hardware.bumblebee.group}";
         Restart = "always";
         RestartSec = 60;
         CPUSchedulingPolicy = "idle";
diff --git a/nixos/modules/hardware/video/encoder/wis-go7007.nix b/nixos/modules/hardware/video/encoder/wis-go7007.nix
index c0eb2b814b33..e9b3cf72a8dd 100644
--- a/nixos/modules/hardware/video/encoder/wis-go7007.nix
+++ b/nixos/modules/hardware/video/encoder/wis-go7007.nix
@@ -5,11 +5,11 @@ let
 in
 
 {
-  boot.extraModulePackages = [wis_go7007];
+  boot.extraModulePackages = [ wis_go7007 ];
 
-  environment.systemPackages = [wis_go7007];
+  environment.systemPackages = [ wis_go7007 ];
 
-  hardware.firmware = ["${wis_go7007}/firmware"];
+  hardware.firmware = [ wis_go7007 ];
 
-  services.udev.packages = [wis_go7007];
+  services.udev.packages = [ wis_go7007 ];
 }
diff --git a/nixos/modules/installer/cd-dvd/channel.nix b/nixos/modules/installer/cd-dvd/channel.nix
index ca0e233f9e3f..ea7e3e16b8df 100644
--- a/nixos/modules/installer/cd-dvd/channel.nix
+++ b/nixos/modules/installer/cd-dvd/channel.nix
@@ -9,18 +9,17 @@ let
 
   # We need a copy of the Nix expressions for Nixpkgs and NixOS on the
   # CD.  These are installed into the "nixos" channel of the root
-  # user, as expected by nixos-rebuild/nixos-install.
+  # user, as expected by nixos-rebuild/nixos-install. FIXME: merge
+  # with make-channel.nix.
   channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}"
-    { expr = readFile ../../../lib/channel-expr.nix; }
+    { }
     ''
-      mkdir -p $out/nixos
-      cp -prd ${pkgs.path} $out/nixos/nixpkgs
-      ln -s nixpkgs/nixos $out/nixos/nixos
+      mkdir -p $out
+      cp -prd ${pkgs.path} $out/nixos
       chmod -R u+w $out/nixos
-      rm -rf $out/nixos/nixpkgs/.git
-      echo -n ${config.system.nixosVersion} > $out/nixos/nixpkgs/.version
-      echo -n "" > $out/nixos/nixpkgs/.version-suffix
-      echo "$expr" > $out/nixos/default.nix
+      ln -s . $out/nixos/nixpkgs
+      rm -rf $out/nixos/.git
+      echo -n ${config.system.nixosVersionSuffix} > $out/nixos/.version-suffix
     '';
 
 in
@@ -34,7 +33,7 @@ in
         echo "unpacking the NixOS/Nixpkgs sources..."
         mkdir -p /nix/var/nix/profiles/per-user/root
         ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/per-user/root/channels \
-          -i ${channelSources} --quiet --option use-substitutes false
+          -i ${channelSources} --quiet --option build-use-substitutes false
         mkdir -m 0700 -p /root/.nix-defexpr
         ln -s /nix/var/nix/profiles/per-user/root/channels /root/.nix-defexpr/channels
         mkdir -m 0755 -p /var/lib/nixos
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 d9d7254aba25..fa9cc6fa20b9 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -30,8 +30,7 @@ let
   #   * COM32 entries (chainload, reboot, poweroff) are not recognized. They
   #     result in incorrect boot entries.
 
-  baseIsolinuxCfg =
-    ''
+  baseIsolinuxCfg = ''
     SERIAL 0 38400
     TIMEOUT ${builtins.toString syslinuxTimeout}
     UI vesamenu.c32
@@ -40,11 +39,11 @@ 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
-    '';
+  '';
 
   isolinuxMemtest86Entry = ''
     LABEL memtest
@@ -55,12 +54,12 @@ let
 
   isolinuxCfg = baseIsolinuxCfg + (optionalString config.boot.loader.grub.memtest86.enable isolinuxMemtest86Entry);
 
-  # The efi boot image
+  # The EFI boot image.
   efiDir = pkgs.runCommand "efi-directory" {} ''
     mkdir -p $out/EFI/boot
     cp -v ${pkgs.gummiboot}/lib/gummiboot/gummiboot${targetArch}.efi $out/EFI/boot/boot${targetArch}.efi
     mkdir -p $out/loader/entries
-    echo "title NixOS LiveCD" > $out/loader/entries/nixos-livecd.conf
+    echo "title NixOS Live CD" > $out/loader/entries/nixos-livecd.conf
     echo "linux /boot/bzImage" >> $out/loader/entries/nixos-livecd.conf
     echo "initrd /boot/initrd" >> $out/loader/entries/nixos-livecd.conf
     echo "options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}" >> $out/loader/entries/nixos-livecd.conf
@@ -105,7 +104,7 @@ in
   options = {
 
     isoImage.isoName = mkOption {
-      default = "${config.isoImage.isoName}.iso";
+      default = "${config.isoImage.isoBaseName}.iso";
       description = ''
         Name of the generated ISO image file.
       '';
@@ -192,6 +191,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 +215,9 @@ 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 ];
+
+    boot.consoleLogLevel = mkDefault 7;
 
     # 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
@@ -217,6 +230,7 @@ in
     boot.kernelParams =
       [ "root=LABEL=${config.isoImage.volumeID}"
         "boot.shell_on_fail"
+        "nomodeset"
       ];
 
     fileSystems."/" =
@@ -256,6 +270,8 @@ in
 
     boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "usb-storage" ];
 
+    boot.blacklistedKernelModules = [ "nouveau" ];
+
     boot.initrd.kernelModules = [ "loop" ];
 
     # Closures to be copied to the Nix store on the CD, namely the init
diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
new file mode 100644
index 000000000000..0ca57a4635f4
--- /dev/null
+++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+let
+  extlinux-conf-builder =
+    import ../../system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix {
+      inherit pkgs;
+    };
+in
+{
+  imports = [
+    ../../profiles/minimal.nix
+    ../../profiles/installation-device.nix
+    ./sd-image.nix
+  ];
+
+  assertions = lib.singleton {
+    assertion = pkgs.stdenv.system == "armv7l-linux";
+    message = "sd-image-armv7l-multiplatform.nix can be only built natively on ARMv7; " +
+      "it cannot be cross compiled";
+  };
+
+  boot.loader.grub.enable = false;
+  boot.loader.generic-extlinux-compatible.enable = true;
+
+  # FIXME: change this to linuxPackages_latest once v4.2 is out
+  boot.kernelPackages = pkgs.linuxPackages_testing;
+  boot.kernelParams = ["console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"];
+
+  # FIXME: fix manual evaluation on ARM
+  services.nixosManual.enable = lib.mkOverride 0 false;
+
+  # FIXME: this probably should be in installation-device.nix
+  users.extraUsers.root.initialHashedPassword = "";
+
+  sdImage = {
+    populateBootCommands = ''
+        ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot
+    '';
+  };
+}
diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
new file mode 100644
index 000000000000..199a252ad2b5
--- /dev/null
+++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+
+let
+  extlinux-conf-builder =
+    import ../../system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix {
+      inherit pkgs;
+    };
+in
+{
+  imports = [
+    ../../profiles/minimal.nix
+    ../../profiles/installation-device.nix
+    ./sd-image.nix
+  ];
+
+  assertions = lib.singleton {
+    assertion = pkgs.stdenv.system == "armv6l-linux";
+    message = "sd-image-raspberrypi.nix can be only built natively on ARMv6; " +
+      "it cannot be cross compiled";
+  };
+
+  # Needed by RPi firmware
+  nixpkgs.config.allowUnfree = true;
+
+  boot.loader.grub.enable = false;
+  boot.loader.generic-extlinux-compatible.enable = true;
+
+  boot.kernelPackages = pkgs.linuxPackages_rpi;
+
+  # FIXME: fix manual evaluation on ARM
+  services.nixosManual.enable = lib.mkOverride 0 false;
+
+  # FIXME: this probably should be in installation-device.nix
+  users.extraUsers.root.initialHashedPassword = "";
+
+  sdImage = {
+    populateBootCommands = ''
+      for f in bootcode.bin fixup.dat start.elf; do
+        cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/$f boot/
+      done
+      cp ${pkgs.ubootRaspberryPi}/u-boot.bin boot/u-boot-rpi.bin
+      echo 'kernel u-boot-rpi.bin' > boot/config.txt
+      ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot
+    '';
+  };
+}
diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix
new file mode 100644
index 000000000000..12b4f3045614
--- /dev/null
+++ b/nixos/modules/installer/cd-dvd/sd-image.nix
@@ -0,0 +1,127 @@
+# This module creates a bootable SD card image containing the given NixOS
+# configuration. The generated image is MBR partitioned, with a FAT /boot
+# partition, and ext4 root partition. The generated image is sized to fit
+# its contents, and a boot script automatically resizes the root partition
+# to fit the device on the first boot.
+#
+# The derivation for the SD image will be placed in
+# config.system.build.sdImage
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  rootfsImage = import ../../../lib/make-ext4-fs.nix {
+    inherit pkgs;
+    inherit (config.sdImage) storePaths;
+    volumeLabel = "NIXOS_SD";
+  };
+in
+{
+  options.sdImage = {
+    storePaths = mkOption {
+      type = with types; listOf package;
+      example = literalExample "[ pkgs.stdenv ]";
+      description = ''
+        Derivations to be included in the Nix store in the generated SD image.
+      '';
+    };
+
+    bootSize = mkOption {
+      type = types.int;
+      default = 128;
+      description = ''
+        Size of the /boot partition, in megabytes.
+      '';
+    };
+
+    populateBootCommands = mkOption {
+      example = literalExample "'' cp \${pkgs.myBootLoader}/u-boot.bin boot/ ''";
+      description = ''
+        Shell commands to populate the ./boot directory.
+        All files in that directory are copied to the
+        /boot partition on the SD image.
+      '';
+    };
+  };
+
+  config = {
+    fileSystems = {
+      "/boot" = {
+        device = "/dev/disk/by-label/NIXOS_BOOT";
+        fsType = "vfat";
+      };
+      "/" = {
+        device = "/dev/disk/by-label/NIXOS_SD";
+        fsType = "ext4";
+      };
+    };
+
+    sdImage.storePaths = [ config.system.build.toplevel ];
+
+    system.build.sdImage = pkgs.stdenv.mkDerivation {
+      name = "sd-image-${pkgs.stdenv.system}.img";
+
+      buildInputs = with pkgs; [ dosfstools e2fsprogs mtools libfaketime utillinux ];
+
+      buildCommand = ''
+        # Create the image file sized to fit /boot and /, plus 4M of slack
+        rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }')
+        bootSizeBlocks=$((${toString config.sdImage.bootSize} * 1024 * 1024 / 512))
+        imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 4096 * 1024))
+        truncate -s $imageSize $out
+
+        # type=b is 'W95 FAT32', type=83 is 'Linux'.
+        sfdisk $out <<EOF
+            label: dos
+            label-id: 0x2178694e
+
+            start=1M, size=$bootSizeBlocks, type=b, bootable
+            type=83
+        EOF
+
+        # Copy the rootfs into the SD image
+        eval $(partx $out -o START,SECTORS --nr 2 --pairs)
+        dd conv=notrunc if=${rootfsImage} of=$out seek=$START count=$SECTORS
+
+        # Create a FAT32 /boot partition of suitable size into bootpart.img
+        eval $(partx $out -o START,SECTORS --nr 1 --pairs)
+        truncate -s $((SECTORS * 512)) bootpart.img
+        faketime "1970-01-01 00:00:00" mkfs.vfat -i 0x2178694e -n NIXOS_BOOT bootpart.img
+
+        # Populate the files intended for /boot
+        mkdir boot
+        ${config.sdImage.populateBootCommands}
+
+        # Copy the populated /boot into the SD image
+        (cd boot; mcopy -bpsvm -i ../bootpart.img ./* ::)
+        dd conv=notrunc if=bootpart.img of=$out seek=$START count=$SECTORS
+      '';
+    };
+
+    boot.postBootCommands = ''
+      # On the first boot do some maintenance tasks
+      if [ -f /nix-path-registration ]; then
+        # Figure out device names for the boot device and root filesystem.
+        rootPart=$(readlink -f /dev/disk/by-label/NIXOS_SD)
+        bootDevice=$(lsblk -npo PKNAME $rootPart)
+
+        # Resize the root partition and the filesystem to fit the disk
+        echo ",+," | sfdisk -N2 --no-reread $bootDevice
+        ${pkgs.parted}/bin/partprobe
+        ${pkgs.e2fsprogs}/bin/resize2fs $rootPart
+
+        # Register the contents of the initial Nix store
+        ${config.nix.package}/bin/nix-store --load-db < /nix-path-registration
+
+        # nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag.
+        touch /etc/NIXOS
+        ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
+
+        # Prevents this from running on later boots.
+        rm -f /nix-path-registration
+      fi
+    '';
+  };
+}
diff --git a/nixos/modules/installer/tools/auto-upgrade.nix b/nixos/modules/installer/tools/auto-upgrade.nix
new file mode 100644
index 000000000000..b2676b05a02c
--- /dev/null
+++ b/nixos/modules/installer/tools/auto-upgrade.nix
@@ -0,0 +1,81 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.system.autoUpgrade; in
+
+{
+
+  options = {
+
+    system.autoUpgrade = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to periodically upgrade NixOS to the latest
+          version. If enabled, a systemd timer will run
+          <literal>nixos-rebuild switch --upgrade</literal> once a
+          day.
+        '';
+      };
+
+      channel = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = https://nixos.org/channels/nixos-14.12-small;
+        description = ''
+          The URI of the NixOS channel to use for automatic
+          upgrades. By default, this is the channel set using
+          <command>nix-channel</command> (run <literal>nix-channel
+          --list</literal> to see the current value).
+        '';
+      };
+
+      flags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "-I" "stuff=/home/alice/nixos-stuff" "--option" "extra-binary-caches" "http://my-cache.example.org/" ];
+        description = ''
+          Any additional flags passed to <command>nixos-rebuild</command>.
+        '';
+      };
+
+    };
+
+  };
+
+  config = {
+
+    system.autoUpgrade.flags =
+      [ "--no-build-output" ]
+      ++ (if cfg.channel == null
+          then [ "--upgrade" ]
+          else [ "-I" "nixpkgs=${cfg.channel}/nixexprs.tar.xz" ]);
+
+    systemd.services.nixos-upgrade = {
+      description = "NixOS Upgrade";
+
+      restartIfChanged = false;
+      unitConfig.X-StopOnRemoval = false;
+
+      serviceConfig.Type = "oneshot";
+
+      environment = config.nix.envVars //
+        { inherit (config.environment.sessionVariables) NIX_PATH SSL_CERT_FILE;
+          HOME = "/root";
+        };
+
+      path = [ pkgs.gnutar pkgs.xz config.nix.package ];
+
+      script = ''
+        ${config.system.build.nixos-rebuild}/bin/nixos-rebuild test ${toString cfg.flags}
+      '';
+
+      startAt = mkIf cfg.enable "04:40";
+    };
+
+  };
+
+}
diff --git a/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
index f9cbfffde704..4e981c074a57 100644
--- a/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
+++ b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
@@ -53,5 +53,5 @@ fi
 
 # Build a network of VMs
 
-nix-build '<nixos/modules/installer/tools/nixos-build-vms/build-vms.nix>' \
+nix-build '<nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix>' \
     --argstr networkExpr $networkExpr $noOutLinkArg $showTraceArg
diff --git a/nixos/modules/installer/tools/nixos-checkout.nix b/nixos/modules/installer/tools/nixos-checkout.nix
index 3338e5119acb..07274e139f7d 100644
--- a/nixos/modules/installer/tools/nixos-checkout.nix
+++ b/nixos/modules/installer/tools/nixos-checkout.nix
@@ -1,5 +1,5 @@
-# This module generates the nixos-checkout script, which replaces the
-# Nixpkgs source trees in /etc/nixos/nixpkgs with a Git checkout.
+# This module generates the nixos-checkout script, which performs a
+# checkout of the Nixpkgs Git repository.
 
 { config, lib, pkgs, ... }:
 
@@ -27,7 +27,7 @@ let
 
         if [ -z "$(type -P git)" ]; then
             echo "installing Git..."
-            nix-env -iA nixos.pkgs.git || nix-env -i git
+            nix-env -iA nixos.git
         fi
 
         # Move any old nixpkgs directories out of the way.
@@ -37,8 +37,19 @@ let
             mv nixpkgs nixpkgs-$backupTimestamp
         fi
 
-        # Check out the NixOS and Nixpkgs sources.
-        git clone git://github.com/NixOS/nixpkgs.git nixpkgs
+        # Check out the Nixpkgs sources.
+        if ! [ -e nixpkgs/.git ]; then
+            echo "Creating repository in $prefix/nixpkgs..."
+            git init --quiet nixpkgs
+        else
+            echo "Updating repository in $prefix/nixpkgs..."
+        fi
+        cd nixpkgs
+        git remote add origin git://github.com/NixOS/nixpkgs.git || true
+        git remote add channels git://github.com/NixOS/nixpkgs-channels.git || true
+        git remote set-url origin --push git@github.com:NixOS/nixpkgs.git
+        git remote update
+        git checkout master
       '';
    };
 
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index eadaae6715b4..39ef4c51ba10 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 {
@@ -235,7 +235,7 @@ chomp $virt;
 # Check if we're a VirtualBox guest.  If so, enable the guest
 # additions.
 if ($virt eq "oracle") {
-    push @attrs, "services.virtualboxGuest.enable = true;"
+    push @attrs, "virtualisation.virtualbox.guest.enable = true;"
 }
 
 
@@ -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 "/";
@@ -352,9 +364,9 @@ EOF
     if ($fsType eq "btrfs") {
         my ($status, @id_info) = runCommand("btrfs subvol show $rootDir$mountPoint");
         if ($status != 0 || join("", @msg) =~ /ERROR:/) {
-            die "Failed to retreive subvolume info for $mountPoint\n";
+            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";
   # };
@@ -532,6 +544,9 @@ $bootLoaderConfig
   #   uid = 1000;
   # };
 
+  # The NixOS release to be compatible with for stateful data such as databases.
+  system.stateVersion = "@nixosRelease@";
+
 }
 EOF
     } else {
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index 097631eda9c9..4e10615f902f 100644
--- a/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -188,6 +188,9 @@ mkdir -m 0755 -p $mountPoint/bin
 ln -sf @shell@ $mountPoint/bin/sh
 
 
+# Build hooks likely won't function correctly in the minimal chroot; just disable them.
+unset NIX_BUILD_HOOK
+
 # Make the build below copy paths from the CD if possible.  Note that
 # /tmp/root in the chroot is the root of the CD.
 export NIX_OTHER_STORES=/tmp/root/nix:$NIX_OTHER_STORES
@@ -256,14 +259,8 @@ NIXOS_INSTALL_GRUB=1 chroot $mountPoint \
 chroot $mountPoint /nix/var/nix/profiles/system/activate
 
 
-# Some systems may not be prepared to use NixOS' paths.
-export PATH=/run/current-system/sw/bin:/run/current-system/sw/sbin:$PATH
-export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixpkgs=/etc/nixos/nixpkgs
-export NIX_PATH=$NIX_PATH:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels
-
-
 # Ask the user to set a root password.
-if [ "$(chroot $mountPoint nix-instantiate --eval '<nixpkgs/nixos>' -A config.users.mutableUsers)" = true ] && [ -t 1 ] ; then
+if [ "$(chroot $mountPoint /run/current-system/sw/bin/sh -l -c "nix-instantiate --eval '<nixpkgs/nixos>' -A config.users.mutableUsers")" = true ] && [ -t 0 ] ; then
     echo "setting root password..."
     chroot $mountPoint /var/setuid-wrappers/passwd
 fi
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
index ccafa30856c5..af19004cbddb 100644
--- a/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -157,9 +157,9 @@ if [ -n "$buildNix" ]; then
             if ! nix-build '<nixpkgs>' -A nix -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
                 machine="$(uname -m)"
                 if [ "$machine" = x86_64 ]; then
-                    nixStorePath=/nix/store/ffig6yaggbh12dh9y5pnf1grf5lqyipz-nix-1.8
+                    nixStorePath=/nix/store/xryr9g56h8yjddp89d6dw12anyb4ch7c-nix-1.10
                 elif [[ "$machine" =~ i.86 ]]; then
-                    nixStorePath=/nix/store/lglhfp4mimfa5wzjjf1kqz6f5wlsj2mn-nix-1.8
+                    nixStorePath=/nix/store/2w92k5wlpspf0q2k9mnf2z42prx3bwmv-nix-1.10
                 else
                     echo "$0: unsupported platform"
                     exit 1
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix
index 99a74b6d59ed..04e4c1eb9459 100644
--- a/nixos/modules/installer/tools/tools.nix
+++ b/nixos/modules/installer/tools/tools.nix
@@ -40,6 +40,7 @@ let
     src = ./nixos-generate-config.pl;
     path = [ pkgs.btrfsProgs ];
     perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
+    inherit (config.system) nixosRelease;
   };
 
   nixos-option = makeProg {
@@ -56,7 +57,9 @@ let
 in
 
 {
+
   config = {
+
     environment.systemPackages =
       [ nixos-build-vms
         nixos-install
@@ -69,5 +72,7 @@ in
     system.build = {
       inherit nixos-install nixos-generate-config nixos-option nixos-rebuild;
     };
+
   };
+
 }
diff --git a/nixos/modules/misc/assertions.nix b/nixos/modules/misc/assertions.nix
index c1be36e98cba..3b50e60a0ffb 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
@@ -30,5 +30,5 @@ with lib;
     };
 
   };
-  # impl of assertions is in <nixos/modules/system/activation/top-level.nix>
+  # impl of assertions is in <nixpkgs/nixos/modules/system/activation/top-level.nix>
 }
diff --git a/nixos/modules/misc/extra-arguments.nix b/nixos/modules/misc/extra-arguments.nix
index c2c8903546d5..19002b17dace 100644
--- a/nixos/modules/misc/extra-arguments.nix
+++ b/nixos/modules/misc/extra-arguments.nix
@@ -2,10 +2,13 @@
 
 {
   _module.args = {
-    modulesPath = ../.;
-
-    pkgs_i686 = import ../../lib/nixpkgs.nix {
+    pkgs_i686 = import ../../.. {
       system = "i686-linux";
+      # FIXME: we enable config.allowUnfree to make packages like
+      # nvidia-x11 available. This isn't a problem because if the user has
+      # ‘nixpkgs.config.allowUnfree = false’, then evaluation will fail on
+      # the 64-bit package anyway. However, it would be cleaner to respect
+      # nixpkgs.config here.
       config.allowUnfree = true;
     };
 
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 0319c5688fbf..0d2700a126f6 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -196,7 +196,6 @@
       nylon = 168;
       apache-kafka = 169;
       panamax = 170;
-      marathon = 171;
       exim = 172;
       #fleet = 173; # unused
       #input = 174; # unused
@@ -217,6 +216,24 @@
       lambdabot = 191;
       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;
+      riak = 205;
+      shout = 206;
+      gateone = 207;
+      namecoin = 208;
+      dnschain = 209;
+      #lxd = 210; # unused
+      kibana = 211;
+      xtreemfs = 212;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -373,7 +390,7 @@
       seeks = 148;
       prosody = 149;
       i2pd = 150;
-      #dnscrypt-proxy = 151; # unused
+      dnscrypt-proxy = 151;
       systemd-network = 152;
       systemd-resolve = 153;
       systemd-timesync = 154;
@@ -390,7 +407,6 @@
       gitlab = 165;
       nylon = 168;
       panamax = 170;
-      #marathon = 171; # unused
       exim = 172;
       fleet = 173;
       input = 174;
@@ -411,6 +427,25 @@
       lambdabot = 191;
       #asterisk = 192; # unused
       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;
+      riak = 205;
+      #shout = 206; #unused
+      gateone = 207;
+      namecoin = 208;
+      #dnschain = 209; #unused
+      lxd = 210; # unused
+      #kibana = 211;
+      xtreemfs = 212;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index f3ed2aaba09d..4f9c8d4e5ba1 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -35,7 +35,7 @@ in {
         type = types.listOf types.str;
         default = [ ];
         description = ''
-          Extra flags to append to <command>updatedb</command>.
+          Extra flags to pass to <command>updatedb</command>.
         '';
       };
 
@@ -56,6 +56,14 @@ in {
         '';
       };
 
+      includeStore = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to include <filename>/nix/store</filename> in the locate database.
+        '';
+      };
+
     };
 
   };
@@ -63,7 +71,6 @@ in {
   ###### implementation
 
   config = {
-
     systemd.services.update-locatedb =
       { description = "Update Locate Database";
         path  = [ pkgs.su ];
@@ -71,8 +78,9 @@ in {
           ''
             mkdir -m 0755 -p $(dirname ${toString cfg.output})
             exec updatedb \
-            --localuser=${cfg.localuser} \
-            --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
+              --localuser=${cfg.localuser} \
+              ${optionalString (!cfg.includeStore) "--prunepaths='/nix/store'"} \
+              --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
           '';
         serviceConfig.Nice = 19;
         serviceConfig.IOSchedulingClass = "idle";
diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix
index 114feb2562db..5eb38c510b48 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.
@@ -72,7 +72,7 @@ in
   };
 
   config = {
-    _module.args.pkgs = import ../../lib/nixpkgs.nix {
+    _module.args.pkgs = import ../../.. {
       system = config.nixpkgs.system;
 
       inherit (config.nixpkgs) config;
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix
index 5afdcf214f27..b4b0281fe587 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -6,12 +6,35 @@ with lib;
 
   options = {
 
+    system.stateVersion = mkOption {
+      type = types.str;
+      default = config.system.nixosRelease;
+      description = ''
+        Every once in a while, a new NixOS release may change
+        configuration defaults in a way incompatible with stateful
+        data. For instance, if the default version of PostgreSQL
+        changes, the new version will probably be unable to read your
+        existing databases. To prevent such breakage, you can set the
+        value of this option to the NixOS release with which you want
+        to be compatible. The effect is that NixOS will option
+        defaults corresponding to the specified release (such as using
+        an older version of PostgreSQL).
+      '';
+    };
+
     system.nixosVersion = mkOption {
       internal = true;
       type = types.str;
       description = "NixOS version.";
     };
 
+    system.nixosRelease = mkOption {
+      readOnly = true;
+      type = types.str;
+      default = readFile "${toString pkgs.path}/.version";
+      description = "NixOS release.";
+    };
+
     system.nixosVersionSuffix = mkOption {
       internal = true;
       type = types.str;
@@ -25,7 +48,7 @@ with lib;
     };
 
     system.nixosCodeName = mkOption {
-      internal = true;
+      readOnly = true;
       type = types.str;
       description = "NixOS release code name.";
     };
@@ -41,8 +64,7 @@ with lib;
 
   config = {
 
-    system.nixosVersion =
-      mkDefault (readFile "${toString pkgs.path}/.version" + config.system.nixosVersionSuffix);
+    system.nixosVersion = mkDefault (config.system.nixosRelease + config.system.nixosVersionSuffix);
 
     system.nixosVersionSuffix =
       let suffixFile = "${toString pkgs.path}/.version-suffix"; in
@@ -53,7 +75,7 @@ with lib;
       mkDefault (if pathExists fn then readFile fn else "master");
 
     # Note: code names must only increase in alphabetical order.
-    system.nixosCodeName = "Dingo";
+    system.nixosCodeName = "Emu";
 
     # Generate /etc/os-release.  See
     # http://0pointer.de/public/systemd-man/os-release.html for the
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 61cc551f4358..c890eac49910 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -41,6 +41,7 @@
   ./hardware/video/bumblebee.nix
   ./hardware/video/nvidia.nix
   ./hardware/video/ati.nix
+  ./installer/tools/auto-upgrade.nix
   ./installer/tools/nixos-checkout.nix
   ./installer/tools/tools.nix
   ./misc/assertions.nix
@@ -60,8 +61,8 @@
   ./programs/command-not-found/command-not-found.nix
   ./programs/dconf.nix
   ./programs/environment.nix
-  ./programs/info.nix
   ./programs/ibus.nix
+  ./programs/kbdlight.nix
   ./programs/light.nix
   ./programs/nano.nix
   ./programs/screen.nix
@@ -71,9 +72,9 @@
   ./programs/ssmtp.nix
   ./programs/uim.nix
   ./programs/venus.nix
-  ./programs/virtualbox-host.nix
   ./programs/wvdial.nix
   ./programs/freetds.nix
+  ./programs/xfs_quota.nix
   ./programs/zsh/zsh.nix
   ./rename.nix
   ./security/apparmor.nix
@@ -83,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
@@ -129,6 +131,7 @@
   ./services/databases/opentsdb.nix
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
+  ./services/databases/riak.nix
   ./services/databases/virtuoso.nix
   ./services/desktops/accountsservice.nix
   ./services/desktops/geoclue2.nix
@@ -152,6 +155,7 @@
   ./services/hardware/actkbd.nix
   ./services/hardware/amd-hybrid-graphics.nix
   ./services/hardware/bluetooth.nix
+  ./services/hardware/brltty.nix
   ./services/hardware/freefall.nix
   ./services/hardware/nvidia-optimus.nix
   ./services/hardware/pcscd.nix
@@ -185,19 +189,24 @@
   ./services/misc/canto-daemon.nix
   ./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
   ./services/misc/ihaskell.nix
+  ./services/misc/mbpfan.nix
   ./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
@@ -207,9 +216,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
@@ -218,13 +230,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
@@ -242,14 +257,17 @@
   ./services/network-filesystems/diod.nix
   ./services/network-filesystems/u9fs.nix
   ./services/network-filesystems/yandex-disk.nix
+  ./services/network-filesystems/xtreemfs.nix
   ./services/networking/aiccu.nix
   ./services/networking/amuled.nix
   ./services/networking/asterisk.nix
   ./services/networking/atftpd.nix
   ./services/networking/avahi-daemon.nix
   ./services/networking/bind.nix
+  ./services/networking/bird.nix
   ./services/networking/bitlbee.nix
   ./services/networking/btsync.nix
+  ./services/networking/charybdis.nix
   ./services/networking/chrony.nix
   ./services/networking/cjdns.nix
   ./services/networking/cntlm.nix
@@ -258,18 +276,23 @@
   ./services/networking/ddclient.nix
   ./services/networking/dhcpcd.nix
   ./services/networking/dhcpd.nix
+  ./services/networking/dnschain.nix
   ./services/networking/dnscrypt-proxy.nix
   ./services/networking/dnsmasq.nix
+  ./services/networking/docker-registry-server.nix
   ./services/networking/ejabberd.nix
+  ./services/networking/fan.nix
   ./services/networking/firefox/sync-server.nix
   ./services/networking/firewall.nix
   ./services/networking/flashpolicyd.nix
   ./services/networking/freenet.nix
+  ./services/networking/gateone.nix
   ./services/networking/git-daemon.nix
   ./services/networking/gnunet.nix
   ./services/networking/gogoclient.nix
   ./services/networking/gvpe.nix
   ./services/networking/haproxy.nix
+  ./services/networking/heyefi.nix
   ./services/networking/hostapd.nix
   ./services/networking/i2pd.nix
   ./services/networking/i2p.nix
@@ -282,9 +305,11 @@
   ./services/networking/minidlna.nix
   ./services/networking/mstpd.nix
   ./services/networking/murmur.nix
+  ./services/networking/namecoind.nix
   ./services/networking/nat.nix
   ./services/networking/networkmanager.nix
   ./services/networking/ngircd.nix
+  ./services/networking/nix-serve.nix
   ./services/networking/notbit.nix
   ./services/networking/nsd.nix
   ./services/networking/ntopng.nix
@@ -299,6 +324,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
@@ -306,6 +332,9 @@
   ./services/networking/sabnzbd.nix
   ./services/networking/searx.nix
   ./services/networking/seeks.nix
+  ./services/networking/skydns.nix
+  ./services/networking/shout.nix
+  ./services/networking/softether.nix
   ./services/networking/spiped.nix
   ./services/networking/sslh.nix
   ./services/networking/ssh/lshd.nix
@@ -319,6 +348,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
@@ -327,6 +357,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
@@ -335,6 +366,7 @@
   ./services/scheduling/fcron.nix
   ./services/scheduling/marathon.nix
   ./services/search/elasticsearch.nix
+  ./services/search/kibana.nix
   ./services/search/solr.nix
   ./services/security/clamav.nix
   ./services/security/fail2ban.nix
@@ -344,6 +376,7 @@
   ./services/security/haveged.nix
   ./services/security/hologram.nix
   ./services/security/munge.nix
+  ./services/security/physlock.nix
   ./services/security/torify.nix
   ./services/security/tor.nix
   ./services/security/torsocks.nix
@@ -366,6 +399,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
@@ -399,12 +433,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
@@ -429,6 +465,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
@@ -436,6 +473,7 @@
   ./tasks/filesystems/ntfs.nix
   ./tasks/filesystems/reiserfs.nix
   ./tasks/filesystems/unionfs-fuse.nix
+  ./tasks/filesystems/vboxsf.nix
   ./tasks/filesystems/vfat.nix
   ./tasks/filesystems/xfs.nix
   ./tasks/filesystems/zfs.nix
@@ -453,9 +491,12 @@
   ./virtualisation/docker.nix
   ./virtualisation/libvirtd.nix
   ./virtualisation/lxc.nix
+  ./virtualisation/lxd.nix
   ./virtualisation/amazon-options.nix
   ./virtualisation/openvswitch.nix
   ./virtualisation/parallels-guest.nix
   ./virtualisation/virtualbox-guest.nix
+  ./virtualisation/virtualbox-host.nix
+  ./virtualisation/vmware-guest.nix
   ./virtualisation/xen-dom0.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 f6676fc37937..79324f83646b 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -44,15 +44,10 @@
     pkgs.zip
     pkgs.dar # disk archiver
     pkgs.cabextract
-
-    # Some editors.
-    pkgs.vim
-    pkgs.bvi # binary editor
-    pkgs.joe
   ];
 
   # Include support for various filesystems.
-  boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" "zfs" "ntfs" "cifs" ];
+  boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "zfs" "ntfs" "cifs" ];
 
   # Configure host id for ZFS to work
   networking.hostId = "8425e349";
diff --git a/nixos/modules/profiles/clone-config.nix b/nixos/modules/profiles/clone-config.nix
index f0d60bb6c428..77d86f8d7405 100644
--- a/nixos/modules/profiles/clone-config.nix
+++ b/nixos/modules/profiles/clone-config.nix
@@ -30,7 +30,7 @@ let
   relocatedModuleFiles =
     let
       relocateNixOS = path:
-        "<nixos" + removePrefix nixosPath (toString path) + ">";
+        "<nixpkgs/nixos" + removePrefix nixosPath (toString path) + ">";
       relocateOthers = null;
     in
       { nixos = map relocateNixOS partitionedModuleFiles.nixos;
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..c353da227aeb 100644
--- a/nixos/modules/profiles/minimal.nix
+++ b/nixos/modules/profiles/minimal.nix
@@ -7,5 +7,8 @@ with lib;
 
 {
   environment.noXlibs = mkDefault true;
-  i18n.supportedLocales = [ config.i18n.defaultLocale ];
+
+  # This isn't perfect, but let's expect the user specifies an UTF-8 defaultLocale
+  i18n.supportedLocales = [ (config.i18n.defaultLocale + "/UTF-8") ];
+  services.nixosManual.enable = mkDefault false;
 }
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/cdemu.nix b/nixos/modules/programs/cdemu.nix
index d1b1915eea91..98df9b94380f 100644
--- a/nixos/modules/programs/cdemu.nix
+++ b/nixos/modules/programs/cdemu.nix
@@ -9,19 +9,28 @@ in {
     programs.cdemu = {
       enable = mkOption {
         default = false;
-        description = "Whether to enable cdemu for users of appropriate group (default cdrom)";
+        description = ''
+          <command>cdemu</command> for members of
+          <option>programs.cdemu.group</option>.
+        '';
       };
       group = mkOption {
         default = "cdrom";
-        description = "Required group for users of cdemu";
+        description = ''
+          Group that users must be in to use <command>cdemu</command>.
+        '';
       };
       gui = mkOption {
         default = true;
-        description = "Whether to install cdemu GUI (gCDEmu)";
+        description = ''
+          Whether to install the <command>cdemu</command> GUI (gCDEmu).
+        '';
       };
       image-analyzer = mkOption {
         default = true;
-        description = "Whether to install image analyzer";
+        description = ''
+          Whether to install the image analyzer.
+        '';
       };
     };
   };
diff --git a/nixos/modules/programs/command-not-found/command-not-found.nix b/nixos/modules/programs/command-not-found/command-not-found.nix
index bead2dcdcf90..9524d91ea3bc 100644
--- a/nixos/modules/programs/command-not-found/command-not-found.nix
+++ b/nixos/modules/programs/command-not-found/command-not-found.nix
@@ -57,9 +57,9 @@ in
           if [ $? = 126 ]; then
             "$@"
           fi
-	else
+        else
           # Indicate than there was an error so ZSH falls back to its default handler
-	  return 127
+          return 127
         fi
       }
     '';
diff --git a/nixos/modules/programs/command-not-found/command-not-found.pl b/nixos/modules/programs/command-not-found/command-not-found.pl
index 916649059d37..b233d973a4ab 100644
--- a/nixos/modules/programs/command-not-found/command-not-found.pl
+++ b/nixos/modules/programs/command-not-found/command-not-found.pl
@@ -30,11 +30,11 @@ The program ‘$program’ is currently not installed. It is provided by
 the package ‘$package’, which I will now install for you.
 EOF
         ;
-        exit 126 if system("nix-env", "-i", $package) == 0;
+        exit 126 if system("nix-env", "-iA", "nixos.$package") == 0;
     } else {
         print STDERR <<EOF;
 The program ‘$program’ is currently not installed. You can install it by typing:
-  nix-env -i $package
+  nix-env -iA nixos.$package
 EOF
     }
 } else {
@@ -42,7 +42,7 @@ EOF
 The program ‘$program’ is currently not installed. It is provided by
 several packages. You can install it by typing one of the following:
 EOF
-    print STDERR "  nix-env -i $_->{package}\n" foreach @$res;
+    print STDERR "  nix-env -iA nixos.$_->{package}\n" foreach @$res;
 }
 
 exit 127;
diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix
index dce757ceb623..52f6cc221119 100644
--- a/nixos/modules/programs/environment.nix
+++ b/nixos/modules/programs/environment.nix
@@ -23,15 +23,6 @@ in
         EDITOR = mkDefault "nano";
       };
 
-    environment.sessionVariables =
-      { NIX_PATH =
-          [ "/nix/var/nix/profiles/per-user/root/channels/nixos"
-            "nixpkgs=/etc/nixos/nixpkgs"
-            "nixos-config=/etc/nixos/configuration.nix"
-            "/nix/var/nix/profiles/per-user/root/channels"
-          ];
-      };
-
     environment.profiles =
       [ "$HOME/.nix-profile"
         "/nix/var/nix/profiles/default"
diff --git a/nixos/modules/programs/info.nix b/nixos/modules/programs/info.nix
deleted file mode 100644
index 253f9e877693..000000000000
--- a/nixos/modules/programs/info.nix
+++ /dev/null
@@ -1,38 +0,0 @@
-{config, pkgs, ...}:
-
-let
-
-  texinfo = pkgs.texinfoInteractive;
-
-  # Quick hack to make the `info' command work properly.  `info' needs
-  # a "dir" file containing all the installed Info files, which we
-  # don't have (it would be impure to have a package installation
-  # update some global "dir" file).  So this wrapper script around
-  # "info" builds a temporary "dir" file on the fly.  This is a bit
-  # slow (on a cold cache) but not unacceptably so.
-  infoWrapper = pkgs.writeScriptBin "info"
-    ''
-      #! ${pkgs.stdenv.shell}
-
-      dir=$(mktemp --tmpdir -d "info.dir.XXXXXX")
-
-      if test -z "$dir"; then exit 1; fi
-
-      trap 'rm -rf "$dir"' EXIT
-
-      shopt -s nullglob
-
-      for i in $(IFS=:; echo $INFOPATH); do
-          for j in $i/*.info; do
-              ${texinfo}/bin/install-info --quiet $j $dir/dir
-          done
-      done
-
-      INFOPATH=$dir:$INFOPATH ${texinfo}/bin/info "$@"
-    ''; # */
-
-in
-
-{
-  environment.systemPackages = [ infoWrapper texinfo ];
-}
diff --git a/nixos/modules/programs/kbdlight.nix b/nixos/modules/programs/kbdlight.nix
new file mode 100644
index 000000000000..0172368e968f
--- /dev/null
+++ b/nixos/modules/programs/kbdlight.nix
@@ -0,0 +1,16 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.kbdlight;
+
+in
+{
+  options.programs.kbdlight.enable = mkEnableOption "kbdlight";
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.kbdlight ];
+    security.setuidPrograms = [ "kbdlight" ];
+  };
+}
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index 6ca73eea5f6f..87a7bac208b7 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -18,6 +18,14 @@ let
       exec ${askPassword}
     '';
 
+  knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts);
+
+  knownHostsText = flip (concatMapStringsSep "\n") knownHosts
+    (h: assert h.hostNames != [];
+      concatStringsSep "," h.hostNames + " "
+      + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile)
+    );
+
 in
 {
   ###### interface
@@ -27,8 +35,7 @@ in
     programs.ssh = {
 
       askPassword = mkOption {
-        type = types.string;
-        default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
+        type = types.str;
         description = ''Program used by SSH to ask for passwords.'';
       };
 
@@ -77,7 +84,7 @@ in
       };
 
       agentTimeout = mkOption {
-        type = types.nullOr types.string;
+        type = types.nullOr types.str;
         default = null;
         example = "1h";
         description = ''
@@ -92,31 +99,93 @@ in
         '';
       };
 
+      knownHosts = mkOption {
+        default = {};
+        type = types.loaOf (types.submodule ({ name, ... }: {
+          options = {
+            hostNames = mkOption {
+              type = types.listOf types.str;
+              default = [];
+              description = ''
+                A list of host names and/or IP numbers used for accessing
+                the host's ssh service.
+              '';
+            };
+            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.
+              '';
+            };
+            publicKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                The path to the public key file for the host. The public
+                key file is read at build time and saved in the Nix store.
+                You can fetch a public key file from a running SSH server
+                with the <command>ssh-keyscan</command> command. The content
+                of the file should follow the same format as described for
+                the <literal>publicKey</literal> option.
+              '';
+            };
+          };
+          config = {
+            hostNames = mkDefault [ name ];
+          };
+        }));
+        description = ''
+          The set of system-wide known SSH hosts.
+        '';
+        example = [
+          {
+            hostNames = [ "myhost" "myhost.mydomain.com" "10.10.1.4" ];
+            publicKeyFile = literalExample "./pubkeys/myhost_ssh_host_dsa_key.pub";
+          }
+          {
+            hostNames = [ "myhost2" ];
+            publicKeyFile = literalExample "./pubkeys/myhost2_ssh_host_dsa_key.pub";
+          }
+        ];
+      };
+
     };
 
   };
 
   config = {
 
-    assertions = singleton
-      { assertion = cfg.forwardX11 -> cfg.setXAuthLocation;
-        message = "cannot enable X11 forwarding without setting XAuth location";
-      };
-
-    environment.etc =
-      [ { # SSH configuration.  Slight duplication of the sshd_config
-          # generation in the sshd service.
-          source = pkgs.writeText "ssh_config" ''
-            AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
-            ${optionalString cfg.setXAuthLocation ''
-              XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
-            ''}
-            ForwardX11 ${if cfg.forwardX11 then "yes" else "no"}
-            ${cfg.extraConfig}
-          '';
-          target = "ssh/ssh_config";
+    assertions =
+      [ { assertion = cfg.forwardX11 -> cfg.setXAuthLocation;
+          message = "cannot enable X11 forwarding without setting XAuth location";
         }
-      ];
+      ] ++ flip mapAttrsToList cfg.knownHosts (name: data: {
+        assertion = (data.publicKey == null && data.publicKeyFile != null) ||
+                    (data.publicKey != null && data.publicKeyFile == null);
+        message = "knownHost ${name} must contain either a publicKey or publicKeyFile";
+      });
+
+    # SSH configuration. Slight duplication of the sshd_config
+    # generation in the sshd service.
+    environment.etc."ssh/ssh_config".text =
+      ''
+        AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
+
+        ${optionalString cfg.setXAuthLocation ''
+          XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
+        ''}
+
+        ForwardX11 ${if cfg.forwardX11 then "yes" else "no"}
+
+        ${cfg.extraConfig}
+      '';
+
+    environment.etc."ssh/ssh_known_hosts".text = knownHostsText;
 
     # FIXME: this should really be socket-activated for über-awesomeness.
     systemd.user.services.ssh-agent =
@@ -153,5 +222,7 @@ in
         export SSH_ASKPASS=${askPassword}
       '';
 
+    programs.ssh.askPassword = mkDefault "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
+
   };
 }
diff --git a/nixos/modules/programs/venus.nix b/nixos/modules/programs/venus.nix
index 2b70a795f4fd..8f85b602fe2c 100644
--- a/nixos/modules/programs/venus.nix
+++ b/nixos/modules/programs/venus.nix
@@ -41,7 +41,7 @@ in
 
       dates = mkOption {
         default = "*:0/15";
-        type = types.string;
+        type = types.str;
         description = ''
           Specification (in the format described by
           <citerefentry><refentrytitle>systemd.time</refentrytitle>
@@ -52,7 +52,7 @@ in
 
       user = mkOption {
         default = "root";
-        type = types.string;
+        type = types.str;
         description = ''
           User for running venus script.
         '';
@@ -60,7 +60,7 @@ in
 
       group = mkOption {
         default = "root";
-        type = types.string;
+        type = types.str;
         description = ''
           Group for running venus script.
         '';
@@ -68,7 +68,7 @@ in
 
       name = mkOption {
         default = "NixOS Planet";
-        type = types.string;
+        type = types.str;
         description = ''
           Your planet's name.
         '';
@@ -76,7 +76,7 @@ in
 
       link = mkOption {
         default = "http://planet.nixos.org";
-        type = types.string;
+        type = types.str;
         description = ''
           Link to the main page.
         '';
@@ -84,7 +84,7 @@ in
 
       ownerName = mkOption {
         default = "Rok Garbas";
-        type = types.string;
+        type = types.str;
         description = ''
           Your name.
         '';
@@ -92,14 +92,13 @@ in
 
       ownerEmail = mkOption {
         default = "some@example.com";
-        type = types.string;
+        type = types.str;
         description = ''
           Your e-mail address.
         '';
       };
 
       outputTheme = mkOption {
-        default = "${pkgs.venus}/themes/classic_fancy";
         type = types.path;
         description = ''
           Directory containing a config.ini file which is merged with this one.
@@ -166,9 +165,11 @@ 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;
       };
 
+    services.venus.outputTheme = mkDefault "${pkgs.venus}/themes/classic_fancy";
+
   };
 }
diff --git a/nixos/modules/programs/wvdial.nix b/nixos/modules/programs/wvdial.nix
index 8e7d0e51a4e0..1ed929ed4afa 100644
--- a/nixos/modules/programs/wvdial.nix
+++ b/nixos/modules/programs/wvdial.nix
@@ -24,7 +24,7 @@ in
 
       dialerDefaults = mkOption {
         default = "";
-        type = types.string;
+        type = types.str;
         example = ''Init1 = AT+CGDCONT=1,"IP","internet.t-mobile"'';
         description = ''
           Contents of the "Dialer Defaults" section of
@@ -40,7 +40,7 @@ in
           persist
           noauth
         '';
-        type = types.string;
+        type = types.str;
         description = "Default ppp settings for wvdial.";
       };
 
diff --git a/nixos/modules/programs/xfs_quota.nix b/nixos/modules/programs/xfs_quota.nix
new file mode 100644
index 000000000000..90b6304fa999
--- /dev/null
+++ b/nixos/modules/programs/xfs_quota.nix
@@ -0,0 +1,110 @@
+# Configuration for the xfs_quota command
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.programs.xfs_quota;
+
+  limitOptions = opts: concatStringsSep " " [
+    (optionalString (opts.sizeSoftLimit != null) "bsoft=${opts.sizeSoftLimit}")
+    (optionalString (opts.sizeHardLimit != null) "bhard=${opts.sizeHardLimit}")
+  ];
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    programs.xfs_quota = {
+      projects = mkOption {
+        default = {};
+        type = types.attrsOf (types.submodule {
+          options = {
+            id = mkOption {
+              type = types.int;
+              description = "Project ID.";
+            };
+
+            fileSystem = mkOption {
+              type = types.str;
+              description = "XFS filesystem hosting the xfs_quota project.";
+              default = "/";
+            };
+
+            path = mkOption {
+              type = types.str;
+              description = "Project directory.";
+            };
+
+            sizeSoftLimit = mkOption {
+              type = types.nullOr types.str;
+              default = null;
+              example = "30g";
+              description = "Soft limit of the project size";
+            };
+
+            sizeHardLimit = mkOption {
+              type = types.nullOr types.str;
+              default = null;
+              example = "50g";
+              description = "Hard limit of the project size.";
+            };
+          };
+        });
+
+        description = "Setup of xfs_quota projects. Make sure the filesystem is mounted with the pquota option.";
+
+        example = {
+          "projname" = {
+            id = 50;
+            path = "/xfsprojects/projname";
+            sizeHardLimit = "50g";
+          };
+        };
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf (cfg.projects != {}) {
+
+    environment.etc.projects.source = pkgs.writeText "etc-project"
+      (concatStringsSep "\n" (mapAttrsToList
+        (name: opts: "${toString opts.id}:${opts.path}") cfg.projects));
+
+    environment.etc.projid.source = pkgs.writeText "etc-projid"
+      (concatStringsSep "\n" (mapAttrsToList
+        (name: opts: "${name}:${toString opts.id}") cfg.projects));
+
+    systemd.services = mapAttrs' (name: opts:
+      nameValuePair "xfs_quota-${name}" {
+        description = "Setup xfs_quota for project ${name}";
+        script = ''
+          ${pkgs.xfsprogs}/bin/xfs_quota -x -c 'project -s ${name}' ${opts.fileSystem}
+          ${pkgs.xfsprogs}/bin/xfs_quota -x -c 'limit -p ${limitOptions opts} ${name}' ${opts.fileSystem}
+        '';
+
+        wantedBy = [ "multi-user.target" ];
+        after = [ ((replaceChars [ "/" ] [ "-" ] opts.fileSystem) + ".mount") ];
+
+        restartTriggers = [ config.environment.etc.projects.source ];
+
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+        };
+      }
+    ) cfg.projects;
+
+  };
+
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index fc83e7ed590a..62be7dc6cae2 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -77,6 +77,8 @@ in zipModules ([]
 ++ obsolete [ "environment" "nix" ] [ "nix" "package" ]
 ++ obsolete [ "fonts" "enableFontConfig" ] [ "fonts" "fontconfig" "enable" ]
 ++ obsolete [ "fonts" "extraFonts" ] [ "fonts" "fonts" ]
+++ alias [ "users" "extraUsers" ] [ "users" "users" ]
+++ alias [ "users" "extraGroups" ] [ "users" "groups" ]
 
 ++ obsolete [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ]
 ++ obsolete [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ]
@@ -98,6 +100,9 @@ in zipModules ([]
 ++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]
 ++ obsolete [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]
 
+# smartd
+++ obsolete [ "services" "smartd" "deviceOpts" ] [ "services" "smartd" "defaults" "monitored" ]
+
 # OpenSSH
 ++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ]
 ++ alias [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ]
@@ -107,9 +112,17 @@ in zipModules ([]
 ++ obsolete [ "services" "sshd" "permitRootLogin" ] [ "services" "openssh" "permitRootLogin" ]
 ++ obsolete [ "services" "xserver" "startSSHAgent" ] [ "services" "xserver" "startOpenSSHAgent" ]
 ++ obsolete [ "services" "xserver" "startOpenSSHAgent" ] [ "programs" "ssh" "startAgent" ]
+++ alias [ "services" "openssh" "knownHosts" ] [ "programs" "ssh" "knownHosts" ]
 
 # VirtualBox
-++ obsolete [ "services" "virtualbox" "enable" ] [ "services" "virtualboxGuest" "enable" ]
+++ obsolete [ "services" "virtualbox" "enable" ] [ "virtualisation" "virtualbox" "guest" "enable" ]
+++ obsolete [ "services" "virtualboxGuest" "enable" ] [ "virtualisation" "virtualbox" "guest" "enable" ]
+++ obsolete [ "programs" "virtualbox" "enable" ] [ "virtualisation" "virtualbox" "host" "enable" ]
+++ obsolete [ "programs" "virtualbox" "addNetworkInterface" ] [ "virtualisation" "virtualbox" "host" "addNetworkInterface" ]
+++ obsolete [ "programs" "virtualbox" "enableHardening" ] [ "virtualisation" "virtualbox" "host" "enableHardening" ]
+++ obsolete [ "services" "virtualboxHost" "enable" ] [ "virtualisation" "virtualbox" "host" "enable" ]
+++ obsolete [ "services" "virtualboxHost" "addNetworkInterface" ] [ "virtualisation" "virtualbox" "host" "addNetworkInterface" ]
+++ obsolete [ "services" "virtualboxHost" "enableHardening" ] [ "virtualisation" "virtualbox" "host" "enableHardening" ]
 
 # Tarsnap
 ++ obsolete [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ]
@@ -141,6 +154,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 +164,7 @@ in zipModules ([]
 ++ obsolete' [ "services" "samba" "defaultShare" ]
 ++ obsolete' [ "services" "syslog-ng" "serviceName" ]
 ++ obsolete' [ "services" "syslog-ng" "listenToJournal" ]
+++ obsolete' [ "ec2" "metadata" ]
+++ obsolete' [ "services" "openvpn" "enable" ]
 
 )
diff --git a/nixos/modules/security/apparmor.nix b/nixos/modules/security/apparmor.nix
index 4fef62cbffd7..202639f98701 100644
--- a/nixos/modules/security/apparmor.nix
+++ b/nixos/modules/security/apparmor.nix
@@ -37,13 +37,5 @@ in
          ) cfg.profiles;
        };
      };
-
-     security.pam.services.apparmor.text = ''
-       ## AppArmor changes hats according to `order`: first try user, then
-       ## group, and finally fall back to a hat called "DEFAULT"
-       ##
-       ## For now, enable debugging as this is an experimental feature.
-       session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug
-     '';
    };
 }
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/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index b116d8bfef28..40942644868a 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -38,7 +38,7 @@ in
         type = types.bool;
         default = false;
         description = ''
-          Enable the testing grsecurity patch, based on Linux 3.19.
+          Enable the testing grsecurity patch, based on Linux 4.0.
         '';
       };
 
@@ -223,7 +223,7 @@ in
           message   = ''
             If grsecurity is enabled, you must select either the
             stable patch (with kernel 3.14), or the testing patch (with
-            kernel 3.19) to continue.
+            kernel 4.0) to continue.
           '';
         }
         { assertion = !(cfg.stable && cfg.testing);
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 631e8317cb4c..88760574cbc6 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -36,6 +36,16 @@ let
         '';
       };
 
+      u2fAuth = mkOption {
+        default = config.security.pam.enableU2F;
+        type = types.bool;
+        description = ''
+          If set, users listed in
+          <filename>~/.yubico/u2f_keys</filename> are able to log in
+          with the associated U2F key.
+        '';
+      };
+
       usbAuth = mkOption {
         default = config.security.pam.usb.enable;
         type = types.bool;
@@ -116,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;
@@ -174,6 +192,16 @@ let
         description = "Whether to log authentication failures in <filename>/var/log/faillog</filename>.";
       };
 
+      enableAppArmor = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable support for attaching AppArmor profiles at the
+          user/group level, e.g., as part of a role based access
+          control scheme.
+        '';
+      };
+
       text = mkOption {
         type = types.nullOr types.lines;
         description = "Contents of the PAM service file.";
@@ -209,10 +237,14 @@ let
               "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"}
           ${optionalString cfg.fprintAuth
               "auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"}
+          ${optionalString cfg.u2fAuth
+              "auth sufficient ${pkgs.pam_u2f}/lib/security/pam_u2f.so"}
           ${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
@@ -226,12 +258,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.
+          password requisite pam_unix.so nullok sha512
           ${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
@@ -268,6 +302,10 @@ 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"}
+          ${optionalString (cfg.enableAppArmor && config.security.apparmor.enable)
+              "session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug"}
         '';
     };
 
@@ -364,6 +402,13 @@ in
       '';
     };
 
+    security.pam.enableU2F = mkOption {
+      default = false;
+      description = ''
+        Enable the U2F PAM module.
+      '';
+    };
+
     security.pam.enableEcryptfs = mkOption {
       default = false;
       description = ''
@@ -374,7 +419,7 @@ in
     users.motd = mkOption {
       default = null;
       example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
-      type = types.nullOr types.string;
+      type = types.nullOr types.lines;
       description = "Message of the day shown to users when they log in.";
     };
 
@@ -392,6 +437,7 @@ in
       ++ optionals config.krb5.enable [pam_krb5 pam_ccreds]
       ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
       ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ]
+      ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ]
       ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ];
 
     security.setuidPrograms =
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/security/prey.nix b/nixos/modules/security/prey.nix
index e29fa5395a1a..1c643f2e1a57 100644
--- a/nixos/modules/security/prey.nix
+++ b/nixos/modules/security/prey.nix
@@ -16,19 +16,28 @@ in {
         default = false;
         type = types.bool;
         description = ''
-          Enables http://preyproject.com/ bash client. Be sure to specify api and device keys.
-          Once setup, cronjob will run evert 15 minutes and report status.
+          Enables the <link xlink:href="http://preyproject.com/" />
+          shell client. Be sure to specify both API and device keys.
+          Once enabled, a <command>cron</command> job will run every 15
+          minutes to report status information.
         '';
       };
 
       deviceKey = mkOption {
-        type = types.string;
-        description = "Device Key obtained from https://panel.preyproject.com/devices (and clicking on the device)";
+        type = types.str;
+        description = ''
+          <literal>Device key</literal> obtained by visiting
+          <link xlink:href="https://panel.preyproject.com/devices" />
+          and clicking on your device.
+        '';
       };
 
       apiKey = mkOption {
-        type = types.string;
-        description = "API key obtained from https://panel.preyproject.com/profile";
+        type = types.str;
+        description = ''
+          <literal>API key</literal> obtained from
+          <link xlink:href="https://panel.preyproject.com/profile" />.
+        '';
       };
     };
 
diff --git a/nixos/modules/services/amqp/activemq/default.nix b/nixos/modules/services/amqp/activemq/default.nix
index 261f97617664..56ff388f8a9e 100644
--- a/nixos/modules/services/amqp/activemq/default.nix
+++ b/nixos/modules/services/amqp/activemq/default.nix
@@ -32,7 +32,6 @@ in {
         '';
       };
       configurationDir = mkOption {
-        default = "${activemq}/conf";
         description = ''
           The base directory for ActiveMQ's configuration.
           By default, this directory is searched for a file named activemq.xml,
@@ -126,6 +125,8 @@ in {
       '';
     };
 
+    services.activemq.configurationDir = mkDefault "${activemq}/conf";
+
   };
 
 }
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..69f3c3f8a758 100644
--- a/nixos/modules/services/backup/bacula.nix
+++ b/nixos/modules/services/backup/bacula.nix
@@ -169,22 +169,27 @@ in {
         type = types.bool;
         default = false;
         description = ''
-          Whether to enable Bacula File Daemon.
+          Whether to enable the Bacula File Daemon.
         '';
       };
  
       name = mkOption {
         default = "${config.networking.hostName}-fd";
         description = ''
-        	The client name that must be used by the Director when connecting. Generally, it is a good idea to use a name related to the machine so that error messages can be easily identified if you have multiple Clients. This directive is required.
+          The client name that must be used by the Director when connecting.
+          Generally, it is a good idea to use a name related to the machine
+          so that error messages can be easily identified if you have multiple
+          Clients. This directive is required.
         '';
       };
  
       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.
+          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.
         '';
       };
  
@@ -202,7 +207,7 @@ in {
         description = ''
           Extra configuration to be passed in Client directive.
         '';
-        example = ''
+        example = literalExample ''
           Maximum Concurrent Jobs = 20;
           Heartbeat Interval = 30;
         '';
@@ -213,7 +218,7 @@ in {
         description = ''
           Extra configuration to be passed in Messages directive.
         '';
-        example = ''
+        example = literalExample ''
           console = all
         '';
       };
@@ -237,7 +242,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 +307,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/backup/postgresql-backup.nix b/nixos/modules/services/backup/postgresql-backup.nix
index 1f7b123eca37..4a5ebebc682e 100644
--- a/nixos/modules/services/backup/postgresql-backup.nix
+++ b/nixos/modules/services/backup/postgresql-backup.nix
@@ -3,13 +3,13 @@
 with lib;
 
 let
-  inherit (pkgs) postgresql gzip;
+  inherit (pkgs) gzip;
 
-  location = config.services.postgresqlBackup.location ;
+  location = config.services.postgresqlBackup.location;
 
   postgresqlBackupCron = db:
     ''
-      ${config.services.postgresqlBackup.period} root ${postgresql}/bin/pg_dump ${db} | ${gzip}/bin/gzip -c > ${location}/${db}.gz
+      ${config.services.postgresqlBackup.period} root ${config.services.postgresql.package}/bin/pg_dump ${db} | ${gzip}/bin/gzip -c > ${location}/${db}.gz
     '';
 
 in
diff --git a/nixos/modules/services/backup/sitecopy-backup.nix b/nixos/modules/services/backup/sitecopy-backup.nix
index 5f2b4e76aeeb..6e4721ded68b 100644
--- a/nixos/modules/services/backup/sitecopy-backup.nix
+++ b/nixos/modules/services/backup/sitecopy-backup.nix
@@ -21,15 +21,16 @@ in
       enable = mkOption {
         default = false;
         description = ''
-          Whether to enable sitecopy backups of specified directories.
+          Whether to enable <command>sitecopy</command> backups of specified
+          directories.
         '';
       };
 
       period = mkOption {
         default = "15 04 * * *";
         description = ''
-          This option defines (in the format used by cron) when the
-          sitecopy backup are being run.
+          This option defines (in the format used by <command>cron</command>)
+          when the <command>sitecopy</command> backups are to be run.
           The default is to update at 04:15 (at night) every day.
         '';
       };
@@ -47,9 +48,10 @@ in
         ];
         default = [];
         description = ''
-           List of attributesets describing the backups.
+           List of attribute sets describing the backups.
 
-           Username/password are extracted from <filename>${stateDir}/sitecopy.secrets</filename> at activation
+           Username/password are extracted from
+           <filename>${stateDir}/sitecopy.secrets</filename> at activation
            time. The secrets file lines should have the following structure:
            <screen>
              server username password
diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix
index f8eeb4378443..57121e238553 100644
--- a/nixos/modules/services/backup/tarsnap.nix
+++ b/nixos/modules/services/backup/tarsnap.nix
@@ -249,6 +249,8 @@ in
       script = ''
         mkdir -p -m 0755 ${dirOf cfg.cachedir}
         mkdir -p -m 0700 ${cfg.cachedir}
+        chown root:root ${cfg.cachedir}
+        chmod 0700 ${cfg.cachedir}
         DIRS=`cat /etc/tarsnap/$1.dirs`
         exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS
       '';
diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix
index 6a775bb159fc..a06384e27139 100644
--- a/nixos/modules/services/cluster/kubernetes.nix
+++ b/nixos/modules/services/cluster/kubernetes.nix
@@ -73,17 +73,11 @@ in {
       };
 
       port = mkOption {
-        description = "Kubernets apiserver listening port.";
+        description = "Kubernetes apiserver listening port.";
         default = 8080;
         type = types.int;
       };
 
-      readOnlyPort = mkOption {
-        description = "Kubernets apiserver read-only port.";
-        default = 7080;
-        type = types.int;
-      };
-
       securePort = mkOption {
         description = "Kubernetes apiserver secure port.";
         default = 6443;
@@ -102,10 +96,16 @@ in {
         type = types.str;
       };
 
+      clientCaFile = mkOption {
+        description = "Kubernetes apiserver CA file for client auth.";
+        default = "";
+        type = types.str;
+      };
+
       tokenAuth = mkOption {
         description = ''
           Kubernetes apiserver token authentication file. See
-          <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authentication.md"/>
+          <link xlink:href="http://kubernetes.io/v1.0/docs/admin/authentication.html"/>
         '';
         default = {};
         example = literalExample ''
@@ -120,7 +120,7 @@ in {
       authorizationMode = mkOption {
         description = ''
           Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC). See
-          <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authorization.md"/>
+          <link xlink:href="http://kubernetes.io/v1.0/docs/admin/authorization.html"/>
         '';
         default = "AlwaysAllow";
         type = types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC"];
@@ -129,7 +129,7 @@ in {
       authorizationPolicy = mkOption {
         description = ''
           Kubernetes apiserver authorization policy file. See
-          <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authorization.md"/>
+          <link xlink:href="http://kubernetes.io/v1.0/docs/admin/authorization.html"/>
         '';
         default = [];
         example = literalExample ''
@@ -158,6 +158,38 @@ in {
         type = types.str;
       };
 
+      runtimeConfig = mkOption {
+        description = ''
+          Api runtime configuration. See
+          <link xlink:href="http://kubernetes.io/v1.0/docs/admin/cluster-management.html"/>
+        '';
+        default = "";
+        example = "api/all=false,api/v1=true";
+        type = types.str;
+      };
+
+      admissionControl = mkOption {
+        description = ''
+          Kubernetes admission control plugins to use. See
+          <link xlink:href="http://kubernetes.io/v1.0/docs/admin/admission-controllers.html"/>
+        '';
+        default = ["AlwaysAdmit"];
+        example = [
+          "NamespaceLifecycle" "NamespaceExists" "LimitRanger"
+          "SecurityContextDeny" "ServiceAccount" "ResourceQuota"
+        ];
+        type = types.listOf types.str;
+      };
+
+      serviceAccountKey = mkOption {
+        description = ''
+          Kubernetes apiserver PEM-encoded x509 RSA private or public key file,
+          used to verify ServiceAccount tokens.
+        '';
+        default = null;
+        type = types.nullOr types.path;
+      };
+
       extraOpts = mkOption {
         description = "Kubernetes apiserver extra command line options.";
         default = "";
@@ -179,7 +211,7 @@ in {
       };
 
       port = mkOption {
-        description = "Kubernets scheduler listening port.";
+        description = "Kubernetes scheduler listening port.";
         default = 10251;
         type = types.int;
       };
@@ -211,7 +243,7 @@ in {
       };
 
       port = mkOption {
-        description = "Kubernets controller manager listening port.";
+        description = "Kubernetes controller manager listening port.";
         default = 10252;
         type = types.int;
       };
@@ -222,14 +254,26 @@ in {
         type = types.str;
       };
 
-      machines = mkOption {
-        description = "Kubernetes controller list of machines to schedule to schedule onto";
-        default = [config.networking.hostName];
-        type = types.listOf types.str;
+      serviceAccountPrivateKey = mkOption {
+        description = ''
+          Kubernetes controller manager PEM-encoded private RSA key file used to
+          sign service account tokens
+        '';
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      rootCaFile = mkOption {
+        description = ''
+          Kubernetes controller manager certificate authority file included in
+          service account's token secret.
+        '';
+        default = null;
+        type = types.nullOr types.path;
       };
 
       extraOpts = mkOption {
-        description = "Kubernetes controller extra command line options.";
+        description = "Kubernetes controller manager extra command line options.";
         default = "";
         type = types.str;
       };
@@ -242,6 +286,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";
@@ -249,11 +299,25 @@ in {
       };
 
       port = mkOption {
-        description = "Kubernets kubelet info server listening port.";
+        description = "Kubernetes kubelet info server listening port.";
         default = 10250;
         type = types.int;
       };
 
+      healthz = {
+        bind = mkOption {
+          description = "Kubernetes kubelet healthz listening address.";
+          default = "127.0.0.1";
+          type = types.str;
+        };
+
+        port = mkOption {
+          description = "Kubernetes kubelet healthz port.";
+          default = 10248;
+          type = types.int;
+        };
+      };
+
       hostname = mkOption {
         description = "Kubernetes kubelet hostname override";
         default = config.networking.hostName;
@@ -267,14 +331,17 @@ in {
       };
 
       apiServers = mkOption {
-        description = "Kubernetes kubelet list of Kubernetes API servers for publishing events, and reading pods and services.";
+        description = ''
+          Kubernetes kubelet list of Kubernetes API servers for publishing events,
+          and reading pods and services.
+        '';
         default = ["${cfg.apiserver.address}:${toString cfg.apiserver.port}"];
         type = types.listOf types.str;
       };
 
       cadvisorPort = mkOption {
         description = "Kubernetes kubelet local cadvisor port.";
-        default = config.services.cadvisor.port;
+        default = 4194;
         type = types.int;
       };
 
@@ -286,7 +353,7 @@ in {
 
       clusterDomain = mkOption {
         description = "Use alternative domain.";
-        default = "";
+        default = "kubernetes.io";
         type = types.str;
       };
 
@@ -322,13 +389,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,40 +432,40 @@ 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} \
+            --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}"} \
+            ${optionalString (cfg.apiserver.clientCaFile!="")
+              "--client-ca-file=${cfg.apiserver.clientCaFile}"} \
+            --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} \
+            ${optionalString (cfg.apiserver.runtimeConfig!="")
+              "--runtime-config=${cfg.apiserver.runtimeConfig}"} \
+            --admission_control=${concatStringsSep "," cfg.apiserver.admissionControl} \
+            ${optionalString (cfg.apiserver.serviceAccountKey!=null)
+              "--service-account-key-file=${cfg.apiserver.serviceAccountKey}"} \
             --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";
         };
-        postStart = ''
-          until ${pkgs.curl}/bin/curl -s -o /dev/null 'http://${cfg.apiserver.address}:${toString cfg.apiserver.port}/'; do
-            sleep 1;
-          done
-        '';
       };
     })
 
     (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 +475,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 +484,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" ];
@@ -404,9 +493,12 @@ in {
             --address=${cfg.controllerManager.address} \
             --port=${toString cfg.controllerManager.port} \
             --master=${cfg.controllerManager.master} \
-            --machines=${concatStringsSep "," cfg.controllerManager.machines} \
+            ${optionalString (cfg.controllerManager.serviceAccountPrivateKey!=null)
+              "--service-account-private-key-file=${cfg.controllerManager.serviceAccountPrivateKey}"} \
+            ${optionalString (cfg.controllerManager.rootCaFile!=null)
+              "--root-ca-file=${cfg.controllerManager.rootCaFile}"} \
             --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 +507,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 +515,20 @@ 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} \
+            --healthz-bind-address=${cfg.kubelet.healthz.bind} \
+            --healthz-port=${toString cfg.kubelet.healthz.port} \
+            --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,18 +538,39 @@ 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}
           '';
+          Restart = "always"; # Retry connection
+          RestartSec = "5s";
+        };
+      };
+    })
+
+    (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";
         };
       };
     })
@@ -463,18 +579,20 @@ in {
       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;
     })
 
     (mkIf (any (el: el == "node" || el == "master") cfg.roles) {
       services.etcd.enable = mkDefault true;
+
+      services.skydns.enable = mkDefault true;
+      services.skydns.domain = mkDefault cfg.kubelet.clusterDomain;
     })
 
     (mkIf (
@@ -489,8 +607,10 @@ in {
         serviceConfig.Type = "oneshot";
         script = ''
           mkdir -p /var/run/kubernetes
-          chown kubernetes /var/run/kubernetes
-          ln -fs ${pkgs.writeText "kubernetes-dockercfg" cfg.dockerCfg} /var/run/kubernetes/.dockercfg
+          chown kubernetes /var/lib/kubernetes
+
+          rm ${cfg.dataDir}/.dockercfg || true
+          ln -fs ${pkgs.writeText "kubernetes-dockercfg" cfg.dockerCfg} ${cfg.dataDir}/.dockercfg
         '';
       };
 
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 05b13492052a..efc52e917b00 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -167,6 +167,12 @@ in
 
         unitConfig.RequiresMountsFor = "${cfg.dataDir}";
 
+        path = [
+          # Needed for the mysql_install_db command in the preStart script
+          # which calls the hostname command.
+          pkgs.nettools
+        ];
+
         preStart =
           ''
             if ! test -e ${cfg.dataDir}/mysql; then
@@ -176,11 +182,12 @@ in
                 touch /tmp/mysql_init
             fi
 
-            mkdir -m 0700 -p ${cfg.pidDir}
+            mkdir -m 0755 -p ${cfg.pidDir}
             chown -R ${cfg.user} ${cfg.pidDir}
 
             # Make the socket directory
-            mkdir -m 0700 -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/opentsdb.nix b/nixos/modules/services/databases/opentsdb.nix
index 9c9738570e3f..0e73d4aca0e6 100644
--- a/nixos/modules/services/databases/opentsdb.nix
+++ b/nixos/modules/services/databases/opentsdb.nix
@@ -5,10 +5,7 @@ with lib;
 let
   cfg = config.services.opentsdb;
 
-  configFile = pkgs.writeText "opentsdb.conf" ''
-    tsd.core.auto_create_metrics = true
-    tsd.http.request.enable_chunked  = true
-  '';
+  configFile = pkgs.writeText "opentsdb.conf" cfg.config;
 
 in {
 
@@ -59,6 +56,17 @@ in {
         '';
       };
 
+      config = mkOption {
+        type = types.lines;
+        default = ''
+          tsd.core.auto_create_metrics = true
+          tsd.http.request.enable_chunked  = true
+        '';
+        description = ''
+          The contents of OpenTSDB's configuration file
+        '';
+      };
+
     };
 
   };
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index de14c56f7971..bae088c6610e 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -154,7 +154,13 @@ in
 
   config = mkIf config.services.postgresql.enable {
 
-    services.postgresql.authentication =
+    services.postgresql.package =
+      # Note: when changing the default, make it conditional on
+      # ‘system.stateVersion’ to maintain compatibility with existing
+      # systems!
+      mkDefault pkgs.postgresql94;
+
+    services.postgresql.authentication = mkAfter
       ''
         # Generated file; do not edit!
         local all all              ident ${optionalString pre84 "sameuser"}
@@ -186,8 +192,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 +202,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"
@@ -208,6 +213,7 @@ in
 
         serviceConfig =
           { ExecStart = "@${postgresql}/bin/postgres postgres ${toString flags}";
+            ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
             User = "postgres";
             Group = "postgres";
             PermissionsStartOnly = true;
diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix
new file mode 100644
index 000000000000..bee768fa42ae
--- /dev/null
+++ b/nixos/modules/services/databases/riak.nix
@@ -0,0 +1,148 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.riak;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.riak = {
+
+      enable = mkEnableOption "riak";
+
+      package = mkOption {
+        type = types.package;
+        example = literalExample "pkgs.riak2";
+        description = ''
+          Riak package to use.
+        '';
+      };
+
+      nodeName = mkOption {
+        type = types.string;
+        default = "riak@127.0.0.1";
+        description = ''
+          Name of the Erlang node.
+        '';
+      };
+
+      distributedCookie = mkOption {
+        type = types.string;
+        default = "riak";
+        description = ''
+          Cookie for distributed node communication.  All nodes in the
+          same cluster should use the same cookie or they will not be able to
+          communicate.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/db/riak";
+        description = ''
+          Data directory for Riak.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/riak";
+        description = ''
+          Log directory for Riak.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>riak.conf</filename>.
+        '';
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+    environment.etc."riak/riak.conf".text = ''
+      nodename = ${cfg.nodeName}
+      distributed_cookie = ${cfg.distributedCookie}
+
+      platform_log_dir = ${cfg.logDir}
+      platform_etc_dir = /etc/riak
+      platform_data_dir = ${cfg.dataDir}
+
+      ${cfg.extraConfig}
+    '';
+
+    users.extraUsers.riak = {
+      name = "riak";
+      uid = config.ids.uids.riak;
+      group = "riak";
+      description = "Riak server user";
+    };
+
+    users.extraGroups.riak.gid = config.ids.gids.riak;
+
+    systemd.services.riak = {
+      description = "Riak Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      path = [
+        pkgs.utillinux # for `logger`
+        pkgs.bash
+      ];
+
+      environment.RIAK_DATA_DIR = "${cfg.dataDir}";
+      environment.RIAK_LOG_DIR = "${cfg.logDir}";
+      environment.RIAK_ETC_DIR = "/etc/riak";
+
+      preStart = ''
+        if ! test -e ${cfg.logDir}; then
+          mkdir -m 0755 -p ${cfg.logDir}
+          chown -R riak ${cfg.logDir}
+        fi
+
+        if ! test -e ${cfg.dataDir}; then
+          mkdir -m 0700 -p ${cfg.dataDir}
+          chown -R riak ${cfg.dataDir}
+        fi
+      '';
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/riak console";
+        ExecStop = "${cfg.package}/bin/riak stop";
+        StandardInput = "tty";
+        User = "riak";
+        Group = "riak";
+        PermissionsStartOnly = true;
+        # Give Riak a decent amount of time to clean up.
+        TimeoutStopSec = 120;
+        LimitNOFILE = 65536;
+      };
+
+      unitConfig.RequiresMountsFor = [
+        "${cfg.dataDir}"
+        "${cfg.logDir}"
+        "/etc/riak"
+      ];
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/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/brltty.nix b/nixos/modules/services/hardware/brltty.nix
new file mode 100644
index 000000000000..03e530b2c96d
--- /dev/null
+++ b/nixos/modules/services/hardware/brltty.nix
@@ -0,0 +1,48 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.brltty;
+
+in {
+
+  options = {
+
+    services.brltty.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Whether to enable the BRLTTY daemon.";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.brltty = {
+      description = "Braille Device Support";
+      unitConfig = {
+        Documentation = "http://mielke.cc/brltty/";
+        DefaultDependencies = "no";
+        RequiresMountsFor = "${pkgs.brltty}/var/lib/brltty";
+      };
+      serviceConfig = {
+        ExecStart = "${pkgs.brltty}/bin/brltty --no-daemon";
+        Type = "simple";        # Change to notidy after next releae
+        TimeoutStartSec = 5;
+        TimeoutStopSec = 10;
+        Restart = "always";
+        RestartSec = 30;
+        Nice = -10;
+        OOMScoreAdjust = -900;
+        ProtectHome = "read-only";
+        ProtectSystem = "full";
+        SystemCallArchitectures = "native";
+      };
+      before = [ "sysinit.target" ];
+      wantedBy = [ "sysinit.target" ];
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/hardware/freefall.nix b/nixos/modules/services/hardware/freefall.nix
index 6e6960bac491..2be339766069 100644
--- a/nixos/modules/services/hardware/freefall.nix
+++ b/nixos/modules/services/hardware/freefall.nix
@@ -2,50 +2,51 @@
 
 with lib;
 
-{
+let
 
-  ###### interface
+  cfg = config.services.freefall;
 
-  options = with types; {
+in {
 
-    services.freefall = {
+  options.services.freefall = {
 
-      enable = mkOption {
-        default = false;
-        description = ''
-          Whether to protect HP/Dell laptop hard drives (not SSDs) in free fall.
-        '';
-        type = bool;
-      };
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to protect HP/Dell laptop hard drives (not SSDs) in free fall.
+      '';
+    };
 
-      devices = mkOption {
-        default = [ "/dev/sda" ];
-        description = ''
-          Device paths to all internal spinning hard drives.
-        '';
-        type = listOf string;
-      };
+    package = mkOption {
+      type = types.package;
+      default = pkgs.freefall;
+      description = ''
+        freefall derivation to use.
+      '';
+    };
 
+    devices = mkOption {
+      type = types.listOf types.string;
+      default = [ "/dev/sda" ];
+      description = ''
+        Device paths to all internal spinning hard drives.
+      '';
     };
 
   };
 
-  ###### implementation
-
   config = let
 
-    cfg = config.services.freefall;
-
     mkService = dev:
       assert dev != "";
       let dev' = utils.escapeSystemdPath dev; in
-      nameValuePair "freefall-${dev'}"
-        { description = "Free-fall protection for ${dev}";
+      nameValuePair "freefall-${dev'}" {
+        description = "Free-fall protection for ${dev}";
         after = [ "${dev'}.device" ];
         wantedBy = [ "${dev'}.device" ];
-        path = [ pkgs.freefall ];
         serviceConfig = {
-          ExecStart = "${pkgs.freefall}/bin/freefall ${dev}";
+          ExecStart = "${cfg.package}/bin/freefall ${dev}";
           Restart = "on-failure";
           Type = "forking";
         };
@@ -53,9 +54,9 @@ with lib;
 
   in mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.freefall ];
+    environment.systemPackages = [ cfg.package ];
 
-    systemd.services = listToAttrs (map mkService cfg.devices);
+    systemd.services = builtins.listToAttrs (map mkService cfg.devices);
 
   };
 
diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index 3bf765c6f991..0428602688dd 100644
--- a/nixos/modules/services/hardware/sane.nix
+++ b/nixos/modules/services/hardware/sane.nix
@@ -36,7 +36,6 @@ in
 
     hardware.sane.configDir = mkOption {
       type = types.string;
-      default = "${saneConfig}/etc/sane.d";
       description = "The value of SANE_CONFIG_DIR.";
     };
 
@@ -47,6 +46,8 @@ in
 
   config = mkIf config.hardware.sane.enable {
 
+    hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+
     environment.systemPackages = backends;
     environment.sessionVariables = {
       SANE_CONFIG_DIR = config.hardware.sane.configDir;
diff --git a/nixos/modules/services/hardware/tcsd.nix b/nixos/modules/services/hardware/tcsd.nix
index 220b154bd97a..d957b5063d38 100644
--- a/nixos/modules/services/hardware/tcsd.nix
+++ b/nixos/modules/services/hardware/tcsd.nix
@@ -17,8 +17,8 @@ let
     # what is available directly from the PCR registers.
     firmware_log_file = /sys/kernel/security/tpm0/binary_bios_measurements
     kernel_log_file = /sys/kernel/security/ima/binary_runtime_measurements
-    #firmware_pcrs = 0,1,2,3,4,5,6,7
-    #kernel_pcrs = 10,11
+    firmware_pcrs = ${cfg.firmwarePCRs}
+    kernel_pcrs = ${cfg.kernelPCRs}
     platform_cred = ${cfg.platformCred}
     conformance_cred = ${cfg.conformanceCred}
     endorsement_cred = ${cfg.endorsementCred}
@@ -60,20 +60,32 @@ in
       };
 
       stateDir = mkOption {
-	default = "/var/lib/tpm";
+        default = "/var/lib/tpm";
         type = types.path;
-	description = ''
+        description = ''
           The location of the system persistent storage file.
           The system persistent storage file holds keys and data across
           restarts of the TCSD and system reboots. 
-	'';
+        '';
+      };
+
+      firmwarePCRs = mkOption {
+        default = "0,1,2,3,4,5,6,7";
+        type = types.string;
+        description = "PCR indices used in the TPM for firmware measurements.";
+      };
+
+      kernelPCRs = mkOption {
+        default = "8,9,10,11,12";
+        type = types.string;
+        description = "PCR indices used in the TPM for kernel measurements.";
       };
 
       platformCred = mkOption {
         default = "${cfg.stateDir}/platform.cert";
         type = types.path;
         description = ''
-	  Path to the platform credential for your TPM. Your TPM
+          Path to the platform credential for your TPM. Your TPM
           manufacturer may have provided you with a set of credentials
           (certificates) that should be used when creating identities
           using your TPM. When a user of your TPM makes an identity,
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index b3baf1a44611..7ff13af15926 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
@@ -168,25 +171,21 @@ in
     };
 
     hardware.firmware = mkOption {
-      type = types.listOf types.path;
+      type = types.listOf types.package;
       default = [];
       description = ''
-        List of directories containing firmware files.  Such files
+        List of packages containing firmware files.  Such files
         will be loaded automatically if the kernel asks for them
         (i.e., when it has detected specific hardware that requires
-        firmware to function).  If more than one path contains a
-        firmware file with the same name, the first path in the list
-        takes precedence.  Note that you must rebuild your system if
-        you add files to any of these directories.  For quick testing,
-        put firmware files in <filename>/root/test-firmware</filename>
-        and add that directory to the list.  Note that you can also
-        add firmware packages to this list as these are directories in
-        the nix store.
+        firmware to function).  If multiple packages contain firmware
+        files with the same name, the first package in the list takes
+        precedence.  Note that you must rebuild your system if you add
+        files to any of these directories.
       '';
       apply = list: pkgs.buildEnv {
         name = "firmware";
         paths = list;
-        pathsToLink = [ "/" ];
+        pathsToLink = [ "/lib/firmware" ];
         ignoreCollisions = true;
       };
     };
@@ -233,7 +232,7 @@ in
       (isYes "NET")
     ];
 
-    boot.extraModprobeConfig = "options firmware_class path=${config.hardware.firmware}";
+    boot.extraModprobeConfig = "options firmware_class path=${config.hardware.firmware}/lib/firmware";
 
     system.activationScripts.udevd =
       ''
@@ -251,7 +250,7 @@ in
 
         # Allow the kernel to find our firmware.
         if [ -e /sys/module/firmware_class/parameters/path ]; then
-          echo -n "${config.hardware.firmware}" > /sys/module/firmware_class/parameters/path
+          echo -n "${config.hardware.firmware}/lib/firmware" > /sys/module/firmware_class/parameters/path
         fi
       '';
 
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/logstash.nix b/nixos/modules/services/logging/logstash.nix
index 117ee1c900f5..3a798c6f3724 100644
--- a/nixos/modules/services/logging/logstash.nix
+++ b/nixos/modules/services/logging/logstash.nix
@@ -84,10 +84,10 @@ in
         type = types.lines;
         default = ''stdin { type => "example" }'';
         description = "Logstash input configuration.";
-        example = ''
+        example = literalExample ''
           # Read from journal
           pipe {
-            command => "${pkgs.systemd}/bin/journalctl -f -o json"
+            command => "''${pkgs.systemd}/bin/journalctl -f -o json"
             type => "syslog" codec => json {}
           }
         '';
@@ -132,6 +132,7 @@ in
       description = "Logstash Daemon";
       wantedBy = [ "multi-user.target" ];
       environment = { JAVA_HOME = jre; };
+      path = [ pkgs.bash ];
       serviceConfig = {
         ExecStart =
           "${cfg.package}/bin/logstash agent " +
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/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 50ff1b38db12..fca0d2a7f616 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -10,7 +10,7 @@ let
     ''
       base_dir = /var/run/dovecot2/
 
-      protocols = ${optionalString cfg.enableImap "imap"} ${optionalString cfg.enablePop3 "pop3"}
+      protocols = ${optionalString cfg.enableImap "imap"} ${optionalString cfg.enablePop3 "pop3"} ${optionalString cfg.enableLmtp "lmtp"}
     ''
     + (if cfg.sslServerCert!="" then
     ''
@@ -70,6 +70,11 @@ in
         description = "Start the IMAP listener (when Dovecot is enabled).";
       };
 
+      enableLmtp = mkOption {
+        default = false;
+        description = "Start the LMTP listener (when Dovecot is enabled).";
+      };
+
       user = mkOption {
         default = "dovecot2";
         description = "Dovecot user name.";
diff --git a/nixos/modules/services/mail/mlmmj.nix b/nixos/modules/services/mail/mlmmj.nix
index db3a266d011f..e2b37522cb16 100644
--- a/nixos/modules/services/mail/mlmmj.nix
+++ b/nixos/modules/services/mail/mlmmj.nix
@@ -11,10 +11,10 @@ let
   listCtl = domain: list: "${listDir domain list}/control";
   transport = domain: list: "${domain}--${list}@local.list.mlmmj mlmmj:${domain}/${list}";
   virtual = domain: list: "${list}@${domain} ${domain}--${list}@local.list.mlmmj";
-  alias = domain: list: "${list}: \"|${pkgs.mlmmj}/mlmmj-receive -L ${listDir domain list}/\"";
+  alias = domain: list: "${list}: \"|${pkgs.mlmmj}/bin/mlmmj-receive -L ${listDir domain list}/\"";
   subjectPrefix = list: "[${list}]";
   listAddress = domain: list: "${list}@${domain}";
-  customHeaders = list: domain: [ "List-Id: ${list}" "Reply-To: ${list}@${domain}" ];
+  customHeaders = domain: list: [ "List-Id: ${list}" "Reply-To: ${list}@${domain}" ];
   footer = domain: list: "To unsubscribe send a mail to ${list}+unsubscribe@${domain}";
   createList = d: l: ''
     ${pkgs.coreutils}/bin/mkdir -p ${listCtl d l}
@@ -90,14 +90,15 @@ in
       enable = true;
       recipientDelimiter= "+";
       extraMasterConf = ''
-        mlmmj unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj}/bin/mlmmj-receive -F -L ${spoolDir}/$nextHop
+        mlmmj unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj}/bin/mlmmj-receive -F -L ${spoolDir}/$nexthop
       '';
 
       extraAliases = concatMapStrings (alias cfg.listDomain) cfg.mailLists;
 
       extraConfig = ''
-        transport = hash:${stateDir}/transports
-        virtual = hash:${stateDir}/virtuals
+        transport_maps = hash:${stateDir}/transports
+        virtual_alias_maps = hash:${stateDir}/virtuals
+        propagate_unmatched_extensions = virtual
       '';
     };
 
@@ -108,9 +109,10 @@ in
           ${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${spoolDir}
           ${lib.concatMapStrings (createList cfg.listDomain) cfg.mailLists}
           echo ${lib.concatMapStrings (virtual cfg.listDomain) cfg.mailLists} > ${stateDir}/virtuals
-          echo ${cfg.listDomain} mailman: > ${stateDir}/transports
-          echo ${lib.concatMapStrings (transport cfg.listDomain) cfg.mailLists} >> ${stateDir}/transports
-    '';
+          echo ${lib.concatMapStrings (transport cfg.listDomain) cfg.mailLists} > ${stateDir}/transports
+          ${pkgs.postfix}/bin/postmap ${stateDir}/virtuals
+          ${pkgs.postfix}/bin/postmap ${stateDir}/transports
+      '';
 
     systemd.services."mlmmj-maintd" = {
       description = "mlmmj maintenance daemon";
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 b84c63e6421d..e8beba4b3586 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -77,8 +77,9 @@ let
       smtpd_tls_key_file = ${cfg.sslKey}
 
       smtpd_use_tls = yes
-
-      recipientDelimiter = ${cfg.recipientDelimiter}
+    ''
+    + optionalString (cfg.recipientDelimiter != "") ''
+      recipient_delimiter = ${cfg.recipientDelimiter}
     ''
     + optionalString (cfg.virtual != "") ''
       virtual_alias_maps = hash:/etc/postfix/virtual
@@ -265,7 +266,7 @@ in
       extraAliases = mkOption {
         default = "";
         description = "
-          Additional entries to put verbatim into aliases file.
+          Additional entries to put verbatim into aliases file, cf. man-page aliases(8).
         ";
       };
 
@@ -302,7 +303,7 @@ in
       virtual = mkOption {
         default = "";
         description = "
-          Entries for the virtual alias map.
+          Entries for the virtual alias map, cf. man-page virtual(8).
         ";
       };
 
@@ -369,30 +370,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
new file mode 100644
index 000000000000..50532a8a16fb
--- /dev/null
+++ b/nixos/modules/services/misc/confd.nix
@@ -0,0 +1,89 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.confd;
+
+  confdConfig = ''
+    backend = "${cfg.backend}"
+    confdir = "${cfg.confDir}"
+    interval = ${toString cfg.interval}
+    nodes = [ ${concatMapStringsSep "," (s: ''"${s}"'') cfg.nodes}, ]
+    prefix = "${cfg.prefix}"
+    log-level = "${cfg.logLevel}"
+    watch = ${if cfg.watch then "true" else "false"}
+  '';
+
+in {
+  options.services.confd = {
+    enable = mkEnableOption "confd service";
+
+    backend = mkOption {
+      description = "Confd config storage backend to use.";
+      default = "etcd";
+      type = types.enum ["etcd" "consul" "redis" "zookeeper"];
+    };
+
+    interval = mkOption {
+      description = "Confd check interval.";
+      default = 10;
+      type = types.int;
+    };
+
+    nodes = mkOption {
+      description = "Confd list of nodes to connect to.";
+      default = [ "http://127.0.0.1:4001" ];
+      type = types.listOf types.str;
+    };
+
+    watch = mkOption {
+      description = "Confd, whether to watch etcd config for changes.";
+      default = true;
+      type = types.bool;
+    };
+
+    prefix = mkOption {
+      description = "The string to prefix to keys.";
+      default = "/";
+      type = types.path;
+    };
+
+    logLevel = mkOption {
+      description = "Confd log level.";
+      default = "info";
+      type = types.enum ["info" "debug"];
+    };
+
+    confDir = mkOption {
+      description = "The path to the confd configs.";
+      default = "/etc/confd";
+      type = types.path;
+    };
+
+    package = mkOption {
+      description = "Confd package to use.";
+      default = pkgs.confd;
+      type = types.package;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.confd = {
+      description = "Confd Service.";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/confd";
+      };
+    };
+
+    environment.etc = {
+      "confd/confd.toml".text = confdConfig;
+    };
+
+    environment.systemPackages = [ cfg.package ];
+
+    services.etcd.enable = mkIf (cfg.backend == "etcd") (mkDefault true);
+  };
+}
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/etcd.nix b/nixos/modules/services/misc/etcd.nix
index 26d2753879d0..e1839b936f01 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -122,14 +122,6 @@ in {
         mkdir -m 0700 -p ${cfg.dataDir}
         if [ "$(id -u)" = 0 ]; then chown etcd ${cfg.dataDir}; fi
       '';
-      postStart = ''
-        until ${pkgs.etcdctl}/bin/etcdctl set /nixos/state 'up'; do
-          sleep 1;
-        done
-        until ${pkgs.etcdctl}/bin/etcdctl get /nixos/state | grep up; do
-          sleep 1;
-        done
-      '';
     };
 
     environment.systemPackages = [ pkgs.etcdctl ];
diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix
new file mode 100644
index 000000000000..befd8c628f16
--- /dev/null
+++ b/nixos/modules/services/misc/gitit.nix
@@ -0,0 +1,724 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.gitit;
+
+  homeDir = "/var/lib/gitit";
+
+  toYesNo = b: if b then "yes" else "no";
+
+  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 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 = {
+
+      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" "github" ];
+        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 = types.bool;
+        default = false;
+        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 = types.bool;
+        default = true;
+        description = ''
+          Specifies whether to print a tables of contents (with links to
+          sections) on each wiki page.
+        '';
+      };
+
+      plugins = mkOption {
+        type = with types; listOf str;
+        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.
+        '';
+      };
+
+      useCache = mkOption {
+        type = types.bool;
+        default = false;
+        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 = types.bool;
+        default = false;
+        description = "Causes debug information to be logged while gitit is running.";
+      };
+
+      compressResponses = mkOption {
+        type = types.bool;
+        default = true;
+        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:
+<programlisting>
+video/x-ms-wmx  wmx
+</programlisting>
+          If the file is not found, some simple defaults will be used.
+        '';
+      };
+
+      useReCaptcha = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If true, 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 = types.bool;
+        default = false;
+        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 useFeed is false or authentication-method
+          is 'rpx'.
+        '';
+      };
+
+      absoluteUrls = mkOption {
+        type = types.bool;
+        default = false;
+        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 absoluteUrls is true, 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 = types.bool;
+        default = false;
+        description = ''
+          If true, 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 = types.bool;
+        default = true;
+        description = ''
+          If true, all HTML (including that produced by pandoc) is filtered
+          through xss-sanitize.  Set to no only if you trust all of your users.
+        '';
+      };
+
+      oauthClientId = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = "OAuth client ID";
+      };
+
+      oauthClientSecret = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = "OAuth client secret";
+      };
+
+      oauthCallback = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = "OAuth callback URL";
+      };
+
+      oauthAuthorizeEndpoint = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = "OAuth authorize endpoint";
+      };
+
+      oauthAccessTokenEndpoint = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = "OAuth access token endpoint";
+      };
+
+      githubOrg = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = "Github organization";
+      };
+  };
+
+  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: ${toYesNo 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: ${toYesNo cfg.tableOfContents}
+    plugins: ${concatStringsSep "," cfg.plugins}
+    use-cache: ${toYesNo cfg.useCache}
+    cache-dir: ${cfg.cacheDir}
+    max-upload-size: ${cfg.maxUploadSize}
+    max-page-size: ${cfg.maxPageSize}
+    debug-mode: ${toYesNo cfg.debugMode}
+    compress-responses: ${toYesNo cfg.compressResponses}
+    mime-types-file: ${cfg.mimeTypesFile}
+    use-recaptcha: ${toYesNo 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: ${toYesNo cfg.useFeed}
+    base-url: ${toString cfg.baseUrl}
+    absolute-urls: ${toYesNo cfg.absoluteUrls}
+    feed-days: ${toString cfg.feedDays}
+    feed-refresh-time: ${toString cfg.feedRefreshTime}
+    pdf-export: ${toYesNo cfg.pdfExport}
+    pandoc-user-data: ${toString cfg.pandocUserData}
+    xss-sanitize: ${toYesNo cfg.xssSanitize}
+
+    [Github]
+    oauthclientid: ${toString cfg.oauthClientId}
+    oauthclientsecret: ${toString cfg.oauthClientSecret}
+    oauthcallback: ${toString cfg.oauthCallback}
+    oauthauthorizeendpoint: ${toString cfg.oauthAuthorizeEndpoint}
+    oauthaccesstokenendpoint: ${toString cfg.oauthAccessTokenEndpoint}
+    github-org: ${toString cfg.githubOrg}
+  '';
+
+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" ];
+      path = with pkgs; [ curl ]
+             ++ optional cfg.pdfExport texLiveFull
+	     ++ optional (cfg.repositoryType == "darcs") darcs
+	     ++ optional (cfg.repositoryType == "mercurial") mercurial
+	     ++ optional (cfg.repositoryType == "git") git;
+
+      preStart = let
+        gm = "gitit@${config.networking.hostName}";
+      in
+      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 repositoryType == "darcs" then
+	  ''
+	  if [ ! -d _darcs ]
+	  then
+	    ${pkgs.darcs}/bin/darcs initialize
+	    echo "${gm}" > _darcs/prefs/email
+	  ''
+	  else if repositoryType == "mercurial" then
+	  ''
+	  if [ ! -d .hg ]
+	  then
+	    ${pkgs.mercurial}/bin/hg init
+	    cat >> .hg/hgrc <<NAMED
+[ui]
+username = gitit ${gm}
+NAMED
+	  ''
+	  else
+	  ''
+	  if [ ! -d  .git ]
+          then
+            ${pkgs.git}/bin/git init
+            ${pkgs.git}/bin/git config user.email "${gm}"
+            ${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/mbpfan.nix b/nixos/modules/services/misc/mbpfan.nix
new file mode 100644
index 000000000000..3fb5f684b761
--- /dev/null
+++ b/nixos/modules/services/misc/mbpfan.nix
@@ -0,0 +1,113 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.mbpfan;
+  verbose = if cfg.verbose then "v" else "";
+
+in {
+  options.services.mbpfan = {
+    enable = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Whether to enable the mbpfan daemon.
+      '';
+    };
+
+    package = mkOption {
+      default = pkgs.mbpfan;
+      description = ''
+        The package used for the mbpfan daemon.
+      '';
+    };
+
+    minFanSpeed = mkOption {
+      type = types.int;
+      default = 2000;
+      description = ''
+        The minimum fan speed.
+      '';
+    };
+
+    maxFanSpeed = mkOption {
+      type = types.int;
+      default = 6200;
+      description = ''
+        The maximum fan speed.
+      '';
+    };
+
+    lowTemp = mkOption {
+      type = types.int;
+      default = 63;
+      description = ''
+        The low temperature.
+      '';
+    };
+
+    highTemp = mkOption {
+      type = types.int;
+      default = 66;
+      description = ''
+        The high temperature.
+      '';
+    };
+
+    maxTemp = mkOption {
+      type = types.int;
+      default = 86;
+      description = ''
+        The maximum temperature.
+      '';
+    };
+
+    pollingInterval = mkOption {
+      type = types.int;
+      default = 7;
+      description = ''
+        The polling interval.
+      '';
+    };
+
+    verbose = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        If true, sets the log level to verbose.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    boot.kernelModules = [ "coretemp" "applesmc" ];
+
+    environment = {
+      etc."mbpfan.conf".text = ''
+        [general]
+        min_fan_speed = ${toString cfg.minFanSpeed}
+        max_fan_speed = ${toString cfg.maxFanSpeed}
+        low_temp = ${toString cfg.lowTemp}
+        high_temp = ${toString cfg.highTemp}
+        max_temp = ${toString cfg.maxTemp}
+        polling_interval = ${toString cfg.pollingInterval}
+      '';
+      systemPackages = [ cfg.package ];
+    };
+
+    systemd.services.mbpfan = {
+      description = "A fan manager daemon for MacBook Pro";
+      wantedBy = [ "sysinit.target" ];
+      after = [ "syslog.target" "sysinit.target" ];
+      restartTriggers = [ config.environment.etc."mbpfan.conf".source ];
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${cfg.package}/bin/mbpfan -f${verbose}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        PIDFile = "/var/run/mbpfan.pid";
+        Restart = "always";
+      };
+    };
+  };
+}
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 5609cf75bb5c..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 {
@@ -40,12 +40,12 @@ in {
 
       extraCmdLineOptions = mkOption {
         description = ''
-	  Extra command line options for Mesos Master.
+          Extra command line options for Mesos Master.
 
-	  See https://mesos.apache.org/documentation/latest/configuration/
-	'';
+          See https://mesos.apache.org/documentation/latest/configuration/
+        '';
         default = [ "" ];
-        type = types.listOf types.string;
+        type = types.listOf types.str;
         example = [ "--credentials=VALUE" ];
       };
 
@@ -82,20 +82,21 @@ in {
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" ];
       serviceConfig = {
-	ExecStart = ''
-	  ${pkgs.mesos}/bin/mesos-master \
-	    --port=${toString cfg.port} \
-	    --zk=${cfg.zk} \
-	    ${if cfg.quorum == 0 then "--registry=in_memory" else "--registry=replicated_log --quorum=${toString cfg.quorum}"} \
-	    --work_dir=${cfg.workDir} \
-	    --logging_level=${cfg.logLevel} \
-	    ${toString cfg.extraCmdLineOptions}
-	'';
-	Restart = "on-failure";
-	PermissionsStartOnly = true;
+        ExecStart = ''
+          ${pkgs.mesos}/bin/mesos-master \
+            --port=${toString cfg.port} \
+            ${if cfg.quorum == 0
+              then "--registry=in_memory"
+              else "--zk=${cfg.zk} --registry=replicated_log --quorum=${toString cfg.quorum}"} \
+            --work_dir=${cfg.workDir} \
+            --logging_level=${cfg.logLevel} \
+            ${toString cfg.extraCmdLineOptions}
+        '';
+        Restart = "on-failure";
+        PermissionsStartOnly = true;
       };
       preStart = ''
-	mkdir -m 0700 -p ${cfg.workDir}
+        mkdir -m 0700 -p ${cfg.workDir}
       '';
     };
   };
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..4aed91c34978 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
       '';
@@ -76,8 +78,8 @@ in
         description = ''
           This option defines the maximum number of jobs that Nix will try
           to build in parallel.  The default is 1.  You should generally
-          set it to the number of CPUs in your system (e.g., 2 on an Athlon
-          64 X2).
+          set it to the total number of logical cores in your system (e.g., 16
+          for two CPUs with 4 cores each and hyper-threading).
         '';
       };
 
@@ -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.
         '';
       };
 
@@ -252,7 +254,7 @@ in
 
       requireSignedBinaryCaches = mkOption {
         type = types.bool;
-        default = false;
+        default = true;
         description = ''
           If enabled, Nix will only download binaries from binary
           caches if they are cryptographically signed with any of the
@@ -277,6 +279,50 @@ 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.
+        '';
+      };
+
+      nixPath = mkOption {
+        type = types.listOf types.str;
+        default =
+          [ "/nix/var/nix/profiles/per-user/root/channels/nixos"
+            "nixos-config=/etc/nixos/configuration.nix"
+            "/nix/var/nix/profiles/per-user/root/channels"
+          ];
+        description = ''
+          The default Nix expression search path, used by the Nix
+          evaluator to look up paths enclosed in angle brackets
+          (e.g. <literal>&lt;nixpkgs&gt;</literal>).
+        '';
+      };
+
     };
 
   };
@@ -296,14 +342,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 +359,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
@@ -346,7 +392,9 @@ in
       };
 
     # Set up the environment variables for running Nix.
-    environment.sessionVariables = cfg.envVars;
+    environment.sessionVariables = cfg.envVars //
+      { NIX_PATH = concatStringsSep ":" cfg.nixPath;
+      };
 
     environment.extraInit =
       ''
diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix
index c570a01fb3b2..c10d8197686f 100644
--- a/nixos/modules/services/misc/nixos-manual.nix
+++ b/nixos/modules/services/misc/nixos-manual.nix
@@ -80,7 +80,6 @@ in
 
     services.nixosManual.browser = mkOption {
       type = types.path;
-      default = "${pkgs.w3m}/bin/w3m";
       description = ''
         Browser used to show the manual.
       '';
@@ -93,7 +92,7 @@ in
 
     system.build.manual = manual;
 
-    environment.systemPackages = [ manual.manpages help ];
+    environment.systemPackages = [ manual.manpages manual.manual help ];
 
     boot.extraTTYs = mkIf cfg.showManual ["tty${cfg.ttyNumber}"];
 
@@ -116,6 +115,8 @@ in
     services.mingetty.helpLine = mkIf cfg.showManual
       "\nPress <Alt-F${toString cfg.ttyNumber}> for the NixOS manual.";
 
+    services.nixosManual.browser = mkDefault "${pkgs.w3m}/bin/w3m";
+
   };
 
 }
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index f4642b5157ee..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.
@@ -30,6 +30,30 @@ in
         default = "plex";
         description = "Group under which Plex runs.";
       };
+
+
+      managePlugins = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          If set to true, this option will cause all of the symlinks in Plex's
+          plugin directory to be removed and symlinks for paths specified in
+          <option>extraPlugins</option> to be added.
+        '';
+      };
+
+      extraPlugins = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          A list of paths to extra plugin bundles to install in Plex's plugin
+          directory. Every time the systemd unit for Plex starts up, all of the
+          symlinks in Plex's plugin directory will be cleared and this module
+          will symlink all of the paths specified here to that directory. If
+          this behavior is undesired, set <option>managePlugins</option> to
+          false.
+        '';
+      };
     };
   };
 
@@ -45,13 +69,48 @@ in
           mkdir -p "${cfg.dataDir}"
           chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}"
         }
+
         # Copy the database skeleton files to /var/lib/plex/.skeleton
+        # See the the Nix expression for Plex's package for more information on
+        # why this is done.
         test -d "${cfg.dataDir}/.skeleton" || mkdir "${cfg.dataDir}/.skeleton"
         for db in "com.plexapp.plugins.library.db"; do
             cp "${plex}/usr/lib/plexmediaserver/Resources/base_$db" "${cfg.dataDir}/.skeleton/$db"
             chmod u+w "${cfg.dataDir}/.skeleton/$db"
             chown ${cfg.user}:${cfg.group} "${cfg.dataDir}/.skeleton/$db"
         done
+
+        # If managePlugins is enabled, setup symlinks for plugins.
+        ${optionalString cfg.managePlugins ''
+          echo "Preparing plugin directory."
+          PLUGINDIR="${cfg.dataDir}/Plex Media Server/Plug-ins"
+          test -d "$PLUGINDIR" || {
+            mkdir -p "$PLUGINDIR";
+            chown ${cfg.user}:${cfg.group} "$PLUGINDIR";
+          }
+
+          echo "Removing old symlinks."
+          # First, remove all of the symlinks in the directory.
+          for f in `ls "$PLUGINDIR/"`; do
+            if [[ -L "$PLUGINDIR/$f" ]]; then
+              echo "Removing plugin symlink $PLUGINDIR/$f."
+              rm "$PLUGINDIR/$f"
+            fi
+          done
+
+          echo "Symlinking plugins."
+          for path in ${toString cfg.extraPlugins}; do
+            dest="$PLUGINDIR/$(basename $path)"
+            if [[ ! -d "$path" ]]; then
+              echo "Error symlinking plugin from $path: no such directory."
+            elif [[ -d "$dest" || -L "$dest" ]]; then
+              echo "Error symlinking plugin from $path to $dest: file or directory already exists."
+            else
+              echo "Symlinking plugin at $path..."
+              ln -s "$path" "$dest"
+            fi
+          done
+        ''}
      '';
       serviceConfig = {
         Type = "simple";
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/rogue.nix b/nixos/modules/services/misc/rogue.nix
index ed8da8a518ff..aae02e384c97 100644
--- a/nixos/modules/services/misc/rogue.nix
+++ b/nixos/modules/services/misc/rogue.nix
@@ -52,6 +52,7 @@ in
             TTYPath = "/dev/${cfg.tty}";
             TTYReset = true;
             TTYVTDisallocate = true;
+            WorkingDirectory = "/tmp";
             Restart = "always";
           };
       };
diff --git a/nixos/modules/services/misc/subsonic.nix b/nixos/modules/services/misc/subsonic.nix
new file mode 100644
index 000000000000..4d164ad8d65f
--- /dev/null
+++ b/nixos/modules/services/misc/subsonic.nix
@@ -0,0 +1,159 @@
+{ 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;
+        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;
+
+    services.subsonic.transcoders = mkDefault [ "${pkgs.ffmpeg}/bin/ffmpeg" ];
+
+  };
+}
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/bosun.nix b/nixos/modules/services/monitoring/bosun.nix
index 7a53ce174542..7e8dea4ec024 100644
--- a/nixos/modules/services/monitoring/bosun.nix
+++ b/nixos/modules/services/monitoring/bosun.nix
@@ -30,6 +30,7 @@ in {
 
       package = mkOption {
         type = types.package;
+        default = pkgs.bosun;
         example = literalExample "pkgs.bosun";
         description = ''
           bosun binary to use.
@@ -95,8 +96,6 @@ in {
 
   config = mkIf cfg.enable {
   
-    services.bosun.package = mkDefault pkgs.bosun; 
-
     systemd.services.bosun = {
       description = "bosun metrics collector (part of Bosun)";
       wantedBy = [ "multi-user.target" ];
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..8c847af3bfc0 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
@@ -50,12 +51,37 @@ let
     # ganglia_port: 8651
   '';
 
+  diskConfig = pkgs.writeText "disk.yaml" ''
+    init_config:
+
+    instances:
+      - use_mount: no
+  '';
+  
+  networkConfig = pkgs.writeText "network.yaml" ''
+    init_config:
+
+    instances:
+      # Network check only supports one configured instance
+      - collect_connection_state: false
+        excluded_interfaces:
+          - lo
+          - lo0
+  '';
+  
   postgresqlConfig = pkgs.writeText "postgres.yaml" cfg.postgresqlConfig;
   nginxConfig = pkgs.writeText "nginx.yaml" cfg.nginxConfig;
-
+  mongoConfig = pkgs.writeText "mongo.yaml" cfg.mongoConfig;
+  
   etcfiles =
     [ { source = ddConf;
         target = "dd-agent/datadog.conf";
+      }
+      { source = diskConfig;
+        target = "dd-agent/conf.d/disk.yaml";
+      }
+      { source = networkConfig;
+        target = "dd-agent/conf.d/network.yaml";
       } ] ++
     (optional (cfg.postgresqlConfig != null)
       { source = postgresqlConfig;
@@ -64,6 +90,10 @@ let
     (optional (cfg.nginxConfig != null)
       { source = nginxConfig;
         target = "dd-agent/conf.d/nginx.yaml";
+      }) ++
+    (optional (cfg.mongoConfig != null)
+      { source = mongoConfig;
+        target = "dd-agent/conf.d/mongo.yaml";
       });
 
 in {
@@ -80,6 +110,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;
@@ -98,6 +135,12 @@ in {
       default = null;
       type = types.uniq (types.nullOr types.string);
     };
+    
+    mongoConfig = mkOption {
+      description = "MongoDB integration configuration";
+      default = null;
+      type = types.uniq (types.nullOr types.string);
+    };
   };
 
   config = mkIf cfg.enable {
@@ -115,7 +158,7 @@ in {
 
     systemd.services.dd-agent = {
       description = "Datadog agent monitor";
-      path = [ pkgs."dd-agent" pkgs.python pkgs.sysstat pkgs.procps];
+      path = [ pkgs."dd-agent" pkgs.python pkgs.sysstat pkgs.procps ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
         ExecStart = "${pkgs.dd-agent}/bin/dd-agent foreground";
@@ -124,7 +167,7 @@ in {
         Restart = "always";
         RestartSec = 2;
       };
-      restartTriggers = [ pkgs.dd-agent ddConf postgresqlConfig nginxConfig ];
+      restartTriggers = [ pkgs.dd-agent ddConf diskConfig networkConfig postgresqlConfig nginxConfig mongoConfig ];
     };
 
     systemd.services.dogstatsd = {
@@ -141,7 +184,7 @@ in {
         RestartSec = 2;
       };
       environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
-      restartTriggers = [ pkgs.dd-agent ddConf postgresqlConfig nginxConfig ];
+      restartTriggers = [ pkgs.dd-agent ddConf diskConfig networkConfig postgresqlConfig nginxConfig mongoConfig ];
     };
 
     environment.etc = etcfiles;
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
new file mode 100644
index 000000000000..fa653565a67f
--- /dev/null
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -0,0 +1,337 @@
+{ 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.";
+      type = types.str;
+    };
+
+    package = mkOption {
+      description = "Package to use.";
+      default = pkgs.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 the Nix store!"
+    ];
+
+    systemd.services.grafana = {
+      description = "Grafana Service Daemon";
+      wantedBy = ["multi-user.target"];
+      after = ["networking.target"];
+      serviceConfig = {
+        ExecStart = "${cfg.package-backend}/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;
+    };
+
+    services.grafana.staticRootPath = mkDefault "${cfg.package.out}/share/go/src/github.com/grafana/grafana/public";
+
+  };
+}
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..8b97daf8881a 100644
--- a/nixos/modules/services/monitoring/scollector.nix
+++ b/nixos/modules/services/monitoring/scollector.nix
@@ -20,9 +20,11 @@ let
           cfg.collectors)}
     '';
 
-  cmdLineOpts = concatStringsSep " " (
-    [ "-h=${cfg.bosunHost}" "-c=${collectors}" ] ++ cfg.extraOpts
-  );
+  conf = pkgs.writeText "scollector.toml" ''
+    Host = "${cfg.bosunHost}"
+    ColDir = "${collectors}"
+    ${cfg.extraConfig}
+  '';
 
 in {
 
@@ -73,7 +75,7 @@ in {
       };
 
       collectors = mkOption {
-        type = types.attrs;
+        type = with types; attrsOf (listOf path);
         default = {};
         example = literalExample "{ 0 = [ \"\${postgresStats}/bin/collect-stats\" ]; }";
         description = ''
@@ -92,6 +94,14 @@ in {
         '';
       };
 
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra scollector configuration added to the end of scollector.toml
+        '';
+      };
+
     };
 
   };
@@ -108,7 +118,7 @@ in {
         PermissionsStartOnly = true;
         User = cfg.user;
         Group = cfg.group;
-        ExecStart = "${cfg.package}/bin/scollector ${cmdLineOpts}";
+        ExecStart = "${cfg.package}/bin/scollector -conf=${conf} ${lib.concatStringsSep " " cfg.extraOpts}";
       };
     };
 
diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix
index 803bd9e9a65a..1017005226b2 100644
--- a/nixos/modules/services/monitoring/smartd.nix
+++ b/nixos/modules/services/monitoring/smartd.nix
@@ -4,8 +4,66 @@ with lib;
 
 let
 
+  host = config.networking.hostName or "unknown"
+       + optionalString (config.networking.domain != null) ".${config.networking.domain}";
+
   cfg = config.services.smartd;
 
+  nm = cfg.notifications.mail;
+  nw = cfg.notifications.wall;
+  nx = cfg.notifications.x11;
+
+  smartdNotify = pkgs.writeScript "smartd-notify.sh" ''
+    #! ${pkgs.stdenv.shell}
+    ${optionalString nm.enable ''
+      {
+      cat << EOF
+      From: smartd on ${host} <root>
+      To: undisclosed-recipients:;
+      Subject: SMART error on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE
+
+      $SMARTD_FULLMESSAGE
+      EOF
+
+      ${pkgs.smartmontools}/sbin/smartctl -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
+      } | ${nm.mailer} -i "${nm.recipient}"
+    ''}
+    ${optionalString nw.enable ''
+      {
+      cat << EOF
+      Problem detected with disk: $SMARTD_DEVICESTRING
+      Warning message from smartd is:
+
+      $SMARTD_MESSAGE
+      EOF
+      } | ${pkgs.utillinux}/bin/wall 2>/dev/null
+    ''}
+    ${optionalString nx.enable ''
+      export DISPLAY=${nx.display}
+      {
+      cat << EOF
+      Problem detected with disk: $SMARTD_DEVICESTRING
+      Warning message from smartd is:
+
+      $SMARTD_FULLMESSAGE
+      EOF
+      } | ${pkgs.xorg.xmessage}/bin/xmessage -file - 2>/dev/null &
+    ''}
+  '';
+
+  notifyOpts = optionalString (nm.enable || nw.enable || nx.enable)
+    ("-m <nomailer> -M exec ${smartdNotify} " + optionalString cfg.notifications.test "-M test ");
+
+  smartdConf = pkgs.writeText "smartd.conf" ''
+    # Autogenerated smartd startup config file
+    DEFAULT ${notifyOpts}${cfg.defaults.monitored}
+
+    ${concatMapStringsSep "\n" (d: "${d.device} ${d.options}") cfg.devices}
+
+    ${optionalString cfg.autodetect
+       "DEVICESCAN ${notifyOpts}${cfg.defaults.autodetected}"}
+  '';
+
   smartdOpts = { name, ... }: {
 
     options = {
@@ -22,34 +80,11 @@ let
         type = types.separatedString " ";
         description = "Options that determine how smartd monitors the device.";
       };
+
     };
 
   };
 
-  smartdMail = pkgs.writeScript "smartdmail.sh" ''
-    #! ${pkgs.stdenv.shell}
-    TMPNAM=/tmp/smartd-message.$$.tmp
-    if test -n "$SMARTD_ADDRESS"; then
-      echo  >"$TMPNAM" "From: smartd <root>"
-      echo >>"$TMPNAM" 'To: undisclosed-recipients:;'
-      echo >>"$TMPNAM" "Subject: $SMARTD_SUBJECT"
-      echo >>"$TMPNAM"
-      echo >>"$TMPNAM" "Failure on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE"
-      echo >>"$TMPNAM"
-      cat  >>"$TMPNAM"
-      ${pkgs.smartmontools}/sbin/smartctl >>"$TMPNAM" -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
-      /var/setuid-wrappers/sendmail  <"$TMPNAM" -f "$SENDER" -i "$SMARTD_ADDRESS"
-    fi
-  '';
-
-  smartdConf = pkgs.writeText "smartd.conf" (concatMapStrings (device:
-    ''
-      ${device.device} -a -m root -M exec ${smartdMail} ${device.options} ${cfg.deviceOpts}
-    ''
-    ) cfg.devices);
-
-  smartdFlags = if (cfg.devices == []) then "" else "--configfile=${smartdConf}";
-
 in
 
 {
@@ -59,26 +94,104 @@ in
 
     services.smartd = {
 
-      enable = mkOption {
-        default = false;
+      enable = mkEnableOption "smartd daemon from <literal>smartmontools</literal> package";
+
+      autodetect = mkOption {
+        default = true;
         type = types.bool;
-        example = true;
         description = ''
-          Run smartd from the smartmontools package. Note that e-mail
-          notifications will not be enabled unless you configure the list of
-          devices with <varname>services.smartd.devices</varname> as well.
+          Whenever smartd should monitor all devices connected to the
+          machine at the time it's being started (the default).
+
+          Set to false to monitor the devices listed in
+          <option>services.smartd.devices</option> only.
         '';
       };
 
-      deviceOpts = mkOption {
-        default = "";
-        type = types.string;
-        example = "-o on -s (S/../.././02|L/../../7/04)";
-        description = ''
-          Additional options for each device that is monitored. The example
-          turns on SMART Automatic Offline Testing on startup, and schedules short
-          self-tests daily, and long self-tests weekly.
-        '';
+      notifications = {
+
+        mail = {
+          enable = mkOption {
+            default = config.services.mail.sendmailSetuidWrapper != null;
+            type = types.bool;
+            description = "Whenever to send e-mail notifications.";
+          };
+
+          recipient = mkOption {
+            default = "root";
+            type = types.str;
+            description = "Recipient of the notification messages.";
+          };
+
+          mailer = mkOption {
+            default = "/var/setuid-wrappers/sendmail";
+            type = types.path;
+            description = ''
+              Sendmail-compatible binary to be used to send the messages.
+
+              You should probably enable
+              <option>services.postfix</option> or some other MTA for
+              this to work.
+            '';
+          };
+        };
+
+        wall = {
+          enable = mkOption {
+            default = true;
+            type = types.bool;
+            description = "Whenever to send wall notifications to all users.";
+          };
+        };
+
+        x11 = {
+          enable = mkOption {
+            default = config.services.xserver.enable;
+            type = types.bool;
+            description = "Whenever to send X11 xmessage notifications.";
+          };
+
+          display = mkOption {
+            default = ":${toString config.services.xserver.display}";
+            type = types.str;
+            description = "DISPLAY to send X11 notifications to.";
+          };
+        };
+
+        test = mkOption {
+          default = false;
+          type = types.bool;
+          description = "Whenever to send a test notification on startup.";
+        };
+
+      };
+
+      defaults = {
+        monitored = mkOption {
+          default = "-a";
+          type = types.separatedString " ";
+          example = "-a -o on -s (S/../.././02|L/../../7/04)";
+          description = ''
+            Common default options for explicitly monitored (listed in
+            <option>services.smartd.devices</option>) devices.
+
+            The default value turns on monitoring of all the things (see
+            <literal>man 5 smartd.conf</literal>).
+
+            The example also turns on SMART Automatic Offline Testing on
+            startup, and schedules short self-tests daily, and long
+            self-tests weekly.
+          '';
+        };
+
+        autodetected = mkOption {
+          default = cfg.defaults.monitored;
+          type = types.separatedString " ";
+          description = ''
+            Like <option>services.smartd.defaults.monitored</option>, but for the
+            autodetected devices.
+          '';
+        };
       };
 
       devices = mkOption {
@@ -86,14 +199,9 @@ in
         example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ];
         type = types.listOf types.optionSet;
         options = [ smartdOpts ];
-        description = ''
-          List of devices to monitor. By default -- if this list is empty --,
-          smartd will monitor all devices connected to the machine at the time
-          it's being run. Configuring this option has the added benefit of
-          enabling e-mail notifications to "root" every time smartd detects an
-          error.
-        '';
-       };
+        description = "List of devices to monitor.";
+      };
+
     };
 
   };
@@ -103,12 +211,19 @@ in
 
   config = mkIf cfg.enable {
 
+    assertions = [ {
+      assertion = cfg.autodetect || cfg.devices != [];
+      message = "smartd can't run with both disabled autodetect and an empty list of devices to monitor.";
+    } ];
+
     systemd.services.smartd = {
       description = "S.M.A.R.T. Daemon";
 
       wantedBy = [ "multi-user.target" ];
 
-      serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork ${smartdFlags}";
+      path = [ pkgs.nettools ]; # for hostname and dnsdomanname calls in smartd
+
+      serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork --configfile=${smartdConf}";
     };
 
   };
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/nfsd.nix b/nixos/modules/services/network-filesystems/nfsd.nix
index 33b7ec3d9f1c..f1838224098b 100644
--- a/nixos/modules/services/network-filesystems/nfsd.nix
+++ b/nixos/modules/services/network-filesystems/nfsd.nix
@@ -88,10 +88,7 @@ in
 
     environment.systemPackages = [ pkgs.nfs-utils ];
 
-    environment.etc = singleton
-      { source = exports;
-        target = "exports";
-      };
+    environment.etc.exports.source = exports;
 
     boot.kernelModules = [ "nfsd" ];
 
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 8b3741bca0af..72e9b6144d4b 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -97,8 +97,8 @@ in
         description = ''
           Enabling this will add a line directly after pam_unix.so.
           Whenever a password is changed the samba password will be updated as well.
-          However you still yave to add the samba password once using smbpasswd -a user
-          If you don't want to maintain an extra pwd database you still can send plain text
+          However, you still have to add the samba password once, using smbpasswd -a user.
+          If you don't want to maintain an extra password database, you still can send plain text
           passwords which is not secure.
         '';
       };
@@ -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/network-filesystems/xtreemfs.nix b/nixos/modules/services/network-filesystems/xtreemfs.nix
new file mode 100644
index 000000000000..b051214e1d08
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/xtreemfs.nix
@@ -0,0 +1,469 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.xtreemfs;
+
+  xtreemfs = pkgs.xtreemfs;
+
+  home = cfg.homeDir;
+
+  startupScript = class: configPath: pkgs.writeScript "xtreemfs-osd.sh" ''
+    #! ${pkgs.stdenv.shell}
+    JAVA_HOME="${pkgs.jdk}"
+    JAVADIR="${xtreemfs}/share/java"
+    JAVA_CALL="$JAVA_HOME/bin/java -ea -cp $JAVADIR/XtreemFS.jar:$JAVADIR/BabuDB.jar:$JAVADIR/Flease.jar:$JAVADIR/protobuf-java-2.5.0.jar:$JAVADIR/Foundation.jar:$JAVADIR/jdmkrt.jar:$JAVADIR/jdmktk.jar:$JAVADIR/commons-codec-1.3.jar"
+    $JAVA_CALL ${class} ${configPath}
+  '';
+
+  dirReplicationConfig = pkgs.writeText "xtreemfs-dir-replication-plugin.properties" ''
+    babudb.repl.backupDir = ${home}/server-repl-dir
+    plugin.jar = ${xtreemfs}/share/java/BabuDB_replication_plugin.jar
+    babudb.repl.dependency.0 = ${xtreemfs}/share/java/Flease.jar
+
+    ${cfg.dir.replication.extraConfig}
+  '';
+
+  dirConfig = pkgs.writeText "xtreemfs-dir-config.properties" ''
+    uuid = ${cfg.dir.uuid}
+    listen.port = ${toString cfg.dir.port}
+    ${optionalString (cfg.dir.address != "") "listen.address = ${cfg.dir.address}"}
+    http_port = ${toString cfg.dir.httpPort}
+    babudb.baseDir = ${home}/dir/database
+    babudb.logDir = ${home}/dir/db-log
+    babudb.sync = ${if cfg.dir.replication.enable then "FDATASYNC" else cfg.dir.syncMode}
+
+    ${optionalString cfg.dir.replication.enable "babudb.plugin.0 = ${dirReplicationConfig}"}
+
+    ${cfg.dir.extraConfig}
+  '';
+
+  mrcReplicationConfig = pkgs.writeText "xtreemfs-mrc-replication-plugin.properties" ''
+    babudb.repl.backupDir = ${home}/server-repl-mrc
+    plugin.jar = ${xtreemfs}/share/java/BabuDB_replication_plugin.jar
+    babudb.repl.dependency.0 = ${xtreemfs}/share/java/Flease.jar
+
+    ${cfg.mrc.replication.extraConfig}
+  '';
+
+  mrcConfig = pkgs.writeText "xtreemfs-mrc-config.properties" ''
+    uuid = ${cfg.mrc.uuid}
+    listen.port = ${toString cfg.mrc.port}
+    ${optionalString (cfg.mrc.address != "") "listen.address = ${cfg.mrc.address}"}
+    http_port = ${toString cfg.mrc.httpPort}
+    babudb.baseDir = ${home}/mrc/database
+    babudb.logDir = ${home}/mrc/db-log
+    babudb.sync = ${if cfg.mrc.replication.enable then "FDATASYNC" else cfg.mrc.syncMode}
+
+    ${optionalString cfg.mrc.replication.enable "babudb.plugin.0 = ${mrcReplicationConfig}"}
+
+    ${cfg.mrc.extraConfig}
+  '';
+
+  osdConfig = pkgs.writeText "xtreemfs-osd-config.properties" ''
+    uuid = ${cfg.osd.uuid}
+    listen.port = ${toString cfg.osd.port}
+    ${optionalString (cfg.osd.address != "") "listen.address = ${cfg.osd.address}"}
+    http_port = ${toString cfg.osd.httpPort}
+    object_dir = ${home}/osd/
+
+    ${cfg.osd.extraConfig}
+  '';
+
+  optionalDir = optionals cfg.dir.enable ["xtreemfs-dir.service"];
+
+  systemdOptionalDependencies = {
+    after = [ "network.target" ] ++ optionalDir;
+    wantedBy = [ "multi-user.target" ] ++ optionalDir;
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xtreemfs = {
+
+      enable = mkEnableOption "XtreemFS";
+
+      homeDir = mkOption {
+        default = "/var/lib/xtreemfs";
+        description = ''
+          XtreemFS home dir for the xtreemfs user.
+        '';
+      };
+
+      dir = {
+        enable = mkOption {
+          default = true;
+          description = ''
+            Whether to enable XtreemFS DIR service.
+          '';
+        };
+        uuid = mkOption {
+          example = "eacb6bab-f444-4ebf-a06a-3f72d7465e40";
+          description = ''
+            Must be set to a unique identifier, preferably a UUID according to
+            RFC 4122. UUIDs can be generated with `uuidgen` command, found in
+            the `utillinux` package.
+          '';
+        };
+        port = mkOption {
+          default = 32638;
+          description = ''
+            The port to listen on for incoming connections (TCP).
+          '';
+        };
+        address = mkOption {
+          example = "127.0.0.1";
+          default = "";
+          description = ''
+            If specified, it defines the interface to listen on. If not
+            specified, the service will listen on all interfaces (any).
+          '';
+        };
+        httpPort = mkOption {
+          default = 30638;
+          description = ''
+            Specifies the listen port for the HTTP service that returns the
+            status page.
+          '';
+        };
+        syncMode = mkOption {
+          default = "FSYNC";
+          example = "FDATASYNC";
+          description = ''
+            The sync mode influences how operations are committed to the disk
+            log before the operation is acknowledged to the caller.
+
+            -ASYNC mode the writes to the disk log are buffered in memory by the operating system. This is the fastest mode but will lead to data loss in case of a crash, kernel panic or power failure.
+            -SYNC_WRITE_METADATA opens the file with O_SYNC, the system will not buffer any writes. The operation will be acknowledged when data has been safely written to disk. This mode is slow but offers maximum data safety. However, BabuDB cannot influence the disk drive caches, this depends on the OS and hard disk model.
+            -SYNC_WRITE similar to SYNC_WRITE_METADATA but opens file with O_DSYNC which means that only the data is commit to disk. This can lead to some data loss depending on the implementation of the underlying file system. Linux does not implement this mode.
+            -FDATASYNC is similar to SYNC_WRITE but opens the file in asynchronous mode and calls fdatasync() after writing the data to disk.
+            -FSYNC is similar to SYNC_WRITE_METADATA but opens the file in asynchronous mode and calls fsync() after writing the data to disk.
+
+            For best throughput use ASYNC, for maximum data safety use FSYNC.
+
+            (If xtreemfs.dir.replication.enable is true then FDATASYNC is forced)
+          '';
+        };
+        extraConfig = mkOption {
+          default = "";
+          example = ''
+            # specify whether SSL is required
+            ssl.enabled = true
+            ssl.service_creds.pw = passphrase
+            ssl.service_creds.container = pkcs12
+            ssl.service_creds = /etc/xos/xtreemfs/truststore/certs/dir.p12
+            ssl.trusted_certs = /etc/xos/xtreemfs/truststore/certs/trusted.jks
+            ssl.trusted_certs.pw = jks_passphrase
+            ssl.trusted_certs.container = jks
+          '';
+          description = ''
+            Configuration of XtreemFS DIR service.
+            WARNING: configuration is saved as plaintext inside nix store.
+            For more options: http://www.xtreemfs.org/xtfs-guide-1.5.1/index.html
+          '';
+        };
+        replication = {
+          enable = mkEnableOption "XtreemFS DIR replication plugin";
+          extraConfig = mkOption {
+            example = ''
+              # participants of the replication including this replica
+              babudb.repl.participant.0 = 192.168.0.10
+              babudb.repl.participant.0.port = 35676
+              babudb.repl.participant.1 = 192.168.0.11
+              babudb.repl.participant.1.port = 35676
+              babudb.repl.participant.2 = 192.168.0.12
+              babudb.repl.participant.2.port = 35676
+
+              # number of servers that at least have to be up to date
+              # To have a fault-tolerant system, this value has to be set to the
+              # majority of nodes i.e., if you have three replicas, set this to 2
+              # Please note that a setup with two nodes provides no fault-tolerance.
+              babudb.repl.sync.n = 2
+
+              # specify whether SSL is required
+              babudb.ssl.enabled = true
+
+              babudb.ssl.protocol = tlsv12
+
+              # server credentials for SSL handshakes
+              babudb.ssl.service_creds = /etc/xos/xtreemfs/truststore/certs/osd.p12
+              babudb.ssl.service_creds.pw = passphrase
+              babudb.ssl.service_creds.container = pkcs12
+
+              # trusted certificates for SSL handshakes
+              babudb.ssl.trusted_certs = /etc/xos/xtreemfs/truststore/certs/trusted.jks
+              babudb.ssl.trusted_certs.pw = jks_passphrase
+              babudb.ssl.trusted_certs.container = jks
+
+              babudb.ssl.authenticationWithoutEncryption = false
+            '';
+            description = ''
+              Configuration of XtreemFS DIR replication plugin.
+              WARNING: configuration is saved as plaintext inside nix store.
+              For more options: http://www.xtreemfs.org/xtfs-guide-1.5.1/index.html
+            '';
+          };
+        };
+      };
+
+      mrc = {
+        enable = mkOption {
+          default = true;
+          description = ''
+            Whether to enable XtreemFS MRC service.
+          '';
+        };
+        uuid = mkOption {
+          example = "eacb6bab-f444-4ebf-a06a-3f72d7465e41";
+          description = ''
+            Must be set to a unique identifier, preferably a UUID according to
+            RFC 4122. UUIDs can be generated with `uuidgen` command, found in
+            the `utillinux` package.
+          '';
+        };
+        port = mkOption {
+          default = 32636;
+          description = ''
+            The port to listen on for incoming connections (TCP).
+          '';
+        };
+        address = mkOption {
+          example = "127.0.0.1";
+          default = "";
+          description = ''
+            If specified, it defines the interface to listen on. If not
+            specified, the service will listen on all interfaces (any).
+          '';
+        };
+        httpPort = mkOption {
+          default = 30636;
+          description = ''
+            Specifies the listen port for the HTTP service that returns the
+            status page.
+          '';
+        };
+        syncMode = mkOption {
+          default = "FSYNC";
+          example = "FDATASYNC";
+          description = ''
+            The sync mode influences how operations are committed to the disk
+            log before the operation is acknowledged to the caller.
+
+            -ASYNC mode the writes to the disk log are buffered in memory by the operating system. This is the fastest mode but will lead to data loss in case of a crash, kernel panic or power failure.
+            -SYNC_WRITE_METADATA opens the file with O_SYNC, the system will not buffer any writes. The operation will be acknowledged when data has been safely written to disk. This mode is slow but offers maximum data safety. However, BabuDB cannot influence the disk drive caches, this depends on the OS and hard disk model.
+            -SYNC_WRITE similar to SYNC_WRITE_METADATA but opens file with O_DSYNC which means that only the data is commit to disk. This can lead to some data loss depending on the implementation of the underlying file system. Linux does not implement this mode.
+            -FDATASYNC is similar to SYNC_WRITE but opens the file in asynchronous mode and calls fdatasync() after writing the data to disk.
+            -FSYNC is similar to SYNC_WRITE_METADATA but opens the file in asynchronous mode and calls fsync() after writing the data to disk.
+
+            For best throughput use ASYNC, for maximum data safety use FSYNC.
+
+            (If xtreemfs.mrc.replication.enable is true then FDATASYNC is forced)
+          '';
+        };
+        extraConfig = mkOption {
+          example = ''
+            osd_check_interval = 300
+            no_atime = true
+            local_clock_renewal = 0
+            remote_time_sync = 30000
+            authentication_provider = org.xtreemfs.common.auth.NullAuthProvider
+
+            # shared secret between the MRC and all OSDs
+            capability_secret = iNG8UuQJrJ6XVDTe
+
+            dir_service.host = 192.168.0.10
+            dir_service.port = 32638
+
+            # if replication is enabled
+            dir_service.1.host = 192.168.0.11
+            dir_service.1.port = 32638
+            dir_service.2.host = 192.168.0.12
+            dir_service.2.port = 32638
+
+            # specify whether SSL is required
+            ssl.enabled = true
+            ssl.protocol = tlsv12
+            ssl.service_creds.pw = passphrase
+            ssl.service_creds.container = pkcs12
+            ssl.service_creds = /etc/xos/xtreemfs/truststore/certs/mrc.p12
+            ssl.trusted_certs = /etc/xos/xtreemfs/truststore/certs/trusted.jks
+            ssl.trusted_certs.pw = jks_passphrase
+            ssl.trusted_certs.container = jks
+          '';
+          description = ''
+            Configuration of XtreemFS MRC service.
+            WARNING: configuration is saved as plaintext inside nix store.
+            For more options: http://www.xtreemfs.org/xtfs-guide-1.5.1/index.html
+          '';
+        };
+        replication = {
+          enable = mkEnableOption "XtreemFS MRC replication plugin";
+          extraConfig = mkOption {
+            example = ''
+              # participants of the replication including this replica
+              babudb.repl.participant.0 = 192.168.0.10
+              babudb.repl.participant.0.port = 35678
+              babudb.repl.participant.1 = 192.168.0.11
+              babudb.repl.participant.1.port = 35678
+              babudb.repl.participant.2 = 192.168.0.12
+              babudb.repl.participant.2.port = 35678
+
+              # number of servers that at least have to be up to date
+              # To have a fault-tolerant system, this value has to be set to the
+              # majority of nodes i.e., if you have three replicas, set this to 2
+              # Please note that a setup with two nodes provides no fault-tolerance.
+              babudb.repl.sync.n = 2
+
+              # specify whether SSL is required
+              babudb.ssl.enabled = true
+
+              babudb.ssl.protocol = tlsv12
+
+              # server credentials for SSL handshakes
+              babudb.ssl.service_creds = /etc/xos/xtreemfs/truststore/certs/osd.p12
+              babudb.ssl.service_creds.pw = passphrase
+              babudb.ssl.service_creds.container = pkcs12
+
+              # trusted certificates for SSL handshakes
+              babudb.ssl.trusted_certs = /etc/xos/xtreemfs/truststore/certs/trusted.jks
+              babudb.ssl.trusted_certs.pw = jks_passphrase
+              babudb.ssl.trusted_certs.container = jks
+
+              babudb.ssl.authenticationWithoutEncryption = false
+            '';
+            description = ''
+              Configuration of XtreemFS MRC replication plugin.
+              WARNING: configuration is saved as plaintext inside nix store.
+              For more options: http://www.xtreemfs.org/xtfs-guide-1.5.1/index.html
+            '';
+          };
+        };
+      };
+
+      osd = {
+        enable = mkOption {
+          default = true;
+          description = ''
+            Whether to enable XtreemFS OSD service.
+          '';
+        };
+        uuid = mkOption {
+          example = "eacb6bab-f444-4ebf-a06a-3f72d7465e42";
+          description = ''
+            Must be set to a unique identifier, preferably a UUID according to
+            RFC 4122. UUIDs can be generated with `uuidgen` command, found in
+            the `utillinux` package.
+          '';
+        };
+        port = mkOption {
+          default = 32640;
+          description = ''
+            The port to listen on for incoming connections (TCP and UDP).
+          '';
+        };
+        address = mkOption {
+          example = "127.0.0.1";
+          default = "";
+          description = ''
+            If specified, it defines the interface to listen on. If not
+            specified, the service will listen on all interfaces (any).
+          '';
+        };
+        httpPort = mkOption {
+          default = 30640;
+          description = ''
+            Specifies the listen port for the HTTP service that returns the
+            status page.
+          '';
+        };
+        extraConfig = mkOption {
+          example = ''
+            local_clock_renewal = 0
+            remote_time_sync = 30000
+            report_free_space = true
+            capability_secret = iNG8UuQJrJ6XVDTe
+
+            dir_service.host = 192.168.0.10
+            dir_service.port = 32638
+
+            # if replication is used
+            dir_service.1.host = 192.168.0.11
+            dir_service.1.port = 32638
+            dir_service.2.host = 192.168.0.12
+            dir_service.2.port = 32638
+
+            # specify whether SSL is required
+            ssl.enabled = true
+            ssl.service_creds.pw = passphrase
+            ssl.service_creds.container = pkcs12
+            ssl.service_creds = /etc/xos/xtreemfs/truststore/certs/osd.p12
+            ssl.trusted_certs = /etc/xos/xtreemfs/truststore/certs/trusted.jks
+            ssl.trusted_certs.pw = jks_passphrase
+            ssl.trusted_certs.container = jks
+          '';
+          description = ''
+            Configuration of XtreemFS OSD service.
+            WARNING: configuration is saved as plaintext inside nix store.
+            For more options: http://www.xtreemfs.org/xtfs-guide-1.5.1/index.html
+          '';
+        };
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = lib.mkIf cfg.enable {
+
+    environment.systemPackages = [ xtreemfs ];
+
+    users.extraUsers.xtreemfs =
+      { uid = config.ids.uids.xtreemfs;
+        description = "XtreemFS user";
+        createHome = true;
+        home = home;
+      };
+
+    users.extraGroups.xtreemfs =
+      { gid = config.ids.gids.xtreemfs;
+      };
+
+    systemd.services.xtreemfs-dir = mkIf cfg.dir.enable {
+      description = "XtreemFS-DIR Server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "xtreemfs";
+        ExecStart = "${startupScript "org.xtreemfs.dir.DIR" dirConfig}";
+      };
+    };
+
+    systemd.services.xtreemfs-mrc = mkIf cfg.mrc.enable ({
+      description = "XtreemFS-MRC Server";
+      serviceConfig = {
+        User = "xtreemfs";
+        ExecStart = "${startupScript "org.xtreemfs.mrc.MRC" mrcConfig}";
+      };
+    } // systemdOptionalDependencies);
+
+    systemd.services.xtreemfs-osd = mkIf cfg.osd.enable ({
+      description = "XtreemFS-OSD Server";
+      serviceConfig = {
+        User = "xtreemfs";
+        ExecStart = "${startupScript "org.xtreemfs.osd.OSD" osdConfig}";
+      };
+    } // systemdOptionalDependencies);
+
+  };
+
+}
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/bind.nix b/nixos/modules/services/networking/bind.nix
index 57547da10067..34e7470dfc6f 100644
--- a/nixos/modules/services/networking/bind.nix
+++ b/nixos/modules/services/networking/bind.nix
@@ -24,6 +24,8 @@ let
         pid-file "/var/run/named/named.pid";
       };
 
+      ${cfg.extraConfig}
+
       ${ concatMapStrings
           ({ name, file, master ? true, slaves ? [], masters ? [] }:
             ''
@@ -110,6 +112,13 @@ in
         }];
       };
 
+      extraConfig = mkOption {
+        default = "";
+        description = "
+          Extra lines to be added verbatim to the generated named configuration file.
+        ";
+      };
+
       configFile = mkOption {
         default = confFile;
         description = "
diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix
new file mode 100644
index 000000000000..e7e1db191529
--- /dev/null
+++ b/nixos/modules/services/networking/bird.nix
@@ -0,0 +1,76 @@
+{ config, lib, pkgs, ... }:
+
+let
+  inherit (lib) mkEnableOption mkIf mkOption singleton types;
+  inherit (pkgs) bird;
+  cfg = config.services.bird;
+
+  configFile = pkgs.writeText "bird.conf" ''
+    ${cfg.config}
+  '';
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.bird = {
+
+      enable = mkEnableOption "BIRD Internet Routing Daemon";
+
+      config = mkOption {
+        type = types.string;
+        description = ''
+          BIRD Internet Routing Daemon configuration file.
+          <link xlink:href='http://bird.network.cz/'/>
+        '';
+      };
+
+      user = mkOption {
+        type = types.string;
+        default = "ircd";
+        description = ''
+          BIRD Internet Routing Daemon user.
+        '';
+      };
+
+      group = mkOption {
+        type = types.string;
+        default = "ircd";
+        description = ''
+          BIRD Internet Routing Daemon group.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton {
+      name = cfg.user;
+      description = "BIRD Internet Routing Daemon user";
+      uid = config.ids.uids.bird;
+      group = cfg.group;
+    };
+
+    users.extraGroups = singleton {
+      name = cfg.group;
+      gid = config.ids.gids.bird;
+    };
+
+    systemd.services.bird = {
+      description = "BIRD Internet Routing Daemon";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart   = "${bird}/bin/bird -d -c ${configFile} -s /var/run/bird.ctl -u ${cfg.user} -g ${cfg.group}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix
index 7276603da16f..5e6847097a94 100644
--- a/nixos/modules/services/networking/bitlbee.nix
+++ b/nixos/modules/services/networking/bitlbee.nix
@@ -16,11 +16,14 @@ let
     ''
     [settings]
     RunMode = Daemon
-    User = bitlbee  
-    ConfigDir = /var/lib/bitlbee      
+    User = bitlbee
+    ConfigDir = ${cfg.configDir}
     DaemonInterface = ${cfg.interface}
     DaemonPort = ${toString cfg.portNumber}
     AuthMode = ${cfg.authMode}
+    Plugindir = ${pkgs.bitlbee-plugins cfg.plugins}/lib/bitlbee
+    ${lib.optionalString (cfg.hostName != "") "HostName = ${cfg.hostName}"}
+    ${lib.optionalString (cfg.protocols != "") "Protocols = ${cfg.protocols}"}
     ${cfg.extraSettings}
 
     [defaults]
@@ -70,21 +73,58 @@ in
             Open -- Accept connections from anyone, use NickServ for user authentication.
             Closed -- Require authorization (using the PASS command during login) before allowing the user to connect at all.
             Registered -- Only allow registered users to use this server; this disables the register- and the account command until the user identifies himself.
-        ''; 
+        '';
+      };
+
+      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.
+        '';
+      };
+
+      plugins = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        example = literalExample "[ pkgs.bitlbee-facebook ]";
+        description = ''
+          The list of bitlbee plugins to install.
+        '';
+      };
+
+      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 = ''
           Will be inserted in the Settings section of the config file.
-        ''; 
+        '';
       };
 
       extraDefaults = mkOption {
         default = "";
         description = ''
           Will be inserted in the Default section of the config file.
-        ''; 
+        '';
       };
 
     };
@@ -108,7 +148,7 @@ in
         gid = config.ids.gids.bitlbee;
       };
 
-    systemd.services.bitlbee = 
+    systemd.services.bitlbee =
       { description = "BitlBee IRC to other chat networks gateway";
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
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
new file mode 100644
index 000000000000..2f7d006b8816
--- /dev/null
+++ b/nixos/modules/services/networking/charybdis.nix
@@ -0,0 +1,96 @@
+{ config, lib, pkgs, ... }:
+
+let
+  inherit (lib) mkEnableOption mkIf mkOption singleton types;
+  inherit (pkgs) coreutils charybdis;
+  cfg = config.services.charybdis;
+
+  configFile = pkgs.writeText "charybdis.conf" ''
+    ${cfg.config}
+  '';
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.charybdis = {
+
+      enable = mkEnableOption "Charybdis IRC daemon";
+
+      config = mkOption {
+        type = types.string;
+        description = ''
+          Charybdis IRC daemon configuration file.
+        '';
+      };
+
+      statedir = mkOption {
+        type = types.string;
+        default = "/var/lib/charybdis";
+        description = ''
+          Location of the state directory of charybdis.
+        '';
+      };
+
+      user = mkOption {
+        type = types.string;
+        default = "ircd";
+        description = ''
+          Charybdis IRC daemon user.
+        '';
+      };
+
+      group = mkOption {
+        type = types.string;
+        default = "ircd";
+        description = ''
+          Charybdis IRC daemon group.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton {
+      name = cfg.user;
+      description = "Charybdis IRC daemon user";
+      uid = config.ids.uids.ircd;
+      group = cfg.group;
+    };
+
+    users.extraGroups = singleton {
+      name = cfg.group;
+      gid = config.ids.gids.ircd;
+    };
+
+    systemd.services.charybdis = {
+      description = "Charybdis IRC daemon";
+      wantedBy = [ "multi-user.target" ];
+      environment = {
+        BANDB_DBPATH = "${cfg.statedir}/ban.db";
+      };
+      serviceConfig = {
+        ExecStart   = "${charybdis}/bin/charybdis-ircd -foreground -logfile /dev/stdout -configfile ${configFile}";
+        Group = cfg.group;
+        User = cfg.user;
+        PermissionsStartOnly = true; # preStart needs to run with root permissions
+      };
+      preStart = ''
+        ${coreutils}/bin/mkdir -p ${cfg.statedir}
+        ${coreutils}/bin/chown ${cfg.user}:${cfg.group} ${cfg.statedir}
+      '';
+
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix
index 482b61997ae1..deb1cbfc1858 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -5,7 +5,12 @@ with lib;
 
 let
   cfg = config.networking.connman;
+  configFile = pkgs.writeText "connman.conf" ''
+    [General]
+    NetworkInterfaceBlacklist=${concatStringsSep "," cfg.networkInterfaceBlacklist}
 
+    ${cfg.extraConfig}
+  '';
 in {
 
   ###### interface
@@ -22,6 +27,23 @@ in {
         '';
       };
 
+      extraConfig = mkOption {
+        type = types.lines;
+        default = ''
+        '';
+        description = ''
+          Configuration lines appended to the generated connman configuration file.
+        '';
+      };
+
+      networkInterfaceBlacklist = mkOption {
+        type = with types; listOf string;
+        default = [ "vmnet" "vboxnet" "virbr" "ifb" "ve" ];
+        description = ''
+          Default blacklisted interfaces, this includes NixOS containers interfaces (ve).
+        '';
+      };
+
     };
 
   };
@@ -51,7 +73,7 @@ in {
         Type = "dbus";
         BusName = "net.connman";
         Restart = "on-failure";
-        ExecStart = "${pkgs.connman}/sbin/connmand --nodaemon";
+        ExecStart = "${pkgs.connman}/sbin/connmand --config=${configFile} --nodaemon";
         StandardOutput = "null";
       };
     };
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 5308fd995085..66838735c4da 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -6,11 +6,9 @@ let
   dataDir = "/var/lib/consul";
   cfg = config.services.consul;
 
-  configOptions = {
-    data_dir = dataDir;
-  }
-  // (if cfg.webUi then { ui_dir = "${pkgs.consul.ui}"; } else { })
-  // cfg.extraConfig;
+  configOptions = { data_dir = dataDir; } //
+    (if cfg.webUi then { ui_dir = "${pkgs.consul.ui}"; } else { }) //
+    cfg.extraConfig;
 
   configFiles = [ "/etc/consul.json" "/etc/consul-addrs.json" ]
     ++ cfg.extraConfigFiles;
@@ -52,23 +50,6 @@ in
         '';
       };
 
-      joinNodes = mkOption {
-        type = types.listOf types.str;
-        default = [ ];
-        description = ''
-          A list of addresses of nodes which should be joined at startup if the
-          current node is in a left state.
-        '';
-      };
-
-      joinRetries = mkOption {
-        type = types.int;
-        default = 10;
-        description = ''
-          The number of times to retry connecting to the join nodes.
-        '';
-      };
-
       interface = {
 
         advertise = mkOption {
@@ -123,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.";
@@ -154,102 +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;
-    };
+      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;
-      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 ];
-
-      serviceConfig = {
-        ExecStart = "@${pkgs.consul}/bin/consul consul agent"
-          + 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
-      '';
-      postStart = ''
-        # Issues joins to nodes which we statically connect to
-        ${flip concatMapStrings cfg.joinNodes (addr: ''
-          for i in {0..${toString cfg.joinRetries}}; do
-            # Try to join the other nodes ${toString cfg.joinRetries} times before failing
-            consul join "${addr}" && break
-            sleep 1
-          done &
-        '')}
-        wait
-        exit 0
-      '';
-    };
-
-    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/copy-com.nix b/nixos/modules/services/networking/copy-com.nix
index 36bd29109b8a..69a41ab97963 100644
--- a/nixos/modules/services/networking/copy-com.nix
+++ b/nixos/modules/services/networking/copy-com.nix
@@ -1,53 +1,53 @@
-{ config, lib, pkgs, ... }:

-

-with lib;

-

-let

-  

-  cfg = config.services.copy-com;

-

-in 

-

-{

-  options = {

-

-    services.copy-com = {

-	  

-	  enable = mkOption {

-          default = false;

-          description = "

-            Enable the copy.com client.

-

-            The first time copy.com is run, it needs to be configured. Before enabling run 

-            copy_console manually.

-          ";

-      };

-

-      user = mkOption {

-        description = "The user for which copy should run.";

-      };

-

-      debug = mkOption {

-        default = false;

-        description = "Output more.";

-      };

-	  };

-  };

-

-  config = mkIf cfg.enable {

-    environment.systemPackages = [ pkgs.postfix ];

-

-    systemd.services."copy-com-${cfg.user}" = {

-      description = "Copy.com Client";

-      after = [ "network.target" "local-fs.target" ];

-      wantedBy = [ "multi-user.target" ];

-      serviceConfig = {

-        ExecStart = "${pkgs.copy-com}/bin/copy_console ${if cfg.debug then "-consoleOutput -debugToConsole=dirwatch,path-watch,csm_path,csm -debug -console" else ""}";

-        User = "${cfg.user}";

-      };

-

-    };

-  };

-

-}

-

+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.copy-com;
+
+in
+
+{
+  options = {
+
+    services.copy-com = {
+
+	  enable = mkOption {
+          default = false;
+          description = "
+            Enable the Copy.com client.
+            NOTE: before enabling the client for the first time, it must be
+            configured by first running CopyConsole (command line) or CopyAgent
+            (graphical) as the appropriate user.
+          ";
+      };
+
+      user = mkOption {
+        description = "The user for which the Copy.com client should be run.";
+      };
+
+      debug = mkOption {
+        default = false;
+        description = "Output more (debugging) messages to the console.";
+      };
+	  };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.postfix ];
+
+    systemd.services."copy-com-${cfg.user}" = {
+      description = "Copy.com client";
+      after = [ "network.target" "local-fs.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.copy-com}/bin/CopyConsole ${if cfg.debug then "-consoleOutput -debugToConsole=dirwatch,path-watch,csm_path,csm -debug -console" else ""}";
+        User = "${cfg.user}";
+      };
+
+    };
+  };
+
+}
+
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/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index 8552395fdb16..b31d479ab4fd 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -18,6 +18,7 @@ let
     map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ip4 != [ ] || i.ipAddress != null) interfaces)
     ++ mapAttrsToList (i: _: i) config.networking.sits
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
+    ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.vswitches))
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds))
     ++ config.networking.dhcpcd.denyInterfaces;
 
diff --git a/nixos/modules/services/networking/dnschain.nix b/nixos/modules/services/networking/dnschain.nix
new file mode 100644
index 000000000000..f17f8c832ee4
--- /dev/null
+++ b/nixos/modules/services/networking/dnschain.nix
@@ -0,0 +1,110 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services;
+
+  dnschainConf = pkgs.writeText "dnschain.conf" ''
+    [log]
+    level=info
+
+    [dns]
+    host = 127.0.0.1
+    port = 5333
+    oldDNSMethod = NO_OLD_DNS
+    # TODO: check what that address is acutally used for
+    externalIP = 127.0.0.1
+
+    [http]
+    host = 127.0.0.1
+    port=8088
+    tlsPort=4443
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.dnschain = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to run dnschain. That implies running
+          namecoind as well, so make sure to configure
+          it appropriately.
+        '';
+      };
+
+    };
+
+    services.dnsmasq = {
+      resolveDnschainQueries = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Resolve <literal>.bit</literal> top-level domains
+          with dnschain and namecoind.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.dnschain.enable {
+
+    services.namecoind.enable = true;
+
+    services.dnsmasq.servers = optionals cfg.dnsmasq.resolveDnschainQueries [ "/.bit/127.0.0.1#5333" ];
+
+    users.extraUsers = singleton
+      { name = "dnschain";
+        uid = config.ids.uids.dnschain;
+        extraGroups = [ "namecoin" ];
+        description = "Dnschain daemon user";
+        home = "/var/lib/dnschain";
+        createHome = true;
+      };
+
+    systemd.services.dnschain = {
+        description = "Dnschain Daemon";
+        after = [ "namecoind.target" ];
+        wantedBy = [ "multi-user.target" ];
+        path = [ pkgs.openssl ];
+        preStart = ''
+          # Link configuration file into dnschain HOME directory
+          if [ "$(${pkgs.coreutils}/bin/realpath /var/lib/dnschain/.dnschain.conf)" != "${dnschainConf}" ]; then
+              rm -rf /var/lib/dnschain/.dnschain.conf
+              ln -s ${dnschainConf} /var/lib/dnschain/.dnschain.conf
+          fi
+
+          # Create empty namecoin.conf so that dnschain is not
+          # searching for /etc/namecoin/namecoin.conf
+          if [ ! -e /var/lib/dnschain/.namecoin/namecoin.conf ]; then
+              mkdir -p /var/lib/dnschain/.namecoin
+              touch /var/lib/dnschain/.namecoin/namecoin.conf
+          fi
+        '';
+        serviceConfig = {
+          Type = "simple";
+          User = "dnschain";
+          EnvironmentFile = config.services.namecoind.userFile;
+          ExecStart = "${pkgs.dnschain}/bin/dnschain --rpcuser=\${USER} --rpcpassword=\${PASSWORD} --rpcport=8336";
+          ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+          ExecStop = "${pkgs.coreutils}/bin/kill -KILL $MAINPID";
+        };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index 1200ea291aaf..8acb2a1fc823 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,125 @@ 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).
         '';
       };
-
+      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.out}/lib/*.so mr,
+        ${pkgs.tzdata}/share/zoneinfo/** r,
 
-          ${pkgs.glibc.out}/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..6907d63d7611 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 = ''
@@ -96,8 +96,9 @@ in
           Type = "dbus";
           BusName = "uk.org.thekelleys.dnsmasq";
           ExecStart = "${dnsmasq}/bin/dnsmasq -k --enable-dbus --user=dnsmasq -C ${dnsmasqConf}";
-          ExecReload = "${dnsmasq}/bin/kill -HUP $MAINPID";
+          ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         };
+        restartTriggers = [ config.environment.etc.hosts.source ];
     };
 
   };
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/fan.nix b/nixos/modules/services/networking/fan.nix
new file mode 100644
index 000000000000..3170567e5b4a
--- /dev/null
+++ b/nixos/modules/services/networking/fan.nix
@@ -0,0 +1,60 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.networking.fan;
+  modprobe = "${config.system.sbin.modprobe}/sbin/modprobe";
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    networking.fan = {
+
+      enable = mkEnableOption "FAN Networking";
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.fanctl ];
+
+    systemd.services.fan = {
+      description = "FAN Networking";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      before = [ "docker.service" ];
+      restartIfChanged = false;
+      preStart = ''
+        if [ ! -f /proc/sys/net/fan/version ]; then
+          ${modprobe} ipip
+          if [ ! -f /proc/sys/net/fan/version ]; then
+            echo "The Fan Networking patches have not been applied to this kernel!" 1>&2
+            exit 1
+          fi
+        fi
+
+        mkdir -p /var/lib/fan-networking
+      '';
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        ExecStart = "${pkgs.fanctl}/bin/fanctl up -a";
+        ExecStop = "${pkgs.fanctl}/bin/fanctl down -a";
+      };
+    };
+
+  };
+
+}
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..a61f0250ef8b 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.
@@ -420,6 +420,16 @@ in
         '';
     };
 
+    networking.firewall.extraPackages = mkOption {
+      default = [ ];
+      example = [ pkgs.ipset ];
+      description =
+        ''
+          Additional packages to be included in the environment of the system
+          as well as the path of networking.firewall.extraCommands.
+        '';
+    };
+
     networking.firewall.extraStopCommands = mkOption {
       type = types.lines;
       default = "";
@@ -443,7 +453,7 @@ in
 
     networking.firewall.trustedInterfaces = [ "lo" ];
 
-    environment.systemPackages = [ pkgs.iptables pkgs.ipset ];
+    environment.systemPackages = [ pkgs.iptables ] ++ cfg.extraPackages;
 
     boot.kernelModules = map (x: "nf_conntrack_${x}") cfg.connectionTrackingModules;
     boot.extraModprobeConfig = optionalString (!cfg.autoLoadConntrackHelpers) ''
@@ -462,7 +472,7 @@ in
       before = [ "network-pre.target" ];
       after = [ "systemd-modules-load.service" ];
 
-      path = [ pkgs.iptables pkgs.ipset ];
+      path = [ pkgs.iptables ] ++ cfg.extraPackages;
 
       # FIXME: this module may also try to load kernel modules, but
       # containers don't have CAP_SYS_MODULE. So the host system had
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/gateone.nix b/nixos/modules/services/networking/gateone.nix
new file mode 100644
index 000000000000..93273837181e
--- /dev/null
+++ b/nixos/modules/services/networking/gateone.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ...}:
+with lib;
+let
+  cfg = config.services.gateone;
+in
+{
+options = {
+    services.gateone = {
+      enable = mkEnableOption "GateOne server";
+      pidDir = mkOption {
+        default = "/run/gateone";
+        type = types.path;
+        description = ''Path of pid files for GateOne.'';
+      };
+      settingsDir = mkOption {
+        default = "/var/lib/gateone";
+        type = types.path;
+        description = ''Path of configuration files for GateOne.'';
+      };
+    };
+};
+config = mkIf cfg.enable {
+  environment.systemPackages = with pkgs.pythonPackages; [
+    gateone pkgs.openssh pkgs.procps pkgs.coreutils ];
+
+  users.extraUsers.gateone = {
+    description = "GateOne privilege separation user";
+    uid = config.ids.uids.gateone;
+    home = cfg.settingsDir;
+  };
+  users.extraGroups.gateone.gid = config.ids.gids.gateone;
+
+  systemd.services.gateone = with pkgs; {
+    description = "GateOne web-based terminal";
+    path = [ pythonPackages.gateone nix openssh procps coreutils ];
+    preStart = ''
+      if [ ! -d ${cfg.settingsDir} ] ; then
+        mkdir -m 0750 -p ${cfg.settingsDir}
+        chown -R gateone.gateone ${cfg.settingsDir}
+      fi
+      if [ ! -d ${cfg.pidDir} ] ; then
+        mkdir -m 0750 -p ${cfg.pidDir}
+        chown -R gateone.gateone ${cfg.pidDir}
+      fi
+      '';
+    #unitConfig.RequiresMountsFor = "${cfg.settingsDir}";
+    serviceConfig = {
+      ExecStart = ''${pythonPackages.gateone}/bin/gateone --settings_dir=${cfg.settingsDir} --pid_file=${cfg.pidDir}/gateone.pid --gid=${toString config.ids.gids.gateone} --uid=${toString config.ids.uids.gateone}'';
+      User = "gateone";
+      Group = "gateone";
+      WorkingDirectory = cfg.settingsDir;
+      PermissionsStartOnly = true;
+
+    };
+
+    wantedBy = [ "multi-user.target" ];
+    requires = [ "network.target" ];
+  };
+};
+}
+  
diff --git a/nixos/modules/services/networking/heyefi.nix b/nixos/modules/services/networking/heyefi.nix
new file mode 100644
index 000000000000..fc2b5a848578
--- /dev/null
+++ b/nixos/modules/services/networking/heyefi.nix
@@ -0,0 +1,82 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.heyefi;
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.heyefi = {
+
+      enable = mkEnableOption "heyefi";
+
+      cardMacaddress = mkOption {
+        default = "";
+        description = ''
+          An Eye-Fi card MAC address.
+          '';
+      };
+
+      uploadKey = mkOption {
+        default = "";
+        description = ''
+          An Eye-Fi card's upload key.
+          '';
+      };
+
+      uploadDir = mkOption {
+        example = "/home/username/pictures";
+        description = ''
+          The directory to upload the files to.
+          '';
+      };
+
+      user = mkOption {
+        default = "root";
+        description = ''
+          heyefi will be run under this user (user must exist,
+          this can be your user name).
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.heyefi =
+      {
+        description = "heyefi service";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          User = "${cfg.user}";
+          Restart = "always";
+          ExecStart = "${pkgs.heyefi}/bin/heyefi";
+        };
+
+      };
+
+    environment.etc."heyefi/heyefi.config".text =
+      ''
+        # /etc/heyefi/heyefi.conf: DO NOT EDIT -- this file has been generated automatically.
+        cards = [["${config.services.heyefi.cardMacaddress}","${config.services.heyefi.uploadKey}"]]
+        upload_dir = "${toString config.services.heyefi.uploadDir}"
+      '';
+
+    environment.systemPackages = [ pkgs.heyefi ];
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/i2p.nix b/nixos/modules/services/networking/i2p.nix
index bad22c791388..e6ee5fd1f957 100644
--- a/nixos/modules/services/networking/i2p.nix
+++ b/nixos/modules/services/networking/i2p.nix
@@ -7,15 +7,7 @@ let
   homeDir = "/var/lib/i2p";
 in {
   ###### interface
-  options.services.i2p = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Enables i2p as a running service upon activation.
-        '';
-      };
-  };
+  options.services.i2p.enable = mkEnableOption "I2P router";
 
   ###### implementation
   config = mkIf cfg.enable {
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..7d70a3d05fa7 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 {
@@ -86,8 +86,7 @@ rec {
       wantedBy = [ "multi-user.target" ];
       environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted}/lib/python2.7/site-packages/:.";
       preStart = ''
-        if [ ! -d ${cfg.varPath}/ ] ; then 
-            mkdir -p ${cfg.pidPath}
+        if [ ! -d ${cfg.varPath}/ ] ; then
             mkdir -p ${cfg.logPath}/tty
             mkdir -p ${cfg.logPath}/dl
             mkdir -p ${cfg.varPath}/keys
@@ -97,12 +96,15 @@ rec {
             cp ${pkgs.kippo}/src/txtcmds ${cfg.varPath} -r
 
             chmod u+rw ${cfg.varPath} -R
-            chmod u+rw ${cfg.pidPath}
             chown kippo.kippo ${cfg.varPath} -R
-            chown kippo.kippo ${cfg.pidPath}
             chown kippo.kippo ${cfg.logPath} -R
             chmod u+rw ${cfg.logPath} -R
         fi
+        if [ ! -d ${cfg.pidPath}/ ] ; then
+            mkdir -p ${cfg.pidPath}
+            chmod u+rw ${cfg.pidPath}
+            chown kippo.kippo ${cfg.pidPath}
+        fi
       '';
 
       serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n";
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/namecoind.nix b/nixos/modules/services/networking/namecoind.nix
new file mode 100644
index 000000000000..83fc1ec66679
--- /dev/null
+++ b/nixos/modules/services/networking/namecoind.nix
@@ -0,0 +1,150 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.namecoind;
+
+  namecoinConf =
+  let
+    useSSL = (cfg.rpcCertificate != null) && (cfg.rpcKey != null);
+  in
+  pkgs.writeText "namecoin.conf" ''
+    server=1
+    daemon=0
+    rpcallowip=127.0.0.1
+    walletpath=${cfg.wallet}
+    gen=${if cfg.generate then "1" else "0"}
+    rpcssl=${if useSSL then "1" else "0"}
+    ${optionalString useSSL "rpcsslcertificatechainfile=${cfg.rpcCertificate}"}
+    ${optionalString useSSL "rpcsslprivatekeyfile=${cfg.rpcKey}"}
+    ${optionalString useSSL "rpcsslciphers=TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH"}
+    txindex=1
+    txprevcache=1
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.namecoind = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to run namecoind.
+        '';
+      };
+
+      wallet = mkOption {
+        type = types.path;
+        example = "/etc/namecoin/wallet.dat";
+        description = ''
+          Wallet file. The ownership of the file has to be
+          namecoin:namecoin, and the permissions must be 0640.
+        '';
+      };
+
+      userFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/etc/namecoin/user";
+        description = ''
+          File containing the user name and user password to
+          authenticate RPC connections to namecoind.
+          The content of the file is of the form:
+          <literal>
+          USER=namecoin
+          PASSWORD=secret
+          </literal>
+          The ownership of the file has to be namecoin:namecoin,
+          and the permissions must be 0640.
+        '';
+      };
+
+      generate = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to generate (mine) Namecoins.
+        '';
+      };
+
+      rpcCertificate = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/etc/namecoin/server.cert";
+        description = ''
+          Certificate file for securing RPC connections.
+        '';
+      };
+
+      rpcKey = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/etc/namecoin/server.pem";
+        description = ''
+          Key file for securing RPC connections.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton
+      { name = "namecoin";
+        uid = config.ids.uids.namecoin;
+        description = "Namecoin daemon user";
+        home = "/var/lib/namecoin";
+        createHome = true;
+      };
+
+    users.extraGroups = singleton
+      { name = "namecoin";
+        gid = config.ids.gids.namecoin;
+      };
+
+    systemd.services.namecoind = {
+        description = "Namecoind Daemon";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        preStart = ''
+          if [  "$(stat --printf '%u' ${cfg.userFile})" != "${toString config.ids.uids.namecoin}" \
+             -o "$(stat --printf '%g' ${cfg.userFile})" != "${toString config.ids.gids.namecoin}" \
+             -o "$(stat --printf '%a' ${cfg.userFile})" != "640" ]; then
+             echo "ERROR: bad ownership or rights on ${cfg.userFile}" >&2
+             exit 1
+          fi
+          if [  "$(stat --printf '%u' ${cfg.wallet})" != "${toString config.ids.uids.namecoin}" \
+             -o "$(stat --printf '%g' ${cfg.wallet})" != "${toString config.ids.gids.namecoin}" \
+             -o "$(stat --printf '%a' ${cfg.wallet})" != "640" ]; then
+             echo "ERROR: bad ownership or rights on ${cfg.wallet}" >&2
+             exit 1
+          fi
+        '';
+        serviceConfig = {
+          Type = "simple";
+          User = "namecoin";
+          EnvironmentFile = cfg.userFile;
+          ExecStart = "${pkgs.altcoins.namecoind}/bin/namecoind -conf=${namecoinConf} -rpcuser=\${USER} -rpcpassword=\${PASSWORD} -printtoconsole";
+          ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+          ExecStop = "${pkgs.coreutils}/bin/kill -KILL $MAINPID";
+          StandardOutput = "null";
+          Nice = "10";
+        };
+    };
+
+  };
+
+}
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
new file mode 100644
index 000000000000..4f8b9357a828
--- /dev/null
+++ b/nixos/modules/services/networking/nix-serve.nix
@@ -0,0 +1,70 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.nix-serve;
+in
+{
+  options = {
+    services.nix-serve = {
+      enable = mkEnableOption "nix-serve, the standalone Nix binary cache server";
+
+      port = mkOption {
+        type = types.int;
+        default = 5000;
+        description = ''
+          Port number where nix-serve will listen on.
+        '';
+      };
+
+      bindAddress = mkOption {
+        type = types.string;
+        default = "0.0.0.0";
+        description = ''
+          IP address where nix-serve will bind its listening socket.
+        '';
+      };
+
+      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 = "";
+        description = ''
+          Extra command line parameters for nix-serve.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.nix-serve = {
+      description = "nix-serve binary cache server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      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 = "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/ntpd.nix b/nixos/modules/services/networking/ntpd.nix
index a9183577d0a2..5256fc9bc071 100644
--- a/nixos/modules/services/networking/ntpd.nix
+++ b/nixos/modules/services/networking/ntpd.nix
@@ -6,6 +6,8 @@ let
 
   inherit (pkgs) ntp;
 
+  cfg = config.services.ntp;
+
   stateDir = "/var/lib/ntp";
 
   ntpUser = "ntp";
@@ -16,10 +18,10 @@ let
     restrict 127.0.0.1
     restrict -6 ::1
 
-    ${toString (map (server: "server " + server + " iburst\n") config.services.ntp.servers)}
+    ${toString (map (server: "server " + server + " iburst\n") cfg.servers)}
   '';
 
-  ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup";
+  ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup ${toString cfg.extraFlags}";
 
 in
 
@@ -51,6 +53,12 @@ in
         '';
       };
 
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        description = "Extra flags passed to the ntpd command.";
+        default = [];
+      };
+
     };
 
   };
diff --git a/nixos/modules/services/networking/oidentd.nix b/nixos/modules/services/networking/oidentd.nix
index 923e7cd0986e..738ab8313a5d 100644
--- a/nixos/modules/services/networking/oidentd.nix
+++ b/nixos/modules/services/networking/oidentd.nix
@@ -28,7 +28,9 @@ with lib;
     jobs.oidentd =
       { startOn = "started network-interfaces";
         daemonType = "fork";
-        exec = "${pkgs.oidentd}/sbin/oidentd -u oidentd -g nogroup";
+        exec = "${pkgs.oidentd}/sbin/oidentd -u oidentd -g nogroup" +
+          optionalString config.networking.enableIPv6 " -a ::"
+        ;
       };
 
     users.extraUsers.oidentd = {
diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix
index 9dc88e61865d..a96888dec864 100644
--- a/nixos/modules/services/networking/openvpn.nix
+++ b/nixos/modules/services/networking/openvpn.nix
@@ -67,12 +67,6 @@ in
 
   options = {
 
-    /* !!! Obsolete. */
-    services.openvpn.enable = mkOption {
-      default = true;
-      description = "Whether to enable OpenVPN.";
-    };
-
     services.openvpn.servers = mkOption {
       default = {};
 
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/quassel.nix b/nixos/modules/services/networking/quassel.nix
index 579d62884c78..005eb7bd7614 100644
--- a/nixos/modules/services/networking/quassel.nix
+++ b/nixos/modules/services/networking/quassel.nix
@@ -3,7 +3,7 @@
 with lib;
 
 let
-  quassel = pkgs.kde4.quasselDaemon;
+  quassel = pkgs.quasselDaemon_qt5;
   cfg = config.services.quassel;
   user = if cfg.user != null then cfg.user else "quassel";
 in
diff --git a/nixos/modules/services/networking/racoon.nix b/nixos/modules/services/networking/racoon.nix
new file mode 100644
index 000000000000..86e13d1ea0d6
--- /dev/null
+++ b/nixos/modules/services/networking/racoon.nix
@@ -0,0 +1,45 @@
+{ 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
+        mkdir -p /var/racoon
+      '';
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/sabnzbd.nix b/nixos/modules/services/networking/sabnzbd.nix
index 77bf64b80d0f..cacf753fdcd7 100644
--- a/nixos/modules/services/networking/sabnzbd.nix
+++ b/nixos/modules/services/networking/sabnzbd.nix
@@ -17,11 +17,21 @@ in
     services.sabnzbd = {
       enable = mkOption {
         default = false;
-        description = "Whether to enable the sabnzbd FTP server.";
+        description = "Whether to enable the sabnzbd server.";
       };
       configFile = mkOption {
-        default = "/var/sabnzbd/sabnzbd.ini";
-        description = "Path to config file. (You need to create this file yourself!)";
+        default = "/var/lib/sabnzbd/sabnzbd.ini";
+        description = "Path to config file.";
+      };
+
+      user = mkOption {
+        default = "sabnzbd";
+        description = "User to run the service as";
+      };
+
+      group = mkOption {
+        default = "sabnzbd";
+        description = "Group to run the service as";
       };
     };
   };
@@ -31,23 +41,29 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers =
-      [ { name = "sabnzbd";
+    users.extraUsers.sabnzbd = {
           uid = config.ids.uids.sabnzbd;
+          group = "sabnzbd";
           description = "sabnzbd user";
-          home = "/homeless-shelter";
-        }
-      ];
+          home = "/var/lib/sabnzbd/";
+          createHome = true;
+    };
 
-    systemd.services.sabnzbd =
-      { description = "sabnzbd server";
+    users.extraGroups.sabnzbd = {
+      gid = config.ids.gids.sabnzbd;
+    };
+
+    systemd.services.sabnzbd = {
+        description = "sabnzbd server";
         wantedBy    = [ "multi-user.target" ];
         after = [ "network.target" ];
         serviceConfig = {
           Type = "forking";
+          GuessMainPID = "no";
+          User = "${cfg.user}";
+          Group = "${cfg.group}";
           ExecStart = "${sabnzbd}/bin/sabnzbd -d -f ${cfg.configFile}";
         };
-      };
-
+    };
   };
 }
diff --git a/nixos/modules/services/networking/seeks.nix b/nixos/modules/services/networking/seeks.nix
index 155ecbb98ef3..f5bc60be3457 100644
--- a/nixos/modules/services/networking/seeks.nix
+++ b/nixos/modules/services/networking/seeks.nix
@@ -33,7 +33,7 @@ in
         type = types.str;
         description = "
           The Seeks server configuration. If it is not specified,
-          a default configuration is used (${seeks}/etc/seeks).
+          a default configuration is used.
         ";
       };
 
diff --git a/nixos/modules/services/networking/shout.nix b/nixos/modules/services/networking/shout.nix
new file mode 100644
index 000000000000..f55b87a96140
--- /dev/null
+++ b/nixos/modules/services/networking/shout.nix
@@ -0,0 +1,80 @@
+{ pkgs, lib, config, options, ... }:
+
+with lib;
+
+let
+  cfg = config.services.shout;
+  shoutHome = "/var/lib/shout";
+
+in {
+  options.services.shout = {
+    enable = mkEnableOption "Shout web IRC client";
+
+    private = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Make your shout instance private. You will need to configure user
+        accounts by adding entries in <filename>${shoutHome}/users</filename>.
+      '';
+    };
+
+    host = mkOption {
+      type = types.string;
+      default = "0.0.0.0";
+      description = "IP interface to listen on for http connections.";
+    };
+
+    port = mkOption {
+      type = types.int;
+      default = 9000;
+      description = "TCP port to listen on for http connections.";
+    };
+
+    configFile = mkOption {
+      type = types.nullOr types.lines;
+      default = null;
+      description = ''
+        Contents of Shout's <filename>config.js</filename> file. If left empty,
+        Shout will generate from its defaults at first startup.
+
+        Documentation: http://shout-irc.com/docs/server/configuration.html
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers = singleton {
+      name = "shout";
+      uid = config.ids.uids.shout;
+      description = "Shout daemon user";
+      home = shoutHome;
+      createHome = true;
+    };
+
+    systemd.services.shout = {
+      description = "Shout web IRC client";
+      wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
+      after = [ "network-online.target" ];
+      preStart = if isNull cfg.configFile then null
+                 else ''
+                   ln -sf ${pkgs.writeText "config.js" cfg.configFile} \
+                          ${shoutHome}/config.js
+                 '';
+      script = concatStringsSep " " [
+        "${pkgs.shout}/bin/shout"
+        (if cfg.private then "--private" else "--public")
+        "--port" (toString cfg.port)
+        "--host" (toString cfg.host)
+        "--home" shoutHome
+      ];
+      serviceConfig = {
+        User = "shout";
+        ProtectHome = "true";
+        ProtectSystem = "full";
+        PrivateTmp = "true";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
new file mode 100644
index 000000000000..f5eb452fec62
--- /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_NAMESERVERS = concatStringsSep "," cfg.nameservers;
+      };
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/skydns";
+      };
+    };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixos/modules/services/networking/softether.nix b/nixos/modules/services/networking/softether.nix
new file mode 100644
index 000000000000..49538af7d351
--- /dev/null
+++ b/nixos/modules/services/networking/softether.nix
@@ -0,0 +1,150 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  pkg = pkgs.softether;
+  cfg = config.services.softether;
+
+in
+{
+
+  ###### interface
+
+  options = {
+
+    services.softether = {
+
+      enable = mkEnableOption "SoftEther VPN services";
+
+      vpnserver.enable = mkEnableOption "SoftEther VPN Server";
+
+      vpnbridge.enable = mkEnableOption "SoftEther VPN Bridge";
+
+      vpnclient = {
+        enable = mkEnableOption "SoftEther VPN Client";
+        up = mkOption {
+          type = types.lines;
+          default = "";
+          description = ''
+            Shell commands executed when the Virtual Network Adapter(s) is/are starting.
+          '';
+        };
+        down = mkOption {
+          type = types.lines;
+          default = "";
+          description = ''
+            Shell commands executed when the Virtual Network Adapter(s) is/are shutting down.
+          '';
+        };
+      };
+
+      dataDir = mkOption {
+        type = types.string;
+        default = "${pkg.dataDir}";
+        description = ''
+          Data directory for SoftEther VPN.
+        '';
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable (
+
+    mkMerge [{
+      environment.systemPackages = [
+          (pkgs.lib.overrideDerivation pkg (attrs: {
+            dataDir = cfg.dataDir;
+          }))
+        ];
+      jobs.softether = {
+        description = "SoftEther VPN services initial job";
+        startOn = "started network-interfaces";
+        preStart = ''
+            for d in vpnserver vpnbridge vpnclient vpncmd; do
+                if ! test -e ${cfg.dataDir}/$d; then
+                    ${pkgs.coreutils}/bin/mkdir -m0700 -p ${cfg.dataDir}/$d
+                    install -m0600 ${pkg}${cfg.dataDir}/$d/hamcore.se2 ${cfg.dataDir}/$d/hamcore.se2
+                fi
+            done
+            rm -rf ${cfg.dataDir}/vpncmd/vpncmd
+            ln -s ${pkg}${cfg.dataDir}/vpncmd/vpncmd ${cfg.dataDir}/vpncmd/vpncmd
+        '';
+        exec = "true";
+      };
+    }
+
+    (mkIf (cfg.vpnserver.enable) {
+      systemd.services.vpnserver = {
+        description = "SoftEther VPN Server";
+        after = [ "network-interfaces.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          ExecStart = "${pkg}/bin/vpnserver start";
+          ExecStop = "${pkg}/bin/vpnserver stop";
+          Type = "forking";
+        };
+        preStart = ''
+            rm -rf ${cfg.dataDir}/vpnserver/vpnserver
+            ln -s ${pkg}${cfg.dataDir}/vpnserver/vpnserver ${cfg.dataDir}/vpnserver/vpnserver
+        '';
+        postStop = ''
+            rm -rf ${cfg.dataDir}/vpnserver/vpnserver
+        '';
+      };
+    })
+
+    (mkIf (cfg.vpnbridge.enable) {
+      systemd.services.vpnbridge = {
+        description = "SoftEther VPN Bridge";
+        after = [ "network-interfaces.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          ExecStart = "${pkg}/bin/vpnbridge start";
+          ExecStop = "${pkg}/bin/vpnbridge stop";
+          Type = "forking";
+        };
+        preStart = ''
+            rm -rf ${cfg.dataDir}/vpnbridge/vpnbridge
+            ln -s ${pkg}${cfg.dataDir}/vpnbridge/vpnbridge ${cfg.dataDir}/vpnbridge/vpnbridge
+        '';
+        postStop = ''
+            rm -rf ${cfg.dataDir}/vpnbridge/vpnbridge
+        '';
+      };
+    })
+
+    (mkIf (cfg.vpnclient.enable) {
+      systemd.services.vpnclient = {
+        description = "SoftEther VPN Client";
+        after = [ "network-interfaces.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          ExecStart = "${pkg}/bin/vpnclient start";
+          ExecStop = "${pkg}/bin/vpnclient stop";
+          Type = "forking";
+        };
+        preStart = ''
+            rm -rf ${cfg.dataDir}/vpnclient/vpnclient
+            ln -s ${pkg}${cfg.dataDir}/vpnclient/vpnclient ${cfg.dataDir}/vpnclient/vpnclient
+        '';
+        postStart = ''
+            sleep 1
+            ${cfg.vpnclient.up}
+        '';
+        postStop = ''
+            rm -rf ${cfg.dataDir}/vpnclient/vpnclient
+            sleep 1
+            ${cfg.vpnclient.down}
+        '';
+      };
+      boot.kernelModules = [ "tun" ];
+    })
+
+  ]);
+
+}
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index c25532511a07..5baea4bc6aea 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -9,14 +9,6 @@ let
 
   nssModulesPath = config.system.nssModules.path;
 
-  knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts);
-
-  knownHostsText = flip (concatMapStringsSep "\n") knownHosts
-    (h:
-      concatStringsSep "," h.hostNames + " "
-      + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile)
-    );
-
   userOptions = {
 
     openssh.authorizedKeys = {
@@ -48,8 +40,7 @@ let
   };
 
   authKeysFiles = let
-    mkAuthKeyFile = u: {
-      target = "ssh/authorized_keys.d/${u.name}";
+    mkAuthKeyFile = u: nameValuePair "ssh/authorized_keys.d/${u.name}" {
       mode = "0444";
       source = pkgs.writeText "${u.name}-authorized_keys" ''
         ${concatStringsSep "\n" u.openssh.authorizedKeys.keys}
@@ -59,7 +50,7 @@ let
     usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u:
       length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0
     ));
-  in map mkAuthKeyFile usersWithKeys;
+  in listToAttrs (map mkAuthKeyFile usersWithKeys);
 
 in
 
@@ -184,16 +175,11 @@ in
       hostKeys = mkOption {
         type = types.listOf types.attrs;
         default =
-          [ { path = "/etc/ssh/ssh_host_dsa_key";
-              type = "dsa";
-            }
-            { path = "/etc/ssh/ssh_host_ecdsa_key";
-              type = "ecdsa";
-              bits = 521;
-            }
-            { path = "/etc/ssh/ssh_host_ed25519_key";
-              type = "ed25519";
-            }
+          [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
+            { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
+          ] ++ optionals (!versionAtLeast config.system.stateVersion "15.07")
+          [ { type = "dsa"; path = "/etc/ssh/ssh_host_dsa_key"; }
+            { type = "ecdsa"; bits = 521; path = "/etc/ssh/ssh_host_ecdsa_key"; }
           ];
         description = ''
           NixOS can automatically generate SSH host keys.  This option
@@ -216,61 +202,19 @@ in
         description = "Verbatim contents of <filename>sshd_config</filename>.";
       };
 
-      knownHosts = mkOption {
-        default = {};
-        type = types.loaOf types.optionSet;
+      moduliFile = mkOption {
+        example = "services.openssh.moduliFile = /etc/my-local-ssh-moduli;";
+        type = types.path;
         description = ''
-          The set of system-wide known SSH hosts.
+          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.
         '';
-        example = [
-          {
-            hostNames = [ "myhost" "myhost.mydomain.com" "10.10.1.4" ];
-            publicKeyFile = literalExample "./pubkeys/myhost_ssh_host_dsa_key.pub";
-          }
-          {
-            hostNames = [ "myhost2" ];
-            publicKeyFile = literalExample "./pubkeys/myhost2_ssh_host_dsa_key.pub";
-          }
-        ];
-        options = {
-          hostNames = mkOption {
-            type = types.listOf types.string;
-            default = [];
-            description = ''
-              A list of host names and/or IP numbers used for accessing
-              the host's ssh service.
-            '';
-          };
-          publicKey = mkOption {
-            default = null;
-            type = types.nullOr types.str;
-            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.
-            '';
-          };
-          publicKeyFile = mkOption {
-            default = null;
-            type = types.nullOr types.path;
-            description = ''
-              The path to the public key file for the host. The public
-              key file is read at build time and saved in the Nix store.
-              You can fetch a public key file from a running SSH server
-              with the <command>ssh-keyscan</command> command. The content
-              of the file should follow the same format as described for
-              the <literal>publicKey</literal> option.
-            '';
-          };
-        };
       };
 
     };
 
-    users.extraUsers = mkOption {
+    users.users = mkOption {
       options = [ userOptions ];
     };
 
@@ -282,18 +226,14 @@ in
   config = mkIf cfg.enable {
 
     users.extraUsers.sshd =
-      { description = "SSH privilege separation user";
-        home = "/var/empty";
+      { isSystemUser = true;
+        description = "SSH privilege separation user";
       };
 
-    environment.etc = authKeysFiles ++ [
-      { source = "${cfgc.package}/etc/ssh/moduli";
-        target = "ssh/moduli";
-      }
-      { text = knownHostsText;
-        target = "ssh/ssh_known_hosts";
-      }
-    ];
+    services.openssh.moduliFile = mkDefault "${cfgc.package}/etc/ssh/moduli";
+
+    environment.etc = authKeysFiles //
+      { "ssh/moduli".source = cfg.moduliFile; };
 
     systemd =
       let
@@ -411,11 +351,6 @@ in
 
     assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
                     message = "cannot enable X11 forwarding without setting xauth location";}]
-      ++ flip mapAttrsToList cfg.knownHosts (name: data: {
-        assertion = (data.publicKey == null && data.publicKeyFile != null) ||
-                    (data.publicKey != null && data.publicKeyFile == null);
-        message = "knownHost ${name} must contain either a publicKey or publicKeyFile";
-      })
       ++ flip map cfg.listenAddresses ({ addr, port, ... }: {
         assertion = addr != null;
         message = "addr must be specified in each listenAddresses entry";
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index 02572c1e27d2..4eb32b1cf306 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -36,9 +36,7 @@ in
       dataDir = mkOption {
         default = "/var/lib/syncthing";
         description = ''
-          Path where the `.syncthing` (settings and keys) and `Sync`
-          (your synced files) directories will exist. This can be your home
-          directory.
+          Path where the settings and keys will exist.
         '';
       };
 
@@ -56,19 +54,16 @@ in
         description = "Syncthing service";
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
-        environment.STNORESTART = "placeholder";  # do not self-restart
-        environment.HOME = "${cfg.dataDir}";
+        environment.STNORESTART = "yes";  # do not self-restart
+        environment.STNOUPGRADE = "yes";
         serviceConfig = {
           User = "${cfg.user}";
           PermissionsStartOnly = true;
-          Restart = "always";
-          ExecStart = "${pkgs.syncthing}/bin/syncthing -home=${cfg.dataDir}/.syncthing";
+          Restart = "on-failure";
+          ExecStart = "${pkgs.syncthing}/bin/syncthing -no-browser -home=${cfg.dataDir}";
+          SuccessExitStatus = "2 3 4";
+          RestartForceExitStatus="3 4";
         };
-        preStart = ''
-          mkdir -p ${cfg.dataDir}
-          chown ${cfg.user} ${cfg.dataDir}
-        '';
-
       };
 
     environment.systemPackages = [ pkgs.syncthing ];
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index f9ca796ea652..2d43c3d962dd 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -154,6 +154,7 @@ in
     users.extraUsers = flip mapAttrs' cfg.networks (network: _:
       nameValuePair ("tinc.${network}") ({
         description = "Tinc daemon user for ${network}";
+        isSystemUser = true;
       })
     );
 
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/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index b573a356b351..69c76cf97cfd 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -72,6 +72,30 @@ in
         '';
       };
 
+      defaultShared = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Specifies whether local printers are shared by default.
+        '';
+      };
+
+      browsing = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Specifies whether shared printers are advertised.
+        '';
+      };
+
+      webInterface = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Specifies whether the web interface is enabled.
+        '';
+      };
+
       cupsdConf = mkOption {
         type = types.lines;
         default = "";
@@ -136,6 +160,17 @@ in
         '';
       };
 
+      snmpConf = mkOption {
+        type = types.lines;
+        default = ''
+          Address @LOCAL
+        '';
+        description = ''
+          The contents of <filename>/etc/cups/snmp.conf</filename>. See "man
+          cups-snmp.conf" for a complete description.
+        '';
+      };
+
       drivers = mkOption {
         type = types.listOf types.path;
         example = literalExample "[ pkgs.splix ]";
@@ -175,6 +210,7 @@ in
     environment.etc."cups/cups-files.conf".text = cfg.cupsFilesConf;
     environment.etc."cups/cupsd.conf".text = cfg.cupsdConf;
     environment.etc."cups/cups-browsed.conf".text = cfg.browsedConf;
+    environment.etc."cups/snmp.conf".text = cfg.snmpConf;
 
     services.dbus.packages = [ cups ];
 
@@ -183,10 +219,10 @@ in
     # gets loaded, and then cups cannot access the printers.
     boot.blacklistedKernelModules = [ "usblp" ];
 
-    systemd.services.cups =
-      { description = "CUPS Printing Daemon";
+    systemd.packages = [ cups ];
 
-        wantedBy = [ "multi-user.target" ];
+    systemd.services.cups =
+      { wantedBy = [ "multi-user.target" ];
         wants = [ "network.target" ];
         after = [ "network.target" ];
 
@@ -200,17 +236,14 @@ in
             mkdir -m 0755 -p ${cfg.tempDir}
           '';
 
-        serviceConfig.Type = "forking";
-        serviceConfig.ExecStart = "@${cups}/sbin/cupsd cupsd";
-
         restartTriggers =
           [ config.environment.etc."cups/cups-files.conf".source
             config.environment.etc."cups/cupsd.conf".source
           ];
       };
 
-    systemd.services.cups-browsed =
-      { description = "Make remote CUPS printers available locally";
+    systemd.services.cups-browsed = mkIf config.services.avahi.enable
+      { description = "CUPS Remote Printer Discovery";
 
         wantedBy = [ "multi-user.target" ];
         wants = [ "cups.service" "avahi-daemon.service" ];
@@ -262,9 +295,11 @@ in
 
         SetEnv PATH ${bindir}/lib/cups/filter:${bindir}/bin:${bindir}/sbin
 
-        Browsing On
-        BrowseOrder allow,deny
-        BrowseAllow @LOCAL
+        DefaultShared ${if cfg.defaultShared then "Yes" else "No"}
+
+        Browsing ${if cfg.browsing then "Yes" else "No"}
+
+        WebInterface ${if cfg.webInterface then "Yes" else "No"}
 
         DefaultAuthType Basic
 
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/cron.nix b/nixos/modules/services/scheduling/cron.nix
index 1f42086dc1ec..02d80a77da50 100644
--- a/nixos/modules/services/scheduling/cron.nix
+++ b/nixos/modules/services/scheduling/cron.nix
@@ -4,8 +4,6 @@ with lib;
 
 let
 
-  inherit (config.services) jobsTags;
-
   # Put all the system cronjobs together.
   systemCronJobsFile = pkgs.writeText "system-crontab"
     ''
@@ -25,9 +23,9 @@ let
     sendmailPath = "/var/setuid-wrappers/sendmail";
   };
 
-  allFiles = map (f: "\"${f}\"") (
-    [ "${systemCronJobsFile}" ] ++ config.services.cron.cronFiles
-  );
+  allFiles =
+    optional (config.services.cron.systemCronJobs != []) systemCronJobsFile
+    ++ config.services.cron.cronFiles;
 
 in
 
@@ -91,36 +89,49 @@ in
 
   ###### implementation
 
-  config = mkIf (config.services.cron.enable && allFiles != []) {
+  config = mkMerge [
 
-    security.setuidPrograms = [ "crontab" ];
+    { services.cron.enable = mkDefault (allFiles != []); }
 
-    environment.systemPackages = [ cronNixosPkg ];
+    (mkIf (config.services.cron.enable) {
 
-    systemd.services.cron =
-      { description = "Cron Daemon";
+      security.setuidPrograms = [ "crontab" ];
 
-        wantedBy = [ "multi-user.target" ];
+      environment.systemPackages = [ cronNixosPkg ];
 
-        preStart =
-          ''
-            rm -f /etc/crontab
-            cat ${toString allFiles} > /etc/crontab
-            chmod 0600 /etc/crontab
+      environment.etc.crontab =
+        { source = pkgs.runCommand "crontabs" { inherit allFiles; }
+            ''
+              touch $out
+              for i in $allFiles; do
+                cat "$i" >> $out
+              done
+            '';
+          mode = "0600"; # Cron requires this.
+        };
 
-            mkdir -m 710 -p /var/cron
+      systemd.services.cron =
+        { description = "Cron Daemon";
 
-            # By default, allow all users to create a crontab.  This
-            # is denoted by the existence of an empty cron.deny file.
-            if ! test -e /var/cron/cron.allow -o -e /var/cron/cron.deny; then
-                touch /var/cron/cron.deny
-            fi
-          '';
+          wantedBy = [ "multi-user.target" ];
 
-        restartTriggers = [ config.environment.etc.localtime.source ];
-        serviceConfig.ExecStart = "${cronNixosPkg}/bin/cron -n";
-      };
+          preStart =
+            ''
+              mkdir -m 710 -p /var/cron
 
-  };
+              # By default, allow all users to create a crontab.  This
+              # is denoted by the existence of an empty cron.deny file.
+              if ! test -e /var/cron/cron.allow -o -e /var/cron/cron.deny; then
+                  touch /var/cron/cron.deny
+              fi
+            '';
+
+          restartTriggers = [ config.environment.etc.localtime.source ];
+          serviceConfig.ExecStart = "${cronNixosPkg}/bin/cron -n";
+        };
+
+    })
+
+  ];
 
 }
diff --git a/nixos/modules/services/scheduling/marathon.nix b/nixos/modules/services/scheduling/marathon.nix
index 8513d1174c38..4e837c62dc11 100644
--- a/nixos/modules/services/scheduling/marathon.nix
+++ b/nixos/modules/services/scheduling/marathon.nix
@@ -12,27 +12,67 @@ in {
 
   options.services.marathon = {
     enable = mkOption {
-      description = "Whether to enable the marathon mesos framework.";
+      type = types.bool;
       default = false;
-      type = types.uniq types.bool;
-    };
-
-    httpPort = mkOption {
-      description = "Marathon listening port";
-      default = 8080;
-      type = types.int;
+      description = ''
+	Whether to enable the marathon mesos framework.
+      '';
     };
 
     master = mkOption {
-      description = "Marathon mesos master zookeeper address";
-      default = "zk://${head cfg.zookeeperHosts}/mesos";
       type = types.str;
+      default = "zk://${concatStringsSep "," cfg.zookeeperHosts}/mesos";
+      example = "zk://1.2.3.4:2181,2.3.4.5:2181,3.4.5.6:2181/mesos";
+      description = ''
+	Mesos master address. See <link xlink:href="https://mesosphere.github.io/marathon/docs/"/> for details.
+      '';
     };
 
     zookeeperHosts = mkOption {
-      description = "Marathon mesos zookepper addresses";
+      type = types.listOf types.str;
       default = [ "localhost:2181" ];
+      example = [ "1.2.3.4:2181" "2.3.4.5:2181" "3.4.5.6:2181" ];
+      description = ''
+	ZooKeeper hosts' addresses.
+      '';
+    };
+
+    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 = [ ];
+      example = [ "--https_port=8443" "--zk_timeout=10000" "--marathon_store_timeout=2000" ];
+      description = ''
+	Extra command line options to pass to Marathon.
+	See <link xlink:href="https://mesosphere.github.io/marathon/docs/command-line-flags.html"/> for all possible flags.
+      '';
+    };
+
+    environment = mkOption {
+      default = { };
+      type = types.attrs;
+      example = { JAVA_OPTS = "-Xmx512m"; MESOSPHERE_HTTP_CREDENTIALS = "username:password"; };
+      description = ''
+	Environment variables passed to Marathon.
+      '';
     };
   };
 
@@ -41,18 +81,18 @@ in {
   config = mkIf cfg.enable {
     systemd.services.marathon = {
       description = "Marathon Service";
+      environment = cfg.environment;
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" "zookeeper.service" "mesos-master.service" "mesos-slave.service" ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.marathon}/bin/marathon --master ${cfg.master} --zk zk://${head cfg.zookeeperHosts}/marathon";
-        User = "marathon";
+        ExecStart = "${pkgs.marathon}/bin/marathon --master ${cfg.master} --zk zk://${concatStringsSep "," cfg.zookeeperHosts}/marathon --http_port ${toString cfg.httpPort} ${concatStringsSep " " cfg.extraCmdLineOptions}";
+        User = cfg.user;
+        Restart = "always";
+        RestartSec = "2";
       };
     };
 
-    users.extraUsers.marathon = {
-      uid = config.ids.uids.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..3436bd01d848 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -34,7 +34,13 @@ in {
     enable = mkOption {
       description = "Whether to enable elasticsearch.";
       default = false;
-      type = types.uniq types.bool;
+      type = types.bool;
+    };
+
+    package = mkOption {
+      description = "Elasticsearch package to use.";
+      default = pkgs.elasticsearch;
+      type = types.package;
     };
 
     host = mkOption {
@@ -102,7 +108,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" ];
     };
 
@@ -123,7 +129,7 @@ in {
       after = [ "network-interfaces.target" ];
       environment = { ES_HOME = cfg.dataDir; };
       serviceConfig = {
-        ExecStart = "${pkgs.elasticsearch}/bin/elasticsearch -Des.path.conf=${configDir} ${toString cfg.extraCmdLineOptions}";
+        ExecStart = "${cfg.package}/bin/elasticsearch -Des.path.conf=${configDir} ${toString cfg.extraCmdLineOptions}";
         User = "elasticsearch";
         PermissionsStartOnly = true;
       };
@@ -142,7 +148,7 @@ in {
       '';
     };
 
-    environment.systemPackages = [ pkgs.elasticsearch ];
+    environment.systemPackages = [ cfg.package ];
 
     users.extraUsers = singleton {
       name = "elasticsearch";
diff --git a/nixos/modules/services/search/kibana.nix b/nixos/modules/services/search/kibana.nix
new file mode 100644
index 000000000000..f47ab8f55861
--- /dev/null
+++ b/nixos/modules/services/search/kibana.nix
@@ -0,0 +1,168 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.kibana;
+
+  cfgFile = pkgs.writeText "kibana.json" (builtins.toJSON (
+    (filterAttrsRecursive (n: v: v != null) ({
+      server = {
+        host = cfg.host;
+        port = cfg.port;
+        ssl = {
+          cert = cfg.cert;
+          key = cfg.key;
+        };
+      };
+
+      kibana = {
+        index = cfg.index;
+        defaultAppId = cfg.defaultAppId;
+      };
+
+      elasticsearch = {
+        url = cfg.elasticsearch.url;
+        username = cfg.elasticsearch.username;
+        password = cfg.elasticsearch.password;
+        ssl = {
+          cert = cfg.elasticsearch.cert;
+          key = cfg.elasticsearch.key;
+          ca = cfg.elasticsearch.ca;
+        };
+      };
+
+      logging = {
+        verbose = cfg.logLevel == "verbose";
+        quiet = cfg.logLevel == "quiet";
+        silent = cfg.logLevel == "silent";
+        dest = "stdout";
+      };
+    } // cfg.extraConf)
+  )));
+in {
+  options.services.kibana = {
+    enable = mkEnableOption "enable kibana service";
+
+    host = mkOption {
+      description = "Kibana listening host";
+      default = "127.0.0.1";
+      type = types.str;
+    };
+
+    port = mkOption {
+      description = "Kibana listening port";
+      default = 5601;
+      type = types.int;
+    };
+
+    cert = mkOption {
+      description = "Kibana ssl certificate.";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    key = mkOption {
+      description = "Kibana ssl key.";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    index = mkOption {
+      description = "Elasticsearch index to use for saving kibana config.";
+      default = ".kibana";
+      type = types.str;
+    };
+
+    defaultAppId = mkOption {
+      description = "Elasticsearch default application id.";
+      default = "discover";
+      type = types.str;
+    };
+
+    elasticsearch = {
+      url = mkOption {
+        description = "Elasticsearch url";
+        default = "http://localhost:9200";
+        type = types.str;
+      };
+
+      username = mkOption {
+        description = "Username for elasticsearch basic auth.";
+        default = null;
+        type = types.nullOr types.str;
+      };
+
+      password = mkOption {
+        description = "Password for elasticsearch basic auth.";
+        default = null;
+        type = types.nullOr types.str;
+      };
+
+      ca = mkOption {
+        description = "CA file to auth against elasticsearch.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      cert = mkOption {
+        description = "Certificate file to auth against elasticsearch.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      key = mkOption {
+        description = "Key file to auth against elasticsearch.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+    };
+
+    logLevel = mkOption {
+      description = "Kibana log level";
+      default = "normal";
+      type = types.enum ["verbose" "normal" "silent" "quiet"];
+    };
+
+    package = mkOption {
+      description = "Kibana package to use";
+      default = pkgs.kibana;
+      type = types.package;
+    };
+
+    dataDir = mkOption {
+      description = "Kibana data directory";
+      default = "/var/lib/kibana";
+      type = types.path;
+    };
+
+    extraConf = mkOption {
+      description = "Kibana extra configuration";
+      default = {};
+      type = types.attrs;
+    };
+  };
+
+  config = mkIf (cfg.enable) {
+    systemd.services.kibana = {
+      description = "Kibana Service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-interfaces.target" "elasticsearch.service" ];
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/kibana --config ${cfgFile}";
+        User = "kibana";
+        WorkingDirectory = cfg.dataDir;
+      };
+    };
+
+    environment.systemPackages = [ cfg.package ];
+
+    users.extraUsers = singleton {
+      name = "kibana";
+      uid = config.ids.uids.kibana;
+      description = "Kibana service user";
+      home = cfg.dataDir;
+      createHome = true;
+    };
+  };
+}
diff --git a/nixos/modules/services/security/hologram.nix b/nixos/modules/services/security/hologram.nix
index f9abf38942f4..58f308df7a21 100644
--- a/nixos/modules/services/security/hologram.nix
+++ b/nixos/modules/services/security/hologram.nix
@@ -95,7 +95,7 @@ in {
       wantedBy    = [ "multi-user.target" ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.goPackages.hologram}/bin/hologram-server --debug --conf ${cfgFile}";
+        ExecStart = "${pkgs.hologram}/bin/hologram-server --debug --conf ${cfgFile}";
       };
     };
   };
diff --git a/nixos/modules/services/security/physlock.nix b/nixos/modules/services/security/physlock.nix
new file mode 100644
index 000000000000..34d0be3b1beb
--- /dev/null
+++ b/nixos/modules/services/security/physlock.nix
@@ -0,0 +1,114 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.physlock;
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.physlock = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the <command>physlock</command> screen locking mechanism.
+
+          Enable this and then run <command>systemctl start physlock</command>
+          to securely lock the screen.
+
+          This will switch to a new virtual terminal, turn off console
+          switching and disable SysRq mechanism (when
+          <option>services.physlock.disableSysRq</option> is set)
+          until the root or <option>services.physlock.user</option>
+          password is given.
+        '';
+      };
+
+      user = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          User whose password will be used to unlock the screen on par
+          with the root password.
+        '';
+      };
+
+      disableSysRq = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to disable SysRq when locked with physlock.
+        '';
+      };
+
+      lockOn = {
+
+        suspend = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Whether to lock screen with physlock just before suspend.
+          '';
+        };
+
+        hibernate = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Whether to lock screen with physlock just before hibernate.
+          '';
+        };
+
+        extraTargets = mkOption {
+          type = types.listOf types.str;
+          default = [];
+          example = [ "display-manager.service" ];
+          description = ''
+            Other targets to lock the screen just before.
+
+            Useful if you want to e.g. both autologin to X11 so that
+            your <filename>~/.xsession</filename> gets executed and
+            still to have the screen locked so that the system can be
+            booted relatively unattended.
+          '';
+        };
+
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    # for physlock -l and physlock -L
+    environment.systemPackages = [ pkgs.physlock ];
+
+    systemd.services."physlock" = {
+      enable = true;
+      description = "Physlock";
+      wantedBy = optional cfg.lockOn.suspend   "suspend.target"
+              ++ optional cfg.lockOn.hibernate "hibernate.target"
+              ++ cfg.lockOn.extraTargets;
+      before   = optional cfg.lockOn.suspend   "systemd-suspend.service"
+              ++ optional cfg.lockOn.hibernate "systemd-hibernate.service"
+              ++ cfg.lockOn.extraTargets;
+      serviceConfig.Type = "forking";
+      script = ''
+        ${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"}${optionalString (cfg.user != null) " -u ${cfg.user}"}
+      '';
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index 853b458cf589..77427ce9606e 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
 
@@ -70,6 +73,7 @@ in
       enable = mkOption {
         type = types.bool;
         default = true;
+        internal = true;
         description = ''
           Whether to start the D-Bus message bus daemon, which is
           required by many other system services and applications.
diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix
index 59ba12bcc175..d98ef8a306d5 100644
--- a/nixos/modules/services/system/nscd.nix
+++ b/nixos/modules/services/system/nscd.nix
@@ -42,7 +42,10 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.nscd.description = "Name service cache daemon user";
+    users.extraUsers.nscd =
+      { isSystemUser = true;
+        description = "Name service cache daemon user";
+      };
 
     systemd.services.nscd =
       { description = "Name Service Cache Daemon";
diff --git a/nixos/modules/services/torrent/deluge.nix b/nixos/modules/services/torrent/deluge.nix
index 00df4042d890..becd57055d41 100644
--- a/nixos/modules/services/torrent/deluge.nix
+++ b/nixos/modules/services/torrent/deluge.nix
@@ -36,6 +36,8 @@ in {
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.pythonPackages.deluge ];
       serviceConfig.ExecStart = "${pkgs.pythonPackages.deluge}/bin/deluged -d";
+      # To prevent "Quit & shutdown daemon" from working; we want systemd to manage it!
+      serviceConfig.Restart = "on-success";
       serviceConfig.User = "deluge";
       serviceConfig.Group = "deluge";
     };
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 3e1e0bcc1df2..d32868f7f8eb 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..921f774bcaa0 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.3";
+  fullversion = "${version}";
 
   # Our bare-bones wp-config.php file using the above settings
   wordpressConfig = pkgs.writeText "wp-config.php" ''
@@ -38,38 +28,79 @@ 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>
+
+    ${config.extraHtaccess}
   '';
 
+  # 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 = "0sz5jjhjpwqis8336gyq9a77cr4sf8zahd1y4pzmpvpzn9cn503y";
     };
     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 +133,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 +158,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 +184,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 +205,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 =
@@ -186,10 +222,22 @@ in
         settings, see <link xlink:href='http://codex.wordpress.org/Editing_wp-config.php'/>.
       '';
     };
-  }; 
+    extraHtaccess = mkOption {
+      default = "";
+      example =
+        ''
+          php_value upload_max_filesize 20M
+          php_value post_max_size 20M
+        '';
+      description = ''
+        Any additional text to be appended to Wordpress's .htaccess file.
+      '';
+    };
+  };
 
   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 +246,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/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index fe50c182bfe5..25816446e999 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -8,9 +8,12 @@ let
   configFile = pkgs.writeText "nginx.conf" ''
     user ${cfg.user} ${cfg.group};
     daemon off;
+
     ${cfg.config}
+
     ${optionalString (cfg.httpConfig != "") ''
     http {
+      include ${cfg.package}/conf/mime.types;
       ${cfg.httpConfig}
     }
     ''}
diff --git a/nixos/modules/services/web-servers/phpfpm.nix b/nixos/modules/services/web-servers/phpfpm.nix
index 8551e3ccdeb2..82398948bfaa 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.
         '';
@@ -44,8 +44,7 @@ in {
 
       phpIni = mkOption {
         type = types.path;
-        default = "${cfg.phpPackage}/etc/php-recommended.ini";
-        description = "php.ini file to use.";
+        description = "PHP configuration file to use.";
       };
 
       poolConfigs = mkOption {
@@ -86,5 +85,7 @@ in {
       };
     };
 
+    services.phpfpm.phpIni = mkDefault "${cfg.phpPackage}/etc/php-recommended.ini";
+
   };
 }
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/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index d53f119c9558..fdee5fbc6c5b 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -25,6 +25,24 @@ let
     '';
   };
 
+  nixos-gsettings-desktop-schemas = pkgs.stdenv.mkDerivation {
+    name = "nixos-gsettings-desktop-schemas";
+    buildInputs = [ pkgs.nixos-artwork ];
+    buildCommand = ''
+     mkdir -p $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas
+     cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0 $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/
+     chmod -R a+w $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas
+     cat - > $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF
+       [org.gnome.desktop.background]
+       picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png'
+
+       [org.gnome.desktop.screensaver]
+       picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png'
+     EOF
+     ${pkgs.glib}/bin/glib-compile-schemas $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/
+    '';
+  };
+
 in {
 
   options = {
@@ -40,12 +58,12 @@ in {
       example = literalExample "[ pkgs.gnome3.gpaste ]";
       description = "Additional list of packages to be added to the session search path.
                      Useful for gnome shell extensions or gsettings-conditionated autostart.";
-      apply = list: list ++ [ gnome3.gnome_shell ]; 
+      apply = list: list ++ [ gnome3.gnome_shell gnome3.gnome-shell-extensions ];
     };
 
     environment.gnome3.packageSet = mkOption {
       default = null;
-      example = literalExample "pkgs.gnome3_12";
+      example = literalExample "pkgs.gnome3_16";
       description = "Which GNOME 3 package set to use.";
       apply = p: if p == null then pkgs.gnome3 else p;
     };
@@ -109,8 +127,8 @@ in {
           # Override default mimeapps
           export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${mimeAppsList}/share
 
-          # Let gnome-control-center find gnome-shell search providers. GNOME 3.12 compatibility.
-          export GNOME_SEARCH_PROVIDERS_DIR=${config.system.path}/share/gnome-shell/search-providers/
+          # Override gsettings-desktop-schema
+          export XDG_DATA_DIRS=${nixos-gsettings-desktop-schemas}/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS
 
           # Let nautilus find extensions
           export NAUTILUS_EXTENSION_DIR=${config.system.path}/lib/nautilus/extensions-3.0/
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 02e51577e3e2..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
 
@@ -76,7 +76,7 @@ in
     services.xserver.desktopManager.session = singleton {
       name = "kde5";
       bgSupport = true;
-      start = ''exec ${plasma5.startkde}/bin/startkde;'';
+      start = ''exec ${plasma5.plasma-workspace}/bin/startkde;'';
     };
 
     security.setuidOwners = singleton {
diff --git a/nixos/modules/services/x11/desktop-managers/kodi.nix b/nixos/modules/services/x11/desktop-managers/kodi.nix
index 1e30308a5139..de00ff93b17c 100644
--- a/nixos/modules/services/x11/desktop-managers/kodi.nix
+++ b/nixos/modules/services/x11/desktop-managers/kodi.nix
@@ -28,4 +28,4 @@ in
 
     environment.systemPackages = [ pkgs.kodi ];
   };
-}
\ No newline at end of file
+}
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index fce5bf11f053..88eefa13de35 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -62,7 +62,7 @@ in
         pkgs.xfce.xfwm4
         # This supplies some "abstract" icons such as
         # "utilities-terminal" and "accessories-text-editor".
-        pkgs.gnome.gnomeicontheme
+        pkgs.gnome3.defaultIconTheme
         pkgs.desktop_file_utils
         pkgs.xfce.libxfce4ui
         pkgs.xfce.garcon
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index c5012dbb5e30..ca0832e5b0c8 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="Desktop environment handles power events" "$0" "$sessionType"
           fi
         fi
 
@@ -108,6 +114,10 @@ let
       rm -rf $HOME/.compose-cache
       mkdir $HOME/.compose-cache
 
+      # Work around KDE errors when a user first logs in and
+      # .local/share doesn't exist yet.
+      mkdir -p $HOME/.local/share
+
       ${cfg.displayManager.sessionCommands}
 
       # Allow the user to execute commands at the beginning of the X session.
@@ -155,7 +165,11 @@ let
       exit 0
     '';
 
-  mkDesktops = names: pkgs.runCommand "desktops" {}
+  mkDesktops = names: pkgs.runCommand "desktops"
+    { # trivial derivation
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
     ''
       mkdir -p $out
       ${concatMapStrings (n: ''
@@ -165,6 +179,7 @@ let
         Type=XSession
         TryExec=${cfg.displayManager.session.script}
         Exec=${cfg.displayManager.session.script} '${n}'
+        X-GDM-BypassXsession=true
         Name=${n}
         Comment=
         EODESKTOP
@@ -218,7 +233,7 @@ in
 
       desktopManagerHandlesLidAndPower = mkOption {
         type = types.bool;
-        default = true;
+        default = false;
         description = ''
           Whether the display manager should prevent systemd from handling
           lid and power events. This is normally handled by the desktop
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 6c3c52730863..c9a563768323 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -18,14 +18,49 @@ in
 
     services.xserver.displayManager.gdm = {
 
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        example = true;
+      enable = mkEnableOption ''
+        GDM as the display manager.
+        <emphasis>GDM is very experimental and may render system unusable.</emphasis>
+      '';
+
+      debug = mkEnableOption ''
+        debugging messages in GDM
+      '';
+
+      autoLogin = mkOption {
+        default = {};
         description = ''
-          Whether to enable GDM as the display manager.
-          <emphasis>GDM is very experimental and may render system unusable.</emphasis>
+          Auto login configuration attrset.
         '';
+
+        type = types.submodule {
+          options = {
+            enable = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Automatically log in as the sepecified <option>autoLogin.user</option>.
+              '';
+            };
+
+            user = mkOption {
+              type = types.nullOr types.str;
+              default = null;
+              description = ''
+                User to be used for the autologin.
+              '';
+            };
+
+            delay = mkOption {
+              type = types.int;
+              default = 0;
+              description = ''
+                Seconds of inactivity after which the autologin will be performed.
+              '';
+            };
+
+          };
+        };
       };
 
     };
@@ -37,6 +72,12 @@ in
 
   config = mkIf cfg.gdm.enable {
 
+    assertions = [
+      { assertion = cfg.gdm.autoLogin.enable -> cfg.gdm.autoLogin.user != null;
+        message = "GDM auto-login requires services.xserver.displayManager.gdm.autoLogin.user to be set";
+      }
+    ];
+
     services.xserver.displayManager.slim.enable = false;
 
     users.extraUsers.gdm =
@@ -50,7 +91,7 @@ in
     users.extraGroups.gdm.gid = config.ids.gids.gdm;
 
     services.xserver.displayManager.job =
-      { 
+      {
         environment = {
           GDM_X_SERVER = "${cfg.xserverBin} ${cfg.xserverArgs}";
           GDM_SESSIONS_DIR = "${cfg.session.desktops}";
@@ -65,12 +106,40 @@ in
     systemd.services.display-manager.wants = [ "systemd-machined.service" ];
     systemd.services.display-manager.after = [ "systemd-machined.service" ];
 
-    systemd.services.display-manager.path = [ gnome3.gnome_shell gnome3.caribou pkgs.xlibs.xhost pkgs.dbus_tools ];
+    systemd.services.display-manager.path = [ gnome3.gnome_shell gnome3.caribou pkgs.xorg.xhost pkgs.dbus_tools ];
 
     services.dbus.packages = [ gdm ];
 
     programs.dconf.profiles.gdm = "${gdm}/share/dconf/profile/gdm";
 
+    # Use AutomaticLogin if delay is zero, because it's immediate.
+    # Otherwise with TimedLogin with zero seconds the prompt is still
+    # presented and there's a little delay.
+    environment.etc."gdm/custom.conf".text = ''
+      [daemon]
+      ${optionalString cfg.gdm.autoLogin.enable (
+        if cfg.gdm.autoLogin.delay > 0 then ''
+          TimedLoginEnable=true
+          TimedLogin=${cfg.gdm.autoLogin.user}
+          TimedLoginDelay=${toString cfg.gdm.autoLogin.delay}
+        '' else ''
+          AutomaticLoginEnable=true
+          AutomaticLogin=${cfg.gdm.autoLogin.user}
+        '')
+      }
+
+      [security]
+
+      [xdmcp]
+
+      [greeter]
+
+      [chooser]
+
+      [debug]
+      ${optionalString cfg.gdm.debug "Enable=true"}
+    '';
+
     # GDM LFS PAM modules, adapted somehow to NixOS
     security.pam.services = {
       gdm-launch-environment.text = ''
@@ -89,7 +158,7 @@ in
         session  optional       pam_permit.so
       '';
 
-     gdm.text = ''
+      gdm.text = ''
         auth     requisite      pam_nologin.so
         auth     required       pam_env.so
 
@@ -130,7 +199,7 @@ in
           "auth     required       pam_deny.so"}
 
         account  sufficient     pam_unix.so
-        
+
         password requisite      pam_unix.so nullok sha512
         ${optionalString config.security.pam.enableEcryptfs
           "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
index d0b69c5452c2..558f5e8cfc7e 100644
--- a/nixos/modules/services/x11/display-managers/kdm.nix
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -19,7 +19,7 @@ let
       ''}
 
       [X-*-Core]
-      Xrdb=${pkgs.xlibs.xrdb}/bin/xrdb
+      Xrdb=${pkgs.xorg.xrdb}/bin/xrdb
       SessionsDirs=${dmcfg.session.desktops}
       Session=${dmcfg.session.script}
       FailsafeClient=${pkgs.xterm}/bin/xterm
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 8c6c678ed19a..54874780bada 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}/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}" \
@@ -65,7 +65,7 @@ let
       greeters-directory = ${cfg.greeter.package}
       sessions-directory = ${dmcfg.session.desktops}
 
-      [SeatDefaults]
+      [Seat:*]
       xserver-command = ${xserverWrapper}
       session-wrapper = ${dmcfg.session.script}
       greeter-session = ${cfg.greeter.name}
@@ -104,7 +104,6 @@ in
       };
 
       background = mkOption {
-        default = "${pkgs.nixos-artwork}/gnome/Gnome_Dark.png";
         description = ''
           The background image or color to use.
         '';
@@ -143,8 +142,26 @@ in
     services.dbus.enable = true;
     services.dbus.packages = [ lightdm ];
 
-    security.pam.services.lightdm = { allowNullPassword = true; startSession = true; };
-    security.pam.services.lightdm-greeter = { allowNullPassword = true; startSession = true; };
+    security.pam.services.lightdm = {
+      allowNullPassword = true;
+      startSession = true;
+    };
+    security.pam.services.lightdm-greeter = {
+      allowNullPassword = true;
+      startSession = true;
+      text = ''
+        auth     required pam_env.so
+        auth     required pam_permit.so
+
+        account  required pam_permit.so
+
+        password required pam_deny.so
+
+        session  required pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  required pam_unix.so
+        session  optional ${pkgs.systemd}/lib/security/pam_systemd.so
+      '';
+    };
 
     users.extraUsers.lightdm = {
       createHome = true;
@@ -154,5 +171,8 @@ in
     };
 
     users.extraGroups.lightdm.gid = config.ids.gids.lightdm;
+
+    services.xserver.displayManager.lightdm.background = mkDefault "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png";
+
   };
 }
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..e50ed08a218a 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -18,6 +18,8 @@ let cfg = config.services.xserver.synaptics;
       Option "TapButton2" "0"
       Option "TapButton3" "0"
     '';
+  pkg = pkgs.xorg.xf86inputsynaptics;
+  etcFile = "X11/xorg.conf.d/50-synaptics.conf";
 in {
 
   options = {
@@ -63,12 +65,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.";
       };
 
@@ -128,9 +148,12 @@ in {
 
   config = mkIf cfg.enable {
 
-    services.xserver.modules = [ pkgs.xorg.xf86inputsynaptics ];
+    services.xserver.modules = [ pkg ];
+
+    environment.etc."${etcFile}".source =
+      "${pkg}/share/X11/xorg.conf.d/50-synaptics.conf";
 
-    environment.systemPackages = [ pkgs.xorg.xf86inputsynaptics ];
+    environment.systemPackages = [ pkg ];
 
     services.xserver.config =
       ''
@@ -147,9 +170,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..ffae22d2d670 100644
--- a/nixos/modules/services/x11/redshift.nix
+++ b/nixos/modules/services/x11/redshift.nix
@@ -1,52 +1,91 @@
 { config, lib, pkgs, ... }:
+
 with lib;
+
 let
+
   cfg = config.services.redshift;
 
 in {
-  options = {
-    services.redshift.enable = mkOption {
+
+  options.services.redshift = {
+    enable = mkOption {
       type = types.bool;
       default = false;
       example = true;
-      description = "Enable Redshift to change your screen's colour temperature depending on the time of day";
+      description = ''
+        Enable Redshift to change your screen's colour temperature depending on
+        the time of day.
+      '';
     };
 
-    services.redshift.latitude = mkOption {
-      description = "Your current latitude";
-      type = types.uniq types.string;
+    latitude = mkOption {
+      type = types.str;
+      description = ''
+        Your current latitude.
+      '';
     };
 
-    services.redshift.longitude = mkOption {
-      description = "Your current longitude";
-      type = types.uniq types.string;
+    longitude = mkOption {
+      type = types.str;
+      description = ''
+        Your current longitude.
+      '';
     };
 
-    services.redshift.temperature = {
+    temperature = {
       day = mkOption {
-        description = "Colour temperature to use during day time";
+        type = types.int;
         default = 5500;
-        type = types.uniq types.int;
+        description = ''
+          Colour temperature to use during the day.
+        '';
       };
       night = mkOption {
-        description = "Colour temperature to use during night time";
+        type = types.int;
         default = 3700;
-        type = types.uniq types.int;
+        description = ''
+          Colour temperature to use at night.
+        '';
       };
     };
 
-    services.redshift.brightness = {
+    brightness = {
       day = mkOption {
-        description = "Screen brightness to apply during the day (between 0.1 and 1.0)";
+        type = types.str;
         default = "1";
-        type = types.uniq types.string;
+        description = ''
+          Screen brightness to apply during the day,
+          between <literal>0.1</literal> and <literal>1.0</literal>.
+        '';
       };
       night = mkOption {
-        description = "Screen brightness to apply during the night (between 0.1 and 1.0)";
+        type = types.str;
         default = "1";
-        type = types.uniq types.string;
+        description = ''
+          Screen brightness to apply during the night,
+          between <literal>0.1</literal> and <literal>1.0</literal>.
+        '';
       };
     };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.redshift;
+      description = ''
+        redshift derivation to use.
+      '';
+    };
+
+    extraOptions = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = [ "-v" "-m randr" ];
+      description = ''
+        Additional command-line arguments to pass to
+        <command>redshift</command>.
+      '';
+    };
   };
 
   config = mkIf cfg.enable {
@@ -56,13 +95,15 @@ in {
       after = [ "display-manager.service" ];
       wantedBy = [ "graphical.target" ];
       serviceConfig.ExecStart = ''
-        ${pkgs.redshift}/bin/redshift \
+        ${cfg.package}/bin/redshift \
           -l ${cfg.latitude}:${cfg.longitude} \
           -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} \
-          -b ${toString cfg.brightness.day}:${toString cfg.brightness.night}
+          -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} \
+          ${lib.strings.concatStringsSep " " cfg.extraOptions}
       '';
       environment = { DISPLAY = ":0"; };
       serviceConfig.Restart = "always";
     };
   };
+
 }
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..4751de07a15d 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
@@ -24,6 +25,7 @@ in
     ./windowmaker.nix
     ./wmii.nix
     ./xmonad.nix
+    ./qtile.nix
     ./none.nix ];
 
   options = {
diff --git a/nixos/modules/services/x11/window-managers/icewm.nix b/nixos/modules/services/x11/window-managers/icewm.nix
index 36028da453a5..9a3e80221890 100644
--- a/nixos/modules/services/x11/window-managers/icewm.nix
+++ b/nixos/modules/services/x11/window-managers/icewm.nix
@@ -3,29 +3,16 @@
 with lib;
 
 let
-
   cfg = config.services.xserver.windowManager.icewm;
-
 in
-
 {
-
   ###### interface
-
   options = {
-
-    services.xserver.windowManager.icewm.enable = mkOption {
-      default = false;
-      description = "Enable the IceWM window manager.";
-    };
-
+    services.xserver.windowManager.icewm.enable = mkEnableOption "oroborus";
   };
 
-
   ###### implementation
-
   config = mkIf cfg.enable {
-
     services.xserver.windowManager.session = singleton
       { name = "icewm";
         start =
@@ -36,7 +23,5 @@ in
       };
 
     environment.systemPackages = [ pkgs.icewm ];
-
   };
-
 }
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/oroborus.nix b/nixos/modules/services/x11/window-managers/oroborus.nix
new file mode 100644
index 000000000000..bd7e3396864b
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/oroborus.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.xserver.windowManager.oroborus;
+in
+{
+  ###### interface
+  options = {
+    services.xserver.windowManager.oroborus.enable = mkEnableOption "oroborus";
+  };
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    services.xserver.windowManager.session = singleton {
+      name = "oroborus";
+      start = ''
+        ${pkgs.oroborus}/bin/oroborus &
+        waitPID=$!
+      '';
+    };
+    environment.systemPackages = [ pkgs.oroborus ];
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/qtile.nix b/nixos/modules/services/x11/window-managers/qtile.nix
new file mode 100644
index 000000000000..37f84f0903c3
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/qtile.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.xserver.windowManager.qtile;
+in
+
+{
+  options = {
+    services.xserver.windowManager.qtile.enable = mkEnableOption "qtile";
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager.session = [{
+      name = "qtile";
+      start = ''
+        ${pkgs.qtile}/bin/qtile
+        waitPID=$!
+      '';
+    }];
+    
+    environment.systemPackages = [ pkgs.qtile ];
+  };
+}
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/window-managers/wmii.nix b/nixos/modules/services/x11/window-managers/wmii.nix
index 75f6fdfe3bc4..e6f534a1be66 100644
--- a/nixos/modules/services/x11/window-managers/wmii.nix
+++ b/nixos/modules/services/x11/window-managers/wmii.nix
@@ -1,47 +1,43 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
+{ config, lib, pkgs, options, modulesPath }:
 
 let
-
+  inherit (lib) mkOption mkIf singleton;
   cfg = config.services.xserver.windowManager.wmii;
-
+  wmii = pkgs.wmii_hg;
 in
-
 {
   options = {
-
     services.xserver.windowManager.wmii.enable = mkOption {
       default = false;
       example = true;
       description = "Enable the wmii window manager.";
     };
-
   };
 
   config = mkIf cfg.enable {
-
     services.xserver.windowManager.session = singleton
       # stop wmii by
       #   $wmiir xwrite /ctl quit
       # this will cause wmii exiting with exit code 0
+      # (or "mod+a quit", which is bound to do the same thing in wmiirc
+      # by default)
       #
       # why this loop?
       # wmii crashes once a month here. That doesn't matter that much
-      # wmii can recover very well. However without loop the x session terminates and then your workspace setup is
-      # lost and all applications running on X will terminate.
+      # wmii can recover very well. However without loop the X session
+      # terminates and then your workspace setup is lost and all
+      # applications running on X will terminate.
       # Another use case is kill -9 wmii; after rotating screen.
-      # Note: we don't like kill for that purpose. But it works (-> subject "wmii and xrandr" on mailinglist)
+      # Note: we don't like kill for that purpose. But it works (->
+      # subject "wmii and xrandr" on mailinglist)
       { name = "wmii";
         start = ''
           while :; do
-            ${pkgs.wmiiSnap}/bin/wmii && break
+            ${wmii}/bin/wmii && break
           done
         '';
       };
 
-    environment.systemPackages = [ pkgs.wmiiSnap ];
-
+    environment.systemPackages = [ wmii ];
   };
-
 }
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 5198864ef6ef..3348e8d0582c 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -13,7 +13,6 @@ let
 
   # Map video driver names to driver packages. FIXME: move into card-specific modules.
   knownVideoDrivers = {
-    nouveau       = { modules = [ pkgs.xf86_video_nouveau ]; };
     unichrome    = { modules = [ pkgs.xorgVideoUnichrome ]; };
     virtualbox   = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; };
     ati = { modules = [ pkgs.xorg.xf86videoati pkgs.xorg.glamoregl ]; };
@@ -238,6 +237,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 +476,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/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index b29488edc081..dd2ce1894ae6 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -115,10 +115,6 @@ in
       ''
         # Various log/runtime directories.
 
-        touch /run/utmp # must exist
-        chgrp ${toString config.ids.gids.utmp} /run/utmp
-        chmod 664 /run/utmp
-
         mkdir -m 0755 -p /run/nix/current-load # for distributed builds
         mkdir -m 0700 -p /run/nix/remote-stores
 
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 4289740322ad..655fbab2a843 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -97,7 +97,7 @@ sub parseFstab {
 sub parseUnit {
     my ($filename) = @_;
     my $info = {};
-    parseKeyValues($info, read_file($filename));
+    parseKeyValues($info, read_file($filename)) if -f $filename;
     parseKeyValues($info, read_file("${filename}.d/overrides.conf")) if -f "${filename}.d/overrides.conf";
     return $info;
 }
@@ -157,7 +157,8 @@ while (my ($unit, $state) = each %{$activePrev}) {
 
     if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) {
         if (! -e $newUnitFile || abs_path($newUnitFile) eq "/dev/null") {
-            $unitsToStop{$unit} = 1;
+            my $unitInfo = parseUnit($prevUnitFile);
+            $unitsToStop{$unit} = 1 if boolIsTrue($unitInfo->{'X-StopOnRemoval'} // "yes");
         }
 
         elsif ($unit =~ /\.target$/) {
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index d7a1e205b4d4..81088a56fb12 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -50,7 +50,7 @@ let
 
         ln -s ${config.system.build.initialRamdisk}/initrd $out/initrd
 
-        ln -s ${config.hardware.firmware} $out/firmware
+        ln -s ${config.hardware.firmware}/lib/firmware $out/firmware
       ''}
 
       echo "$activationScript" > $out/activate
@@ -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}
     '';
 
@@ -97,8 +99,11 @@ let
   # makes it bootable.
   baseSystem = showWarnings (
     if [] == failed then pkgs.stdenv.mkDerivation {
-      name = "nixos-${config.system.nixosVersion}";
+      name = let hn = config.networking.hostName;
+                 nn = if (hn != "") then hn else "unnamed";
+          in "nixos-system-${nn}-${config.system.nixosVersion}";
       preferLocalBuild = true;
+      allowSubstitutes = false;
       buildCommand = systemBuilder;
 
       inherit (pkgs) utillinux coreutils;
@@ -188,6 +193,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..ac40e8a49acf 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -49,9 +49,8 @@ in
       type = types.int;
       default = 4;
       description = ''
-        The kernel console log level.  Only log messages with a
-        priority numerically less than this will appear on the
-        console.
+        The kernel console log level.  Log messages with a priority
+        numerically less than this will not appear on the console.
       '';
     };
 
@@ -159,7 +158,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)
@@ -217,7 +216,7 @@ in
       ];
 
     # The Linux kernel >= 2.6.27 provides firmware.
-    hardware.firmware = [ "${kernel}/lib/firmware" ];
+    hardware.firmware = [ kernel ];
 
     # Create /etc/modules-load.d/nixos.conf, which is read by
     # systemd-modules-load.service to load required kernel modules.
diff --git a/nixos/modules/system/boot/loader/efi.nix b/nixos/modules/system/boot/loader/efi.nix
index 241cfc7e836d..726634e664d7 100644
--- a/nixos/modules/system/boot/loader/efi.nix
+++ b/nixos/modules/system/boot/loader/efi.nix
@@ -15,7 +15,7 @@ with lib;
     efiSysMountPoint = mkOption {
       default = "/boot";
 
-      type = types.string;
+      type = types.str;
 
       description = "Where the EFI System Partition is mounted.";
     };
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..c5c250c14cea
--- /dev/null
+++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix
@@ -0,0 +1,9 @@
+{ pkgs }:
+
+pkgs.substituteAll {
+  src = ./extlinux-conf-builder.sh;
+  isExecutable = true;
+  path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
+  inherit (pkgs) bash;
+  kernelDTB = pkgs.stdenv.platform.kernelDTB or false;
+}
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..b9a42b2a196d
--- /dev/null
+++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh
@@ -0,0 +1,140 @@
+#! @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
+    if [ -n "@kernelDTB@" ]; then
+        # XXX UGLY: maybe the system config should have a top-level "dtbs" entry?
+        copyToKernelsDir $(readlink -m "$path/kernel/../dtbs"); dtbs=$result
+    fi
+
+    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)"
+    if [ -n "@kernelDTB@" ]; then
+        echo "  FDTDIR ../nixos/$(basename $dtbs)"
+    fi
+    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
+
+MENU TITLE ------------------------------------------------------------
+TIMEOUT $timeout
+EOF
+
+addEntry $default default >> $tmpFile
+
+if [ "$numGenerations" -gt 0 ]; then
+    # 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
+fi
+
+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..0b349749244f 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
 
 {
@@ -97,8 +112,66 @@ in
         description = ''
           The devices on which the boot loader, GRUB, will be
           installed. Can be used instead of <literal>device</literal> to
-          install grub into multiple devices (e.g., if as softraid arrays holding /boot).
+          install GRUB onto multiple devices.
+        '';
+      };
+
+      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 path 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 {
@@ -110,12 +183,21 @@ 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;
         description = ''
           Additional bash commands to be run at the script that
-          prepares the grub menu entries.
+          prepares the GRUB menu entries.
         '';
       };
 
@@ -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;
@@ -230,10 +330,10 @@ in
         type = types.addCheck types.str
           (type: type == "uuid" || type == "label" || type == "provided");
         description = ''
-          Determines how grub will identify devices when generating the
+          Determines how GRUB will identify devices when generating the
           configuration file. A value of uuid / label signifies that grub
           will always resolve the uuid or label of the device before using
-          it in the configuration. A value of provided means that grub will
+          it in the configuration. A value of provided means that GRUB will
           use the device name as show in <command>df</command> or
           <command>mount</command>. Note, zfs zpools / datasets are ignored
           and will always be mounted using their labels.
@@ -244,7 +344,7 @@ in
         default = false;
         type = types.bool;
         description = ''
-          Whether grub should be build against libzfs.
+          Whether GRUB should be build against libzfs.
           ZFS support is only available for GRUB v2.
           This option is ignored for GRUB v1.
         '';
@@ -254,7 +354,7 @@ in
         default = false;
         type = types.bool;
         description = ''
-          Whether grub should be build with EFI support.
+          Whether GRUB should be build with EFI support.
           EFI support is only available for GRUB v2.
           This option is ignored for GRUB v1.
         '';
@@ -264,11 +364,20 @@ in
         default = false;
         type = types.bool;
         description = ''
-          Enable support for encrypted partitions. Grub should automatically
+          Enable support for encrypted partitions. GRUB should automatically
           unlock the correct encrypted partition and look for filesystems.
         '';
       };
 
+      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..af39e50ff72d 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";
     }
 }
@@ -231,6 +237,7 @@ else {
         $conf .= "
             " . $grubStore->search;
     }
+    # FIXME: should use grub-mkconfig.
     $conf .= "
         " . $grubBoot->search . "
         if [ -s \$prefix/grubenv ]; then
@@ -239,24 +246,35 @@ else {
 
         # ‘grub-reboot’ sets a one-time saved entry, which we process here and
         # then delete.
-        if [ \"\${saved_entry}\" ]; then
-          # The next line *has* to look exactly like this, otherwise KDM's
-          # reboot feature won't work properly with GRUB 2.
+        if [ \"\${next_entry}\" ]; then
+          # FIXME: KDM expects the next line to be present.
           set default=\"\${saved_entry}\"
-          set saved_entry=
-          set prev_saved_entry=
-          save_env saved_entry
-          save_env prev_saved_entry
+          set default=\"\${next_entry}\"
+          set next_entry=
+          save_env next_entry
           set timeout=1
         else
           set default=$defaultEntry
           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 +282,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 +303,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 +414,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 +433,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 +454,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 +499,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 +516,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 +530,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 +541,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/loader/raspberrypi/builder.sh b/nixos/modules/system/boot/loader/raspberrypi/builder.sh
index f6ccfe493d8a..ccb88ca1c529 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/builder.sh
+++ b/nixos/modules/system/boot/loader/raspberrypi/builder.sh
@@ -60,22 +60,26 @@ addEntry() {
     fi
 
     local kernel=$(readlink -f $path/kernel)
-    # local initrd=$(readlink -f $path/initrd)
+    local initrd=$(readlink -f $path/initrd)
 
     if test -n "@copyKernels@"; then
         copyToKernelsDir $kernel; kernel=$result
-        # copyToKernelsDir $initrd; initrd=$result
+        copyToKernelsDir $initrd; initrd=$result
     fi
     
     echo $(readlink -f $path) > $outdir/$generation-system
     echo $(readlink -f $path/init) > $outdir/$generation-init
     cp $path/kernel-params $outdir/$generation-cmdline.txt
-    # echo $initrd > $outdir/$generation-initrd
+    echo $initrd > $outdir/$generation-initrd
     echo $kernel > $outdir/$generation-kernel
 
     if test $(readlink -f "$path") = "$default"; then
-      copyForced $kernel /boot/kernel.img
-      # copyForced $initrd /boot/initrd
+      if [ @version@ -eq 1 ]; then
+        copyForced $kernel /boot/kernel.img
+      else
+        copyForced $kernel /boot/kernel7.img
+      fi
+      copyForced $initrd /boot/initrd
       cp "$(readlink -f "$path/init")" /boot/nixos-init
       echo "`cat $path/kernel-params` init=$path/init" >/boot/cmdline.txt
 
@@ -98,8 +102,11 @@ fwdir=@firmware@/share/raspberrypi/boot/
 copyForced $fwdir/bootcode.bin  /boot/bootcode.bin
 copyForced $fwdir/fixup.dat     /boot/fixup.dat
 copyForced $fwdir/fixup_cd.dat  /boot/fixup_cd.dat
+copyForced $fwdir/fixup_db.dat  /boot/fixup_db.dat
 copyForced $fwdir/start.elf     /boot/start.elf
 copyForced $fwdir/start_cd.elf  /boot/start_cd.elf
+copyForced $fwdir/start_db.elf  /boot/start_db.elf
+copyForced $fwdir/start_x.elf   /boot/start_x.elf
 
 # Remove obsolete files from /boot/old.
 for fn in /boot/old/*linux* /boot/old/*initrd*; do
diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
index 1ea3ddd8867c..b7400e333e21 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
+++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
@@ -3,6 +3,7 @@
 with lib;
 
 let
+  cfg = config.boot.loader.raspberryPi;
 
   builder = pkgs.substituteAll {
     src = ./builder.sh;
@@ -10,6 +11,7 @@ let
     inherit (pkgs) bash;
     path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
     firmware = pkgs.raspberrypifw;
+    version = cfg.version;
   };
 
   platform = pkgs.stdenv.platform;
@@ -29,11 +31,23 @@ in
       '';
     };
 
+    boot.loader.raspberryPi.version = mkOption {
+      default = 2;
+      type = types.int;
+      description = ''
+      '';
+    };
+
   };
 
   config = mkIf config.boot.loader.raspberryPi.enable {
     system.build.installBootLoader = builder;
     system.boot.loader.id = "raspberrypi";
     system.boot.loader.kernelFile = platform.kernelTarget;
+    assertions = [
+      { assertion = (cfg.version == 1 || cfg.version == 2);
+        message = "loader.raspberryPi.version should be 1 or 2";
+      }
+    ];
   };
 }
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 20eee8e06e07..4a14ff1879c9 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"
@@ -241,20 +242,30 @@ in
 
         name = mkOption {
           example = "luksroot";
-          type = types.string;
+          type = types.str;
           description = "Named to be used for the generated device in /dev/mapper.";
         };
 
         device = mkOption {
           example = "/dev/sda2";
-          type = types.string;
+          type = types.str;
           description = "Path of the underlying block device.";
         };
 
+        header = mkOption {
+          default = null;
+          example = "/root/header.img";
+          type = types.nullOr types.str;
+          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";
-          type = types.nullOr types.string;
+          type = types.nullOr types.str;
           description = ''
             The name of the file (can be a raw device or a partition) that
             should be used as the decryption key for the encrypted device. If
@@ -286,8 +297,8 @@ in
           type = types.bool;
           description = ''
             Whether to allow TRIM requests to the underlying device. This option
-            has security implications, please read the LUKS documentation before
-            activating in.
+            has security implications; please read the LUKS documentation before
+            activating it.
           '';
         };
 
@@ -303,43 +314,43 @@ in
             twoFactor = mkOption {
               default = true;
               type = types.bool;
-              description = "Whether to use a passphrase and a Yubikey (true), or only a Yubikey (false)";
+              description = "Whether to use a passphrase and a Yubikey (true), or only a Yubikey (false).";
             };
 
             slot = mkOption {
               default = 2;
               type = types.int;
-              description = "Which slot on the Yubikey to challenge";
+              description = "Which slot on the Yubikey to challenge.";
             };
 
             saltLength = mkOption {
               default = 16;
               type = types.int;
-              description = "Length of the new salt in byte (64 is the effective maximum)";
+              description = "Length of the new salt in byte (64 is the effective maximum).";
             };
 
             keyLength = mkOption {
               default = 64;
               type = types.int;
-              description = "Length of the LUKS slot key derived with PBKDF2 in byte";
+              description = "Length of the LUKS slot key derived with PBKDF2 in byte.";
             };
 
             iterationStep = mkOption {
               default = 0;
               type = types.int;
-              description = "How much the iteration count for PBKDF2 is increased at each successful authentication";
+              description = "How much the iteration count for PBKDF2 is increased at each successful authentication.";
             };
 
             gracePeriod = mkOption {
               default = 2;
               type = types.int;
-              description = "Time in seconds to wait before attempting to find the Yubikey";
+              description = "Time in seconds to wait before attempting to find the Yubikey.";
             };
 
             ramfsMountPoint = mkOption {
               default = "/crypt-ramfs";
-              type = types.string;
-              description = "Path where the ramfs used to update the LUKS key will be mounted in stage-1";
+              type = types.str;
+              description = "Path where the ramfs used to update the LUKS key will be mounted during early boot.";
             };
 
             /* TODO: Add to the documentation of the current module:
@@ -358,19 +369,19 @@ in
 
               fsType = mkOption {
                 default = "vfat";
-                type = types.string;
-                description = "The filesystem of the unencrypted device";
+                type = types.str;
+                description = "The filesystem of the unencrypted device.";
               };
 
               mountPoint = mkOption {
                 default = "/crypt-storage";
-                type = types.string;
-                description = "Path where the unencrypted device will be mounted in stage-1";
+                type = types.str;
+                description = "Path where the unencrypted device will be mounted during early boot.";
               };
 
               path = mkOption {
                 default = "/crypt-storage/default";
-                type = types.string;
+                type = types.str;
                 description = ''
                   Absolute path of the salt on the unencrypted device with
                   that device's root directory as "/".
@@ -419,10 +430,10 @@ in
         mkdir -p $out/etc/ssl
         cp -pdv ${pkgs.openssl}/etc/ssl/openssl.cnf $out/etc/ssl
 
-      cat > $out/bin/openssl-wrap <<EOF
-#!$out/bin/sh
-EOF
-      chmod +x $out/bin/openssl-wrap
+        cat > $out/bin/openssl-wrap <<EOF
+        #!$out/bin/sh
+        EOF
+        chmod +x $out/bin/openssl-wrap
       ''}
     '';
 
@@ -432,10 +443,10 @@ EOF
         $out/bin/ykchalresp -V
         $out/bin/ykinfo -V
         cat > $out/bin/openssl-wrap <<EOF
-#!$out/bin/sh
-export OPENSSL_CONF=$out/etc/ssl/openssl.cnf
-$out/bin/openssl "\$@"
-EOF
+        #!$out/bin/sh
+        export OPENSSL_CONF=$out/etc/ssl/openssl.cnf
+        $out/bin/openssl "\$@"
+        EOF
         $out/bin/openssl-wrap version
       ''}
     '';
diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix
index a1feaad6132d..9bb10eac9880 100644
--- a/nixos/modules/system/boot/modprobe.nix
+++ b/nixos/modules/system/boot/modprobe.nix
@@ -35,6 +35,7 @@ with lib;
             fi
 
           '';
+        meta.priority = 4;
       };
       description = ''
         Wrapper around modprobe that sets the path to the modules
@@ -84,11 +85,7 @@ with lib;
         '')}
         ${config.boot.extraModprobeConfig}
       '';
-    environment.etc."modprobe.d/usb-load-ehci-first.conf".text =
-      ''
-        softdep uhci_hcd pre: ehci_hcd
-        softdep ohci_hcd pre: ehci_hcd
-      '';
+    environment.etc."modprobe.d/debian.conf".source = pkgs.kmod-debian-aliases;
 
     environment.systemPackages = [ config.system.sbin.modprobe pkgs.kmod ];
 
@@ -101,7 +98,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/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 0221374ab835..34eea9af83b1 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -132,7 +132,7 @@ let
   commonNetworkOptions = {
 
     enable = mkOption {
-      default = false;
+      default = true;
       type = types.bool;
       description = ''
         Whether to manage network configuration using <command>systemd-network</command>.
@@ -482,6 +482,11 @@ let
     };
   };
 
+  commonMatchText = def: ''
+    [Match]
+    ${attrsToSection def.matchConfig}
+  '';
+
   linkToUnit = name: def:
     { inherit (def) enable;
       text = commonMatchText def +
@@ -636,9 +641,6 @@ in
     environment.etc."systemd/network".source =
       generateUnits "network" cfg.units [] [];
 
-    users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network;
-    users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network;
-
     systemd.services.systemd-networkd = {
       wantedBy = [ "multi-user.target" ];
       before = [ "network-interfaces.target" ];
diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix
index ecd547322d3c..5a98b9b6d480 100644
--- a/nixos/modules/system/boot/resolved.nix
+++ b/nixos/modules/system/boot/resolved.nix
@@ -30,9 +30,6 @@ with lib;
       DNS=${concatStringsSep " " config.networking.nameservers}
     '';
 
-    users.extraUsers.systemd-resolve.uid = config.ids.uids.systemd-resolve;
-    users.extraGroups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
-
   };
 
 }
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 5af644279e5f..51828c5c090b 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -135,7 +135,7 @@ ln -s @modulesClosure@/lib/modules /lib/modules
 echo @extraUtils@/bin/modprobe > /proc/sys/kernel/modprobe
 for i in @kernelModules@; do
     echo "loading module $(basename $i)..."
-    modprobe $i || true
+    modprobe $i
 done
 
 
@@ -146,7 +146,7 @@ ln -sfn @udevRules@ /etc/udev/rules.d
 mkdir -p /dev/.mdadm
 systemd-udevd --daemon
 udevadm trigger --action=add
-udevadm settle || true
+udevadm settle
 
 
 # Load boot-time keymap before any LVM/LUKS initialization
@@ -182,9 +182,9 @@ if test -e /sys/power/resume -a -e /sys/power/disk; then
         for sd in @resumeDevices@; do
             # Try to detect resume device. According to Ubuntu bug:
             # https://bugs.launchpad.net/ubuntu/+source/pm-utils/+bug/923326/comments/1
-            # When there are multiple swap devices, we can't know where will hibernate
-            # image reside. We can check all of them for swsuspend blkid.
-            resumeInfo="$(udevadm info -q property "$sd" )"
+            # when there are multiple swap devices, we can't know where the hibernate
+            # image will reside. We can check all of them for swsuspend blkid.
+            resumeInfo="$(test -e "$sd" && udevadm info -q property "$sd")"
             if [ "$(echo "$resumeInfo" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then
                 resumeDev="$sd"
                 break
@@ -290,10 +290,23 @@ mountFS() {
         if [ -z "$fsType" ]; then fsType=auto; fi
     fi
 
-    echo "$device /mnt-root$mountPoint $fsType $options" >> /etc/fstab
+    # Filter out x- options, which busybox doesn't do yet.
+    local optionsFiltered="$(IFS=,; for i in $options; do if [ "${i:0:2}" != "x-" ]; then echo -n $i,; fi; done)"
+
+    echo "$device /mnt-root$mountPoint $fsType $optionsFiltered" >> /etc/fstab
 
     checkFS "$device" "$fsType"
 
+    # Optionally resize the filesystem.
+    case $options in
+        *x-nixos.autoresize*)
+            if [ "$fsType" = ext2 -o "$fsType" = ext3 -o "$fsType" = ext4 ]; then
+                echo "resizing $device..."
+                resize2fs "$device"
+            fi
+            ;;
+    esac
+
     # Create backing directories for unionfs-fuse.
     if [ "$fsType" = unionfs-fuse ]; then
         for i in $(IFS=:; echo ${options##*,dirs=}); do
@@ -303,7 +316,7 @@ mountFS() {
 
     echo "mounting $device on $mountPoint..."
 
-    mkdir -p "/mnt-root$mountPoint" || true
+    mkdir -p "/mnt-root$mountPoint"
 
     # For CIFS mounts, retry a few times before giving up.
     local n=0
@@ -317,7 +330,7 @@ mountFS() {
 
 
 # Try to find and mount the root device.
-mkdir /mnt-root
+mkdir -p $targetRoot
 
 exec 3< @fsInfo@
 
@@ -375,7 +388,7 @@ while read -u 3 mountPoint; do
 
     # Wait once more for the udev queue to empty, just in case it's
     # doing something with $device right now.
-    udevadm settle || true
+    udevadm settle
 
     mountFS "$device" "$mountPoint" "$options" "$fsType"
 done
@@ -388,9 +401,9 @@ exec 3>&-
 
 # Emit a udev rule for /dev/root to prevent systemd from complaining.
 if [ -e /mnt-root/iso ]; then
-    eval $(udevadm info --export --export-prefix=ROOT_ --device-id-of-file=/mnt-root/iso || true)
+    eval $(udevadm info --export --export-prefix=ROOT_ --device-id-of-file=/mnt-root/iso)
 else
-    eval $(udevadm info --export --export-prefix=ROOT_ --device-id-of-file=$targetRoot || true)
+    eval $(udevadm info --export --export-prefix=ROOT_ --device-id-of-file=$targetRoot)
 fi
 if [ "$ROOT_MAJOR" -a "$ROOT_MINOR" -a "$ROOT_MAJOR" != 0 ]; then
     mkdir -p /run/udev/rules.d
@@ -399,7 +412,7 @@ fi
 
 
 # Stop udevd.
-udevadm control --exit || true
+udevadm control --exit
 
 # Kill any remaining processes, just to be sure we're not taking any
 # with us into stage 2. But keep storage daemons like unionfs-fuse.
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index af1353952d8b..6b722c4e1105 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -70,6 +70,12 @@ let
       copy_bin_and_libs ${pkgs.kmod}/bin/kmod
       ln -sf kmod $out/bin/modprobe
 
+      # Copy resize2fs if needed.
+      ${optionalString (any (fs: fs.autoResize) (attrValues config.fileSystems)) ''
+        # We need mke2fs in the initrd.
+        copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs
+      ''}
+
       ${config.boot.initrd.extraUtilsCommands}
 
       # Copy ld manually since it isn't detected correctly
@@ -241,6 +247,9 @@ let
           };
           symlink = "/etc/modprobe.d/ubuntu.conf";
         }
+        { object = pkgs.kmod-debian-aliases;
+          symlink = "/etc/modprobe.d/debian.conf";
+        }
       ];
   };
 
@@ -358,7 +367,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.";
     };
 
@@ -390,7 +399,6 @@ in
       }
     ];
 
-
     system.build.bootStage1 = bootStage1;
     system.build.initialRamdisk = initialRamdisk;
     system.build.extraUtils = extraUtils;
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index 173453a17f71..a73070ab332f 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -85,8 +85,10 @@ done
 
 
 # More special file systems, initialise required directories.
-mkdir -m 0755 /dev/shm
-mount -t tmpfs -o "rw,nosuid,nodev,size=@devShmSize@" tmpfs /dev/shm
+if ! mountpoint -q /dev/shm; then
+    mkdir -m 0755 /dev/shm
+    mount -t tmpfs -o "rw,nosuid,nodev,size=@devShmSize@" tmpfs /dev/shm
+fi
 mkdir -m 0755 -p /dev/pts
 [ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default
 mkdir -m 01777 -p /tmp
@@ -162,7 +164,9 @@ $systemConfig/activate
 # Restore the system time from the hardware clock.  We do this after
 # running the activation script to be sure that /etc/localtime points
 # at the current time zone.
-hwclock --hctosys
+if [ -e /dev/rtc ]; then
+    hwclock --hctosys
+fi
 
 
 # Record the boot configuration.
diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix
index e8cfd3395cb0..8acaa5212f5f 100644
--- a/nixos/modules/system/boot/systemd-lib.nix
+++ b/nixos/modules/system/boot/systemd-lib.nix
@@ -13,20 +13,93 @@ 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}
         '';
 
+  boolValues = [true false "yes" "no"];
+
+  digits = map toString (range 0 9);
+
+  isByteFormat = s:
+    let
+      l = reverseList (stringToCharacters s);
+      suffix = head l;
+      nums = tail l;
+    in elem suffix (["K" "M" "G" "T"] ++ digits)
+      && all (num: elem num digits) nums;
+
+  assertByteFormat = name: group: attr:
+    optional (attr ? ${name} && ! isByteFormat attr.${name})
+      "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT].";
+
+  hexChars = stringToCharacters "0123456789abcdefABCDEF";
+
+  isMacAddress = s: stringLength s == 17
+    && flip all (splitString ":" s) (bytes:
+      all (byte: elem byte hexChars) (stringToCharacters bytes)
+    );
+
+  assertMacAddress = name: group: attr:
+    optional (attr ? ${name} && ! isMacAddress attr.${name})
+      "Systemd ${group} field `${name}' must be a valid mac address.";
+
+
+  assertValueOneOf = name: values: group: attr:
+    optional (attr ? ${name} && !elem attr.${name} values)
+      "Systemd ${group} field `${name}' cannot have value `${attr.${name}}'.";
+
+  assertHasField = name: group: attr:
+    optional (!(attr ? ${name}))
+      "Systemd ${group} field `${name}' must exist.";
+
+  assertRange = name: min: max: group: attr:
+    optional (attr ? ${name} && !(min <= attr.${name} && max >= attr.${name}))
+      "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]";
+
+  assertOnlyFields = fields: group: attr:
+    let badFields = filter (name: ! elem name fields) (attrNames attr); in
+    optional (badFields != [ ])
+      "Systemd ${group} has extra fields [${concatStringsSep " " badFields}].";
+
+  checkUnitConfig = group: checks: v:
+    let errors = concatMap (c: c group v) checks; in
+    if errors == [] then true
+      else builtins.trace (concatStringsSep "\n" errors) false;
+
+  toOption = x:
+    if x == true then "true"
+    else if x == false then "false"
+    else toString x;
+
+  attrsToSection = as:
+    concatStrings (concatLists (mapAttrsToList (name: value:
+      map (x: ''
+          ${name}=${toOption x}
+        '')
+        (if isList value then value else [value]))
+        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 785634cbf66a..a7a334dec285 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -1,58 +1,9 @@
 { config, lib }:
 
 with lib;
+with import ./systemd-lib.nix { inherit config lib pkgs; };
 
 let
-
-  boolValues = [true false "yes" "no"];
-
-  assertValueOneOf = name: values: group: attr:
-    optional (attr ? ${name} && !elem attr.${name} values)
-      "Systemd ${group} field `${name}' cannot have value `${attr.${name}}'.";
-
-  assertHasField = name: group: attr:
-    optional (!(attr ? ${name}))
-      "Systemd ${group} field `${name}' must exist.";
-
-  assertOnlyFields = fields: group: attr:
-    let badFields = filter (name: ! elem name fields) (attrNames attr); in
-    optional (badFields != [ ])
-      "Systemd ${group} has extra fields [${concatStringsSep " " badFields}].";
-
-  assertRange = name: min: max: group: attr:
-    optional (attr ? ${name} && !(min <= attr.${name} && max >= attr.${name}))
-      "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]";
-
-  digits = map toString (range 0 9);
-
-  isByteFormat = s:
-    let
-      l = reverseList (stringToCharacters s);
-      suffix = head l;
-      nums = tail l;
-    in elem suffix (["K" "M" "G" "T"] ++ digits)
-      && all (num: elem num digits) nums;
-
-  assertByteFormat = name: group: attr:
-    optional (attr ? ${name} && ! isByteFormat attr.${name})
-      "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT].";
-
-  hexChars = stringToCharacters "0123456789abcdefABCDEF";
-
-  isMacAddress = s: stringLength s == 17
-    && flip all (splitString ":" s) (bytes:
-      all (byte: elem byte hexChars) (stringToCharacters bytes)
-    );
-
-  assertMacAddress = name: group: attr:
-    optional (attr ? ${name} && ! isMacAddress attr.${name})
-      "Systemd ${group} field `${name}' must be a valid mac address.";
-
-  checkUnitConfig = group: checks: v:
-    let errors = concatMap (c: c group v) checks; in
-    if errors == [] then true
-      else builtins.trace (concatStringsSep "\n" errors) false;
-
   checkService = checkUnitConfig "Service" [
     (assertValueOneOf "Type" [
       "simple" "forking" "oneshot" "dbus" "notify" "idle"
@@ -91,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 4beab19d4b22..34eda7247cdd 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -69,6 +69,7 @@ let
       "systemd-journal-flush.service"
       "systemd-journal-gatewayd.socket"
       "systemd-journal-gatewayd.service"
+      "systemd-journald-audit.socket"
       "systemd-journald-dev-log.socket"
       "syslog.socket"
 
@@ -109,8 +110,6 @@ let
       "systemd-hibernate.service"
       "systemd-suspend.service"
       "systemd-hybrid-sleep.service"
-      "systemd-shutdownd.socket"
-      "systemd-shutdownd.service"
 
       # Reboot stuff.
       "reboot.target"
@@ -276,19 +275,6 @@ let
     };
   };
 
-  toOption = x:
-    if x == true then "true"
-    else if x == false then "false"
-    else toString x;
-
-  attrsToSection = as:
-    concatStrings (concatLists (mapAttrsToList (name: value:
-      map (x: ''
-          ${name}=${toOption x}
-        '')
-        (if isList value then value else [value]))
-        as));
-
   commonUnitText = def: ''
       [Unit]
       ${attrsToSection def.unitConfig}
@@ -369,11 +355,6 @@ let
         '';
     };
 
-  commonMatchText = def: ''
-      [Match]
-      ${attrsToSection def.matchConfig}
-    '';
-
 in
 
 {
@@ -463,6 +444,17 @@ in
       '';
     };
 
+    systemd.generators = mkOption {
+      type = types.attrsOf types.path;
+      default = {};
+      example = { "systemd-gpt-auto-generator" = "/dev/null"; };
+      description = ''
+        Definition of systemd generators.
+        For each <literal>NAME = VALUE</literal> pair of the attrSet, a link is generated from
+        <literal>/etc/systemd/system-generators/NAME</literal> to <literal>VALUE</literal>.
+      '';
+    };
+
     systemd.defaultUnit = mkOption {
       default = "multi-user.target";
       type = types.str;
@@ -509,7 +501,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.
@@ -619,20 +611,17 @@ in
 
     environment.systemPackages = [ systemd ];
 
-    environment.etc."systemd/system".source =
-      generateUnits "system" cfg.units upstreamSystemUnits upstreamSystemWants;
+    environment.etc = {
+      "systemd/system".source = generateUnits "system" cfg.units upstreamSystemUnits upstreamSystemWants;
 
-    environment.etc."systemd/user".source =
-      generateUnits "user" cfg.user.units upstreamUserUnits [];
+      "systemd/user".source = generateUnits "user" cfg.user.units upstreamUserUnits [];
 
-    environment.etc."systemd/system.conf".text =
-      ''
+      "systemd/system.conf".text = ''
         [Manager]
         ${config.systemd.extraConfig}
       '';
 
-    environment.etc."systemd/journald.conf".text =
-      ''
+      "systemd/journald.conf".text = ''
         [Journal]
         RateLimitInterval=${config.services.journald.rateLimitInterval}
         RateLimitBurst=${toString config.services.journald.rateLimitBurst}
@@ -643,29 +632,44 @@ in
         ${config.services.journald.extraConfig}
       '';
 
-    environment.etc."systemd/logind.conf".text =
-      ''
+      "systemd/logind.conf".text = ''
         [Login]
         ${config.services.logind.extraConfig}
       '';
 
-    environment.etc."systemd/sleep.conf".text =
-      ''
+      "systemd/sleep.conf".text = ''
         [Sleep]
       '';
 
+      "tmpfiles.d/systemd.conf".source = "${systemd}/example/tmpfiles.d/systemd.conf";
+      "tmpfiles.d/x11.conf".source = "${systemd}/example/tmpfiles.d/x11.conf";
+
+      "tmpfiles.d/nixos.conf".text = ''
+        # This file is created automatically and should not be modified.
+        # Please change the option ‘systemd.tmpfiles.rules’ instead.
+
+        ${concatStringsSep "\n" cfg.tmpfiles.rules}
+      '';
+    } // mapAttrs' (n: v: nameValuePair "systemd/system-generators/${n}" {"source"=v;}) cfg.generators;
+
     system.activationScripts.systemd = stringAfter [ "groups" ]
       ''
         mkdir -m 0755 -p /var/lib/udev
-        mkdir -p /var/log/journal
-        chmod 0755 /var/log/journal
 
-        # Make all journals readable to users in the wheel and adm
-        # groups, in addition to those in the systemd-journal group.
-        # Users can always read their own journals.
-        ${pkgs.acl.bin}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal || true
+        if ! [ -e /etc/machine-id ]; then
+          ${systemd}/bin/systemd-machine-id-setup
+        fi
+
+        # Keep a persistent journal. Note that systemd-tmpfiles will
+        # set proper ownership/permissions.
+        mkdir -m 0700 -p /var/log/journal
       '';
 
+    users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network;
+    users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network;
+    users.extraUsers.systemd-resolve.uid = config.ids.uids.systemd-resolve;
+    users.extraGroups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
+
     # Target for ‘charon send-keys’ to hook into.
     users.extraGroups.keys.gid = config.ids.gids.keys;
 
@@ -729,6 +733,14 @@ in
         })
         (filterAttrs (name: service: service.startAt != "") cfg.services);
 
+    # Generate timer units for all services that have a ‘startAt’ value.
+    systemd.user.timers =
+      mapAttrs (name: service:
+        { wantedBy = [ "timers.target" ];
+          timerConfig.OnCalendar = service.startAt;
+        })
+        (filterAttrs (name: service: service.startAt != "") cfg.user.services);
+
     systemd.sockets.systemd-journal-gatewayd.wantedBy =
       optional config.services.journald.enableHttpGateway "sockets.target";
 
@@ -740,24 +752,21 @@ in
         startSession = true;
       };
 
-    environment.etc."tmpfiles.d/x11.conf".source = "${systemd}/example/tmpfiles.d/x11.conf";
-
-    environment.etc."tmpfiles.d/nixos.conf".text =
-      ''
-        # This file is created automatically and should not be modified.
-        # Please change the option ‘systemd.tmpfiles.rules’ instead.
-
-        z /var/log/journal 2755 root systemd-journal - -
-        z /var/log/journal/%m 2755 root systemd-journal - -
-        z /var/log/journal/%m/* 0640 root systemd-journal - -
-
-        ${concatStringsSep "\n" cfg.tmpfiles.rules}
-      '';
-
+    # Some overrides to upstream units.
+    systemd.services."systemd-backlight@".restartIfChanged = false;
+    systemd.services."systemd-rfkill@".restartIfChanged = false;
     systemd.services."user@".restartIfChanged = false;
-
-    systemd.services.systemd-remount-fs.restartIfChanged = false;
     systemd.services.systemd-journal-flush.restartIfChanged = false;
+    systemd.services.systemd-random-seed.restartIfChanged = false;
+    systemd.services.systemd-remount-fs.restartIfChanged = false;
+    systemd.services.systemd-update-utmp.restartIfChanged = false;
+    systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
+    systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
+    systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
+
+    # Don't bother with certain units in containers.
+    systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container";
+    systemd.services.systemd-random-seed.unitConfig.ConditionVirtualization = "!container";
 
   };
 
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/encrypted-devices.nix b/nixos/modules/tasks/encrypted-devices.nix
index 0370e36fbec2..331531cee151 100644
--- a/nixos/modules/tasks/encrypted-devices.nix
+++ b/nixos/modules/tasks/encrypted-devices.nix
@@ -6,6 +6,7 @@ let
   fileSystems = attrValues config.fileSystems ++ config.swapDevices;
   encDevs = filter (dev: dev.encrypted.enable) fileSystems;
   keyedEncDevs = filter (dev: dev.encrypted.keyFile != null) encDevs;
+  keylessEncDevs = filter (dev: dev.encrypted.keyFile == null) encDevs;
   isIn = needle: haystack: filter (p: p == needle) haystack != [];
   anyEncrypted =
     fold (j: v: v || j.encrypted.enable) false encDevs;
@@ -22,22 +23,22 @@ let
       blkDev = mkOption {
         default = null;
         example = "/dev/sda1";
-        type = types.uniq (types.nullOr types.string);
+        type = types.nullOr types.str;
         description = "Location of the backing encrypted device.";
       };
 
       label = mkOption {
         default = null;
         example = "rootfs";
-        type = types.uniq (types.nullOr types.string);
-        description = "Label of the backing encrypted device.";
+        type = types.uniq (types.nullOr types.str);
+        description = "Label of the unlocked encrypted device. Set <literal>fileSystems.&lt;name?&gt;.device</literal> to <literal>/dev/mapper/&lt;label&gt;</literal> to mount the unlocked device.";
       };
 
       keyFile = mkOption {
         default = null;
         example = "/root/.swapkey";
-        type = types.uniq (types.nullOr types.string);
-        description = "File system location of keyfile.";
+        type = types.nullOr types.str;
+        description = "File system location of keyfile. This unlocks the drive after the root has been mounted to <literal>/mnt-root</literal>.";
       };
     };
   };
@@ -58,11 +59,11 @@ in
     boot.initrd = {
       luks = {
         devices =
-          map (dev: { name = dev.encrypted.label; device = dev.encrypted.blkDev; } ) encDevs;
+          map (dev: { name = dev.encrypted.label; device = dev.encrypted.blkDev; } ) keylessEncDevs;
         cryptoModules = [ "aes" "sha256" "sha1" "xts" ];
       };
       postMountCommands =
-        concatMapStrings (dev: "cryptsetup luksOpen --key-file ${dev.encrypted.keyFile} ${dev.encrypted.label};\n") keyedEncDevs;
+        concatMapStrings (dev: "cryptsetup luksOpen --key-file ${dev.encrypted.keyFile} ${dev.encrypted.blkDev} ${dev.encrypted.label};\n") keyedEncDevs;
     };
   };
 }
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index ce8d6079faac..9dd250f140ce 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -7,7 +7,7 @@ let
 
   fileSystems = attrValues config.fileSystems;
 
-  prioOption = prio: optionalString (prio !=null) " pri=${toString prio}";
+  prioOption = prio: optionalString (prio != null) " pri=${toString prio}";
 
   fileSystemOpts = { name, config, ... }: {
 
@@ -22,14 +22,14 @@ let
       device = mkOption {
         default = null;
         example = "/dev/sda";
-        type = types.uniq (types.nullOr types.string);
+        type = types.nullOr types.str;
         description = "Location of the device.";
       };
 
       label = mkOption {
         default = null;
         example = "root-partition";
-        type = types.uniq (types.nullOr types.string);
+        type = types.nullOr types.str;
         description = "Label of the device (if any).";
       };
 
@@ -41,9 +41,9 @@ let
       };
 
       options = mkOption {
-        default = "defaults,relatime";
+        default = "defaults";
         example = "data=journal";
-        type = types.commas;
+        type = types.commas; # FIXME: should be a list
         description = "Options used to mount the file system.";
       };
 
@@ -58,6 +58,17 @@ let
         '';
       };
 
+      autoResize = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          If set, the filesystem is grown to its maximum size before
+          being mounted. (This is typically the size of the containing
+          partition.) This is currently only supported for ext2/3/4
+          filesystems that are mounted during early boot.
+        '';
+      };
+
       noCheck = mkOption {
         default = false;
         type = types.bool;
@@ -69,6 +80,7 @@ let
     config = {
       mountPoint = mkDefault name;
       device = mkIf (config.fsType == "tmpfs") (mkDefault config.fsType);
+      options = mkIf config.autoResize "x-nixos.autoresize";
     };
 
   };
@@ -121,7 +133,7 @@ in
     boot.supportedFilesystems = mkOption {
       default = [ ];
       example = [ "btrfs" ];
-      type = types.listOf types.string;
+      type = types.listOf types.str;
       description = "Names of supported filesystem types.";
     };
 
@@ -141,7 +153,7 @@ in
 
     environment.etc.fstab.text =
       let
-        fsToSkipCheck = [ "none" "btrfs" "zfs" "tmpfs" "nfs" ];
+        fsToSkipCheck = [ "none" "btrfs" "zfs" "tmpfs" "nfs" "vboxsf" ];
         skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck;
       in ''
         # This is a generated file.  Do not edit!
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/filesystems/vboxsf.nix b/nixos/modules/tasks/filesystems/vboxsf.nix
new file mode 100644
index 000000000000..87f1984f084f
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/vboxsf.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "vboxsf") config.boot.initrd.supportedFilesystems;
+
+  package = pkgs.runCommand "mount.vboxsf" {} ''
+    mkdir -p $out/bin
+    cp ${pkgs.linuxPackages.virtualboxGuestAdditions}/bin/mount.vboxsf $out/bin
+  '';
+in
+
+{
+  config = mkIf (any (fs: fs == "vboxsf") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ package ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "vboxsf" ];
+
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix
index d4b10e9ed09e..675bd3d232a6 100644
--- a/nixos/modules/tasks/filesystems/zfs.nix
+++ b/nixos/modules/tasks/filesystems/zfs.nix
@@ -21,9 +21,9 @@ let
 
   kernel = config.boot.kernelPackages;
 
-  splKernelPkg = if cfgZfs.useGit then kernel.spl_git else kernel.spl;
-  zfsKernelPkg = if cfgZfs.useGit then kernel.zfs_git else kernel.zfs;
-  zfsUserPkg = if cfgZfs.useGit then pkgs.zfs_git else pkgs.zfs;
+  splKernelPkg = kernel.spl;
+  zfsKernelPkg = kernel.zfs;
+  zfsUserPkg = pkgs.zfs;
 
   autosnapPkg = pkgs.zfstools.override {
     zfs = zfsUserPkg;
@@ -53,16 +53,6 @@ in
 
   options = {
     boot.zfs = {
-      useGit = mkOption {
-        type = types.bool;
-        default = false;
-        example = true;
-        description = ''
-          Use the git version of the SPL and ZFS packages.
-          Note that these are unreleased versions, with less testing, and therefore
-          may be more unstable.
-        '';
-      };
 
       extraPools = mkOption {
         type = types.listOf types.str;
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-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
index 328d94cbb05c..d8b1592c36bb 100644
--- a/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -220,6 +220,45 @@ in
             '';
           });
 
+        createVswitchDevice = n: v: nameValuePair "${n}-netdev"
+          (let
+            managedInterfaces = filter (x: hasAttr x cfg.interfaces) v.interfaces;
+            managedInterfaceServices = concatMap (i: [ "network-addresses-${i}.service" "network-link-${i}.service" ]) managedInterfaces;
+            virtualInterfaces = filter (x: (hasAttr x cfg.interfaces) && cfg.interfaces.${x}.virtual) v.interfaces;
+            virtualInterfaceServices = concatMap (i: [ "${i}-netdev.service" ]) virtualInterfaces;
+            deps = map subsystemDevice v.interfaces;
+            ofRules = pkgs.writeText "vswitch-${n}-openFlowRules" v.openFlowRules;
+          in
+          { description = "Open vSwitch Interface ${n}";
+            wantedBy = [ "network.target" "vswitchd.service" (subsystemDevice n) ];
+            requires = optionals v.bindInterfaces (deps ++ managedInterfaceServices ++ virtualInterfaceServices);
+            requiredBy = optionals v.bindInterfaces (managedInterfaceServices ++ virtualInterfaceServices);
+            bindsTo = deps ++ [ "vswitchd.service" ];
+            partOf = [ "vswitchd.service" ];
+            after = [ "network-pre.target" "vswitchd.service" ] ++ deps ++ managedInterfaceServices ++ virtualInterfaceServices;
+            before = [ "network-interfaces.target" (subsystemDevice n) ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute config.virtualisation.vswitch.package ];
+            script = ''
+              echo "Removing old Open vSwitch ${n}..."
+              ovs-vsctl --if-exists del-br ${n}
+
+              echo "Adding Open vSwitch ${n}..."
+              ovs-vsctl -- add-br ${n} ${concatMapStrings (i: " -- add-port ${n} ${i}") v.interfaces} \
+                ${concatMapStrings (x: " -- set-controller ${n} " + x)  v.controllers} \
+                ${concatMapStrings (x: " -- " + x) (splitString "\n" v.extraOvsctlCmds)}
+
+              echo "Adding OpenFlow rules for Open vSwitch ${n}..."
+              ovs-ofctl add-flows ${n} ${ofRules}
+            '';
+            postStop = ''
+              ip link set ${n} down || true
+              ovs-ofctl del-flows ${n} || true
+              ovs-vsctl --if-exists del-br ${n}
+            '';
+          });
+
         createBondDevice = n: v: nameValuePair "${n}-netdev"
           (let
             deps = map subsystemDevice v.interfaces;
@@ -335,6 +374,7 @@ in
            map configureAddrs interfaces ++
            map createTunDevice (filter (i: i.virtual) interfaces))
          // mapAttrs' createBridgeDevice cfg.bridges
+         // mapAttrs' createVswitchDevice cfg.vswitches
          // mapAttrs' createBondDevice cfg.bonds
          // mapAttrs' createMacvlanDevice cfg.macvlans
          // mapAttrs' createSitDevice cfg.sits
diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix
index 8223c5a4941e..301ee43fd0e5 100644
--- a/nixos/modules/tasks/network-interfaces-systemd.nix
+++ b/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -35,6 +35,9 @@ in
     assertions = [ {
       assertion = cfg.defaultGatewayWindowSize == null;
       message = "networking.defaultGatewayWindowSize is not supported by networkd.";
+    } {
+      assertion = cfg.vswitches == {};
+      message = "networking.vswichtes are not supported by networkd.";
     } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: {
       assertion = !rstp;
       message = "networking.bridges.${n}.rstp is not supported by networkd.";
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 71a721abba21..9ffede48bf52 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -12,7 +12,8 @@ let
   hasBonds = cfg.bonds != { };
 
   slaves = concatMap (i: i.interfaces) (attrValues cfg.bonds)
-    ++ concatMap (i: i.interfaces) (attrValues cfg.bridges);
+    ++ concatMap (i: i.interfaces) (attrValues cfg.bridges)
+    ++ concatMap (i: i.interfaces) (attrValues cfg.vswitches);
 
   slaveIfs = map (i: cfg.interfaces.${i}) (filter (i: cfg.interfaces ? ${i}) slaves);
 
@@ -45,6 +46,51 @@ let
     '';
   });
 
+  # Collect all interfaces that are defined for a device
+  # as device:interface key:value pairs.
+  wlanDeviceInterfaces =
+    let
+      allDevices = unique (mapAttrsToList (_: v: v.device) cfg.wlanInterfaces);
+      interfacesOfDevice = d: filterAttrs (_: v: v.device == d) cfg.wlanInterfaces;
+    in
+      genAttrs allDevices (d: interfacesOfDevice d);
+
+  # Convert device:interface key:value pairs into a list, and if it exists,
+  # place the interface which is named after the device at the beginning.
+  wlanListDeviceFirst = device: interfaces:
+    if hasAttr device interfaces
+    then [{"${device}"=interfaces.device; _iName=device;}] ++ mapAttrsToList (n: v: v//{_iName=n;}) (filterAttrs (n: _: n!=device) interfaces)
+    else mapAttrsToList (n: v: v // {_iName = n;}) interfaces;
+
+  # udev script that configures a physical wlan device and adds virtual interfaces
+  wlanDeviceUdevScript = device: interfaceList: pkgs.writeScript "wlan-${device}-udev-script" ''
+    #!${pkgs.stdenv.shell}
+
+    # Change the wireless phy device to a predictable name.
+    if [ -e "/sys/class/net/${device}/phy80211/name" ]; then
+      ${pkgs.iw}/bin/iw phy `${pkgs.coreutils}/bin/cat /sys/class/net/${device}/phy80211/name` set name ${device} || true
+    fi
+
+    # Crate new, virtual interfaces and configure them at the same time
+    ${flip concatMapStrings (drop 1 interfaceList) (i: ''
+    ${pkgs.iw}/bin/iw dev ${device} interface add ${i._iName} type ${i.type} \
+      ${optionalString (i.type == "mesh" && i.meshID != null) "mesh_id ${i.meshID}"} \
+      ${optionalString (i.type == "monitor" && i.flags != null) "flags ${i.flags}"} \
+      ${optionalString (i.type == "managed" && i.fourAddr != null) "4addr ${if i.fourAddr then "on" else "off"}"} \
+      ${optionalString (i.mac != null) "addr ${i.mac}"}
+    '')}
+
+    # Reconfigure and rename the default interface that already exists
+    ${flip concatMapStrings (take 1 interfaceList) (i: ''
+      ${pkgs.iw}/bin/iw dev ${device} set type ${i.type}
+      ${optionalString (i.type == "mesh" && i.meshID != null) "${pkgs.iw}/bin/iw dev ${device} set meshid ${i.meshID}"}
+      ${optionalString (i.type == "monitor" && i.flags != null) "${pkgs.iw}/bin/iw dev ${device} set monitor ${i.flags}"}
+      ${optionalString (i.type == "managed" && i.fourAddr != null) "${pkgs.iw}/bin/iw dev ${device} set 4addr ${if i.fourAddr then "on" else "off"}"}
+      ${optionalString (i.mac != null) "${pkgs.iproute}/bin/ip link set dev ${device} address ${i.mac}"}
+      ${optionalString (device != i._iName) "${pkgs.iproute}/bin/ip link set dev ${device} name ${i._iName}"}
+    '')}
+  '';
+
   # We must escape interfaces due to the systemd interpretation
   subsystemDevice = interface:
     "sys-subsystem-net-devices-${escapeSystemdPath interface}.device";
@@ -371,6 +417,81 @@ in
       options = [ interfaceOpts ];
     };
 
+    networking.vswitches = mkOption {
+      default = { };
+      example =
+        { vs0.interfaces = [ "eth0" "eth1" ];
+          vs1.interfaces = [ "eth2" "wlan0" ];
+        };
+      description =
+        ''
+          This option allows you to define Open vSwitches that connect
+          physical networks together.  The value of this option is an
+          attribute set.  Each attribute specifies a vswitch, with the
+          attribute name specifying the name of the vswitch's network
+          interface.
+        '';
+
+      type = types.attrsOf types.optionSet;
+
+      options = {
+
+        interfaces = mkOption {
+          example = [ "eth0" "eth1" ];
+          type = types.listOf types.str;
+          description =
+            "The physical network interfaces connected by the vSwitch.";
+        };
+
+        bindInterfaces = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            If true, then the interfaces of the vSwitch are brought 'up' and especially
+            also 'down' together with the vSwitch. That requires that every interfaces
+            is configured as a systemd network services.
+          '';
+        };
+
+        controllers = mkOption {
+          type = types.listOf types.str;
+          default = [];
+          example = [ "ptcp:6653:[::1]" ];
+          description = ''
+            Specify the controller targets. For the allowed options see <literal>man 8 ovs-vsctl</literal>.
+          '';
+        };
+
+        openFlowRules = mkOption {
+          type = types.lines;
+          default = "";
+          example = ''
+            actions=normal
+          '';
+          description = ''
+            OpenFlow rules to insert into the Open vSwitch. All <literal>openFlowRules</literal> are
+            loaded with <literal>ovs-ofctl</literal> within one atomic operation.
+          '';
+        };
+
+        extraOvsctlCmds = mkOption {
+          type = types.lines;
+          default = "";
+          example = ''
+            set-fail-mode <switch_name> secure
+            set Bridge <switch_name> stp_enable=true
+          '';
+          description = ''
+            Commands to manipulate the Open vSwitch database. Every line executed with <literal>ovs-vsctl</literal>.
+            All commands are bundled together with the operations for adding the interfaces
+            into one atomic operation.
+          '';
+        };
+
+      };
+
+    };
+
     networking.bridges = mkOption {
       default = { };
       example =
@@ -392,7 +513,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.";
         };
@@ -499,7 +620,7 @@ in
 
         interface = mkOption {
           example = "enp4s0";
-          type = types.string;
+          type = types.str;
           description = "The interface the macvlan will transmit packets through.";
         };
 
@@ -605,13 +726,117 @@ in
 
         interface = mkOption {
           example = "enp4s0";
-          type = types.string;
+          type = types.str;
           description = "The interface the vlan will transmit packets through.";
         };
 
       };
     };
 
+    networking.wlanInterfaces = mkOption {
+      default = { };
+      example = {
+        "wlan-station0" = {
+            device = "wlp6s0";
+        };
+        "wlan-adhoc0" = {
+            type = "ibss";
+            device = "wlp6s0";
+            mac = "02:00:00:00:00:01";
+        };
+        "wlan-p2p0" = {
+            device = "wlp6s0";
+            mac = "02:00:00:00:00:02";
+        };
+        "wlan-ap0" = {
+            device = "wlp6s0";
+            mac = "02:00:00:00:00:03";
+        };
+      };
+      description =
+        ''
+          Creating multiple WLAN interfaces on top of one physical WLAN device (NIC).
+
+          The name of the WLAN interface corresponds to the name of the attribute.
+          A NIC is referenced by the persistent device name of the WLAN interface that
+          <literal>udev</literal> assigns to a NIC by default.
+          If a NIC supports multiple WLAN interfaces, then the one NIC can be used as
+          <literal>device</literal> for multiple WLAN interfaces.
+          If a NIC is used for creating WLAN interfaces, then the default WLAN interface
+          with a persistent device name form <literal>udev</literal> is not created.
+          A WLAN interface with the persistent name assigned from <literal>udev</literal>
+          would have to be created explicitly.
+        '';
+
+      type = types.attrsOf types.optionSet;
+
+      options = {
+
+        device = mkOption {
+          type = types.string;
+          example = "wlp6s0";
+          description = "The name of the underlying hardware WLAN device as assigned by <literal>udev</literal>.";
+        };
+
+        type = mkOption {
+          type = types.string;
+          default = "managed";
+          example = "ibss";
+          description = ''
+            The type of the WLAN interface. The type has to be either <literal>managed</literal>,
+            <literal>ibss</literal>, <literal>monitor</literal>, <literal>mesh</literal> or <literal>wds</literal>.
+            Also, the type has to be supported by the underlying hardware of the device.
+          '';
+        };
+
+        meshID = mkOption {
+          type = types.nullOr types.string;
+          default = null;
+          description = "MeshID of interface with type <literal>mesh</literal>.";
+        };
+
+        flags = mkOption {
+          type = types.nullOr types.string;
+          default = null;
+          example = "control";
+          description = ''
+            Flags for interface of type <literal>monitor</literal>. The valid flags are:
+            none:     no special flags
+            fcsfail:  show frames with FCS errors
+            control:  show control frames
+            otherbss: show frames from other BSSes
+            cook:     use cooked mode
+            active:   use active mode (ACK incoming unicast packets)
+          '';
+        };
+
+        fourAddr = mkOption {
+          type = types.nullOr types.bool;
+          default = null;
+          description = "Whether to enable <literal>4-address mode</literal> with type <literal>managed</literal>.";
+        };
+
+        mac = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "02:00:00:00:00:01";
+          description = ''
+            MAC address to use for the device. If <literal>null</literal>, then the MAC of the
+            underlying hardware WLAN device is used.
+
+            INFO: Locally administered MAC addresses are of the form:
+            <itemizedlist>
+            <listitem><para>x2:xx:xx:xx:xx:xx</para></listitem>
+            <listitem><para>x6:xx:xx:xx:xx:xx</para></listitem>
+            <listitem><para>xA:xx:xx:xx:xx:xx</para></listitem>
+            <listitem><para>xE:xx:xx:xx:xx:xx</para></listitem>
+            </itemizedlist>
+          '';
+        };
+
+      };
+    };
+
     networking.useDHCP = mkOption {
       type = types.bool;
       default = true;
@@ -708,11 +933,14 @@ in
         pkgs.iproute
         pkgs.iputils
         pkgs.nettools
-        pkgs.wirelesstools
+        pkgs.openresolv
+      ]
+      ++ optionals (!config.boot.isContainer) [
+        pkgs.wirelesstools # FIXME: obsolete?
         pkgs.iw
         pkgs.rfkill
-        pkgs.openresolv
-      ] ++ bridgeStp;
+      ]
+      ++ bridgeStp;
 
     systemd.targets."network-interfaces" =
       { description = "All Network Interfaces";
@@ -763,6 +991,27 @@ in
 
     services.mstpd = mkIf needsMstpd { enable = true; };
 
+    virtualisation.vswitch = mkIf (cfg.vswitches != { }) { enable = true; };
+
+    services.udev.packages = mkIf (cfg.wlanInterfaces != {}) [
+      (pkgs.writeTextFile {
+        name = "99-zzz-wlanInterfaces-last.rules";
+        destination = "/etc/udev/rules.d/99-zzz-wlanInterfaces-last.rules";
+        text = ''
+          # If persistent udev device name is not used for an interface, then do not
+          # call systemd for that udev device name and only execute the script that
+          # modifies or prepares the WLAN interfaces. All other commands that would
+          # otherwise be executed when the udev device is added, like, e.g., the calling
+          # of systemd-sysctl or the activation of wpa_supplicant is disabled when the
+          # persistend udev device name is not usef for an interface.
+          ${flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) (device:
+          let script = wlanDeviceUdevScript device (wlanListDeviceFirst device wlanDeviceInterfaces."${device}"); in
+          if hasAttr device cfg.wlanInterfaces
+          then ''ACTION=="add", SUBSYSTEM=="net", NAME=="${device}", ENV{DEVTYPE}=="wlan", RUN+="${script}"''
+          else ''ACTION=="add", SUBSYSTEM=="net", NAME=="${device}", ENV{DEVTYPE}=="wlan", NAME="", TAG-="systemd", RUN:="${script}"'')}
+        '';
+      }) ];
+
   };
 
 }
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-config.nix b/nixos/modules/virtualisation/amazon-config.nix
deleted file mode 100644
index 809cdb4d108e..000000000000
--- a/nixos/modules/virtualisation/amazon-config.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  imports = [ <nixpkgs/nixos/modules/virtualisation/amazon-image.nix> ];
-}
diff --git a/nixos/modules/virtualisation/amazon-grow-partition.nix b/nixos/modules/virtualisation/amazon-grow-partition.nix
new file mode 100644
index 000000000000..44a9fa93e7ec
--- /dev/null
+++ b/nixos/modules/virtualisation/amazon-grow-partition.nix
@@ -0,0 +1,50 @@
+# This module automatically grows the root partition on Amazon EC2 HVM
+# instances. This allows an instance to be created with a bigger root
+# filesystem than provided by the AMI.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  growpart = pkgs.stdenv.mkDerivation {
+    name = "growpart";
+    src = pkgs.fetchurl {
+      url = "https://launchpad.net/cloud-utils/trunk/0.27/+download/cloud-utils-0.27.tar.gz";
+      sha256 = "16shlmg36lidp614km41y6qk3xccil02f5n3r4wf6d1zr5n4v8vd";
+    };
+    patches = [ ./growpart-util-linux-2.26.patch ];
+    buildPhase = ''
+      cp bin/growpart $out
+      sed -i 's|awk|gawk|' $out
+      sed -i 's|sed|gnused|' $out
+    '';
+    dontInstall = true;
+    dontPatchShebangs = true;
+  };
+
+in
+
+{
+
+  config = mkIf config.ec2.hvm {
+
+    boot.initrd.extraUtilsCommands = ''
+      copy_bin_and_libs ${pkgs.gawk}/bin/gawk
+      copy_bin_and_libs ${pkgs.gnused}/bin/sed
+      copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
+      cp -v ${growpart} $out/bin/growpart
+      ln -s sed $out/bin/gnused
+    '';
+
+    boot.initrd.postDeviceCommands = ''
+      if [ -e /dev/xvda ] && [ -e /dev/xvda1 ]; then
+        TMPDIR=/run sh $(type -P growpart) /dev/xvda 1
+        udevadm settle
+      fi
+    '';
+
+  };
+
+}
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index 600a29f31bc5..bf2364a0459d 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -1,105 +1,40 @@
+# Configuration for Amazon EC2 instances. (Note that this file is a
+# misnomer - it should be "amazon-config.nix" or so, not
+# "amazon-image.nix", since it's used not only to build images but
+# also to reconfigure instances. However, we can't rename it because
+# existing "configuration.nix" files on EC2 instances refer to it.)
+
 { config, lib, pkgs, ... }:
 
 with lib;
-let
-  cfg = config.ec2;
-in
+
+let cfg = config.ec2; in
+
 {
-  imports = [ ../profiles/headless.nix ./ec2-data.nix ];
+  imports = [ ../profiles/headless.nix ./ec2-data.nix ./amazon-grow-partition.nix ];
 
   config = {
-    system.build.amazonImage =
-      pkgs.vmTools.runInLinuxVM (
-        pkgs.runCommand "amazon-image"
-          { preVM =
-              ''
-                mkdir $out
-                diskImage=$out/nixos.img
-                ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "8G"
-                mv closure xchg/
-              '';
-            buildInputs = [ pkgs.utillinux pkgs.perl ];
-            exportReferencesGraph =
-              [ "closure" config.system.build.toplevel ];
-          }
-          ''
-            ${if cfg.hvm then ''
-              # Create a single / partition.
-              ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
-              ${pkgs.parted}/sbin/parted /dev/vda -- mkpart primary ext2 1M -1s
-              . /sys/class/block/vda1/uevent
-              mknod /dev/vda1 b $MAJOR $MINOR
-
-              # Create an empty filesystem and mount it.
-              ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1
-              ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1
-              mkdir /mnt
-              mount /dev/vda1 /mnt
-            '' else ''
-              # Create an empty filesystem and mount it.
-              ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda
-              ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda
-              mkdir /mnt
-              mount /dev/vda /mnt
-            ''}
-
-            # The initrd expects these directories to exist.
-            mkdir /mnt/dev /mnt/proc /mnt/sys
-
-            mount -o bind /proc /mnt/proc
-            mount -o bind /dev /mnt/dev
-            mount -o bind /sys /mnt/sys
-
-            # Copy all paths in the closure to the filesystem.
-            storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
-
-            mkdir -p /mnt/nix/store
-            echo "copying everything (will take a while)..."
-            cp -prd $storePaths /mnt/nix/store/
-
-            # 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 --option build-users-group ""
-
-            # Create the system profile to allow nixos-rebuild to work.
-            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 ${./amazon-config.nix} /mnt/etc/nixos/configuration.nix
-
-            # Generate the GRUB menu.
-            ln -s vda /dev/xvda
-            chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
-
-            umount /mnt/proc /mnt/dev /mnt/sys
-            umount /mnt
-          ''
-      );
-
-    fileSystems."/".device = "/dev/disk/by-label/nixos";
+
+    fileSystems."/" = {
+      device = "/dev/disk/by-label/nixos";
+      autoResize = true;
+    };
 
     boot.initrd.kernelModules = [ "xen-blkfront" ];
     boot.kernelModules = [ "xen-netfront" ];
+    boot.kernelParams = mkIf cfg.hvm [ "console=ttyS0" ];
 
     # Prevent the nouveau kernel module from being loaded, as it
     # interferes with the nvidia/nvidia-uvm modules needed for CUDA.
-    boot.blacklistedKernelModules = [ "nouveau" ];
+    # Also blacklist xen_fbfront to prevent a 30 second delay during
+    # boot.
+    boot.blacklistedKernelModules = [ "nouveau" "xen_fbfront" ];
 
     # Generate a GRUB menu.  Amazon's pv-grub uses this to boot our kernel/initrd.
     boot.loader.grub.version = if cfg.hvm then 2 else 1;
     boot.loader.grub.device = if cfg.hvm then "/dev/xvda" else "nodev";
     boot.loader.grub.timeout = 0;
-    boot.loader.grub.extraPerEntryConfig = "root (hd0${lib.optionalString cfg.hvm ",0"})";
+    boot.loader.grub.extraPerEntryConfig = mkIf (!cfg.hvm) "root (hd0)";
 
     boot.initrd.postDeviceCommands =
       ''
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/azure-common.nix b/nixos/modules/virtualisation/azure-common.nix
new file mode 100644
index 000000000000..47022c6887c3
--- /dev/null
+++ b/nixos/modules/virtualisation/azure-common.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+{
+  imports = [ ../profiles/headless.nix ];
+
+  boot.kernelParams = [ "console=ttyS0" "earlyprintk=ttyS0" "rootdelay=300" "panic=1" "boot.panic_on_fail" ];
+  boot.initrd.kernelModules = [ "hv_vmbus" "hv_netvsc" "hv_utils" "hv_storvsc" ];
+
+  # Generate a GRUB menu. 
+  boot.loader.grub.device = "/dev/sda";
+  boot.loader.grub.version = 2;
+  boot.loader.grub.timeout = 0;
+
+  # Don't put old configurations in the GRUB menu.  The user has no
+  # way to select them anyway.
+  boot.loader.grub.configurationLimit = 0;
+
+  fileSystems."/".device = "/dev/disk/by-label/nixos";
+
+  # Allow root logins only using the SSH key that the user specified
+  # at instance creation time, ping client connections to avoid timeouts
+  services.openssh.enable = true;
+  services.openssh.permitRootLogin = "without-password";
+  services.openssh.extraConfig = ''
+    ClientAliveInterval 180
+  '';
+
+  # Force getting the hostname from Azure
+  networking.hostName = mkDefault "";
+
+  # Always include cryptsetup so that NixOps can use it.
+  # sg_scan is needed to finalize disk removal on older kernels
+  environment.systemPackages = [ pkgs.cryptsetup pkgs.sg3_utils ];
+
+  networking.usePredictableInterfaceNames = false;
+
+  services.udev.extraRules = ''
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:0", ATTR{removable}=="0", SYMLINK+="disk/by-lun/0",
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:1", ATTR{removable}=="0", SYMLINK+="disk/by-lun/1",
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:2", ATTR{removable}=="0", SYMLINK+="disk/by-lun/2"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:3", ATTR{removable}=="0", SYMLINK+="disk/by-lun/3"
+
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:4", ATTR{removable}=="0", SYMLINK+="disk/by-lun/4"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:5", ATTR{removable}=="0", SYMLINK+="disk/by-lun/5"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:6", ATTR{removable}=="0", SYMLINK+="disk/by-lun/6"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:7", ATTR{removable}=="0", SYMLINK+="disk/by-lun/7"
+
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:8", ATTR{removable}=="0", SYMLINK+="disk/by-lun/8"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:9", ATTR{removable}=="0", SYMLINK+="disk/by-lun/9"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:10", ATTR{removable}=="0", SYMLINK+="disk/by-lun/10"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:11", ATTR{removable}=="0", SYMLINK+="disk/by-lun/11"
+
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:12", ATTR{removable}=="0", SYMLINK+="disk/by-lun/12"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:13", ATTR{removable}=="0", SYMLINK+="disk/by-lun/13"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:14", ATTR{removable}=="0", SYMLINK+="disk/by-lun/14"
+    ENV{DEVTYPE}=="disk", KERNEL!="sda" SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNELS=="?:0:0:15", ATTR{removable}=="0", SYMLINK+="disk/by-lun/15"
+
+  '';
+
+}
diff --git a/nixos/modules/virtualisation/azure-image.nix b/nixos/modules/virtualisation/azure-image.nix
index ab5a9c51fa5b..1013396c0498 100644
--- a/nixos/modules/virtualisation/azure-image.nix
+++ b/nixos/modules/virtualisation/azure-image.nix
@@ -5,8 +5,6 @@ let
   diskSize = "4096";
 in
 {
-  imports = [ ../profiles/headless.nix ];
-
   system.build.azureImage =
     pkgs.vmTools.runInLinuxVM (
       pkgs.runCommand "azure-image"
@@ -24,12 +22,11 @@ in
 
           postVM =
             ''
-              echo Converting
               mkdir -p $out
               ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vpc $diskImage $out/disk.vhd
               rm $diskImage
             '';
-          diskImageBase = "nixos-${config.system.nixosVersion}-${pkgs.stdenv.system}.raw";
+          diskImageBase = "nixos-image-${config.system.nixosVersion}-${pkgs.stdenv.system}.raw";
           buildInputs = [ pkgs.utillinux pkgs.perl ];
           exportReferencesGraph =
             [ "closure" config.system.build.toplevel ];
@@ -93,34 +90,11 @@ in
         ''
     );
 
-  fileSystems."/".device = "/dev/disk/by-label/nixos";
+  imports = [ ./azure-common.nix ];
 
   # Azure metadata is available as a CD-ROM drive.
   fileSystems."/metadata".device = "/dev/sr0";
 
-  boot.kernelParams = [ "console=ttyS0" "earlyprintk=ttyS0" "rootdelay=300" "panic=1" "boot.panic_on_fail" ];
-  boot.initrd.kernelModules = [ "hv_vmbus" "hv_netvsc" "hv_utils" "hv_storvsc" ];
-
-  # Generate a GRUB menu. 
-  boot.loader.grub.device = "/dev/sda";
-  boot.loader.grub.version = 2;
-  boot.loader.grub.timeout = 0;
-
-  # Don't put old configurations in the GRUB menu.  The user has no
-  # way to select them anyway.
-  boot.loader.grub.configurationLimit = 0;
-
-  # Allow root logins only using the SSH key that the user specified
-  # at instance creation time.
-  services.openssh.enable = true;
-  services.openssh.permitRootLogin = "without-password";
-
-  # Force getting the hostname from Azure
-  networking.hostName = mkDefault "";
-
-  # Always include cryptsetup so that NixOps can use it.
-  environment.systemPackages = [ pkgs.cryptsetup ];
-
   systemd.services.fetch-ssh-keys =
     { description = "Fetch host keys and authorized_keys for root user";
 
@@ -157,8 +131,4 @@ in
       serviceConfig.StandardOutput = "journal+console";
      };
 
-  networking.usePredictableInterfaceNames = false;
-
-  #users.extraUsers.root.openssh.authorizedKeys.keys = [ (builtins.readFile <ssh-pub-key>) ];
-
 }
diff --git a/nixos/modules/virtualisation/brightbox-config.nix b/nixos/modules/virtualisation/brightbox-config.nix
new file mode 100644
index 000000000000..528ffecc0bf2
--- /dev/null
+++ b/nixos/modules/virtualisation/brightbox-config.nix
@@ -0,0 +1,5 @@
+{ config, pkgs, modulesPath, ... }:
+
+{
+  imports = [ "${modulesPath}/virtualisation/brightbox-image.nix" ];
+}
diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix
new file mode 100644
index 000000000000..0eb46d39b521
--- /dev/null
+++ b/nixos/modules/virtualisation/brightbox-image.nix
@@ -0,0 +1,166 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  diskSize = "20G";
+in
+{
+  imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ];
+
+  system.build.brightboxImage =
+    pkgs.vmTools.runInLinuxVM (
+      pkgs.runCommand "brightbox-image"
+        { preVM =
+            ''
+              mkdir $out
+              diskImage=$out/$diskImageBase
+              truncate $diskImage --size ${diskSize}
+              mv closure xchg/
+            '';
+
+          postVM =
+            ''
+              PATH=$PATH:${pkgs.gnutar}/bin:${pkgs.gzip}/bin
+              pushd $out
+              ${pkgs.qemu_kvm}/bin/qemu-img convert -c -O qcow2 $diskImageBase nixos.qcow2
+              rm $diskImageBase
+              popd
+            '';
+          diskImageBase = "nixos-image-${config.system.nixosVersion}-${pkgs.stdenv.system}.raw";
+          buildInputs = [ pkgs.utillinux pkgs.perl ];
+          exportReferencesGraph =
+            [ "closure" config.system.build.toplevel ];
+        }
+        ''
+          # Create partition table
+          ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
+          ${pkgs.parted}/sbin/parted /dev/vda mkpart primary ext4 1 ${diskSize}
+          ${pkgs.parted}/sbin/parted /dev/vda print
+          . /sys/class/block/vda1/uevent
+          mknod /dev/vda1 b $MAJOR $MINOR
+
+          # Create an empty filesystem and mount it.
+          ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1
+          ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1
+
+          mkdir /mnt
+          mount /dev/vda1 /mnt
+
+          # The initrd expects these directories to exist.
+          mkdir /mnt/dev /mnt/proc /mnt/sys
+
+          mount --bind /proc /mnt/proc
+          mount --bind /dev /mnt/dev
+          mount --bind /sys /mnt/sys
+
+          # Copy all paths in the closure to the filesystem.
+          storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
+
+          mkdir -p /mnt/nix/store
+          echo "copying everything (will take a while)..."
+          cp -prd $storePaths /mnt/nix/store/
+
+          # 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 --option build-users-group ""
+
+          # Create the system profile to allow nixos-rebuild to work.
+          chroot /mnt ${config.nix.package}/bin/nix-env \
+              -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel} \
+              --option build-users-group ""
+
+          # `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 /mnt/boot/grub
+          cp ${./brightbox-config.nix} /mnt/etc/nixos/configuration.nix
+
+          # Generate the GRUB menu.
+          ln -s vda /dev/sda
+          chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
+
+          umount /mnt/proc /mnt/dev /mnt/sys
+          umount /mnt
+        ''
+    );
+
+  fileSystems."/".label = "nixos";
+
+  # Generate a GRUB menu.  Amazon's pv-grub uses this to boot our kernel/initrd.
+  boot.loader.grub.device = "/dev/vda";
+  boot.loader.grub.timeout = 0;
+
+  # Don't put old configurations in the GRUB menu.  The user has no
+  # way to select them anyway.
+  boot.loader.grub.configurationLimit = 0;
+
+  # Allow root logins only using the SSH key that the user specified
+  # at instance creation time.
+  services.openssh.enable = true;
+  services.openssh.permitRootLogin = "without-password";
+
+  # Force getting the hostname from Google Compute.
+  networking.hostName = mkDefault "";
+
+  # Always include cryptsetup so that NixOps can use it.
+  environment.systemPackages = [ pkgs.cryptsetup ];
+
+  systemd.services."fetch-ec2-data" =
+    { description = "Fetch EC2 Data";
+
+      wantedBy = [ "multi-user.target" "sshd.service" ];
+      before = [ "sshd.service" ];
+      wants = [ "ip-up.target" ];
+      after = [ "ip-up.target" ];
+
+      path = [ pkgs.wget pkgs.iproute ];
+
+      script =
+        ''
+          wget="wget -q --retry-connrefused -O -"
+
+          ${optionalString (config.networking.hostName == "") ''
+            echo "setting host name..."
+            ${pkgs.nettools}/bin/hostname $($wget http://169.254.169.254/latest/meta-data/hostname)
+          ''}
+
+          # Don't download the SSH key if it has already been injected
+          # into the image (a Nova feature).
+          if ! [ -e /root/.ssh/authorized_keys ]; then
+              echo "obtaining SSH key..."
+              mkdir -m 0700 -p /root/.ssh
+              $wget http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /root/key.pub
+              if [ $? -eq 0 -a -e /root/key.pub ]; then
+                  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
+                  rm -f /root/key.pub
+              fi
+          fi
+
+          # Extract the intended SSH host key for this machine from
+          # the supplied user data, if available.  Otherwise sshd will
+          # generate one normally.
+          $wget http://169.254.169.254/2011-01-01/user-data > /root/user-data || true
+          key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' /root/user-data)"
+          key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' /root/user-data)"
+          if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then
+              mkdir -m 0755 -p /etc/ssh
+              (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key)
+              echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub
+          fi
+        '';
+
+      serviceConfig.Type = "oneshot";
+      serviceConfig.RemainAfterExit = true;
+    };
+
+}
diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix
index 67047541102c..c210c8d5f25e 100644
--- a/nixos/modules/virtualisation/container-config.nix
+++ b/nixos/modules/virtualisation/container-config.nix
@@ -19,10 +19,6 @@ with lib;
     # Shut up warnings about not having a boot loader.
     system.build.installBootLoader = "${pkgs.coreutils}/bin/true";
 
-    systemd.services.systemd-remount-fs.enable = false;
-
-    systemd.services.systemd-random-seed.enable = false;
-
   };
 
 }
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index da39dda85353..02cf1fe46a55 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -12,6 +12,12 @@ let
     perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
     su = "${pkgs.shadow.su}/bin/su";
     inherit (pkgs) utillinux;
+
+    postInstall = ''
+      t=$out/etc/bash_completion.d
+      mkdir -p $t
+      cp ${./nixos-container-completion.sh} $t/nixos-container
+    '';
   };
 
   # The container's init script, a small wrapper around the regular
@@ -102,7 +108,7 @@ in
             };
 
             hostAddress = mkOption {
-              type = types.nullOr types.string;
+              type = types.nullOr types.str;
               default = null;
               example = "10.231.136.1";
               description = ''
@@ -111,7 +117,7 @@ in
             };
 
             localAddress = mkOption {
-              type = types.nullOr types.string;
+              type = types.nullOr types.str;
               default = null;
               example = "10.231.136.2";
               description = ''
@@ -120,6 +126,15 @@ in
               '';
             };
 
+            interfaces = mkOption {
+              type = types.listOf types.string;
+              default = [];
+              example = [ "eth1" "eth2" ];
+              description = ''
+                The list of interfaces to be moved into the container.
+              '';
+            };
+
             autoStart = mkOption {
               type = types.bool;
               default = false;
@@ -218,6 +233,10 @@ in
               extraFlags+=" --network-veth"
             fi
 
+            for iface in $INTERFACES; do
+              extraFlags+=" --network-interface=$iface"
+            done
+
             for iface in $MACVLANS; do
               extraFlags+=" --network-macvlan=$iface"
             done
@@ -286,7 +305,7 @@ in
             ''
               #! ${pkgs.stdenv.shell} -e
               ${nixos-container}/bin/nixos-container run "$INSTANCE" -- \
-                bash --login -c "/nix/var/nix/profiles/system/bin/switch-to-configuration test"
+                bash --login -c "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/bin/switch-to-configuration test"
             '';
 
           SyslogIdentifier = "container %i";
@@ -331,6 +350,7 @@ in
                 LOCAL_ADDRESS=${cfg.localAddress}
               ''}
             ''}
+             INTERFACES="${toString cfg.interfaces}"
            ${optionalString cfg.autoStart ''
              AUTO_START=1
            ''}
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index 5be76b2682f5..0115b972e80d 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -43,9 +43,20 @@ in
             in future.  So set this option explicitly to false if you wish.
           '';
       };
+    storageDriver =
+      mkOption {
+        type = types.enum ["aufs" "btrfs" "devicemapper" "overlay" "zfs"];
+        description =
+          ''
+            This option determines which Docker storage driver to use.
+            It is required but lacks a default value as its most
+            suitable value will depend the filesystems available on the
+            host.
+          '';
+      };
     extraOptions =
       mkOption {
-        type = types.str;
+        type = types.separatedString " ";
         default = "";
         description =
           ''
@@ -54,6 +65,21 @@ in
           '';
       };
 
+    postStart =
+      mkOption {
+        type = types.lines;
+        default = ''
+          while ! [ -e /var/run/docker.sock ]; do
+            sleep 0.1
+          done
+        '';
+        description = ''
+          The postStart phase of the systemd service. You may need to
+          override this if you are passing in flags to docker which
+          don't cause the socket file to be created.
+        '';
+      };
+
 
   };
 
@@ -70,7 +96,7 @@ in
         after = [ "network.target" "docker.socket" ];
         requires = [ "docker.socket" ];
         serviceConfig = {
-          ExecStart = "${pkgs.docker}/bin/docker --daemon=true --host=fd:// --group=docker ${cfg.extraOptions}";
+          ExecStart = "${pkgs.docker}/bin/docker daemon --host=fd:// --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}";
           #  I'm not sure if that limits aren't too high, but it's what
           #  goes in config bundled with docker itself
           LimitNOFILE = 1048576;
@@ -96,18 +122,17 @@ in
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
         serviceConfig = {
-          ExecStart = "${pkgs.docker}/bin/docker --daemon=true --group=docker ${cfg.extraOptions}";
+          ExecStart = "${pkgs.docker}/bin/docker daemon --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}";
           #  I'm not sure if that limits aren't too high, but it's what
           #  goes in config bundled with docker itself
           LimitNOFILE = 1048576;
           LimitNPROC = 1048576;
         } // proxy_env;
 
-        postStart = ''
-          while ! [ -e /var/run/docker.sock ]; do
-            sleep 0.1
-          done
-        '';
+        path = [ pkgs.kmod ];
+        environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules";
+
+        postStart = cfg.postStart;
 
         # Presumably some containers are running we don't want to interrupt
         restartIfChanged = false;
diff --git a/nixos/modules/virtualisation/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix
index 15114b1e76ac..383750520ab7 100644
--- a/nixos/modules/virtualisation/ec2-data.nix
+++ b/nixos/modules/virtualisation/ec2-data.nix
@@ -7,19 +7,9 @@
 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" =
+    systemd.services.fetch-ec2-data =
       { description = "Fetch EC2 Data";
 
         wantedBy = [ "multi-user.target" "sshd.service" ];
@@ -31,12 +21,10 @@ with lib;
 
         script =
           ''
-            ip route del blackhole 169.254.169.254/32 || true
-
             wget="wget -q --retry-connrefused -O -"
 
-            echo "setting host name..."
             ${optionalString (config.networking.hostName == "") ''
+              echo "setting host name..."
               ${pkgs.nettools}/bin/hostname $($wget http://169.254.169.254/1.0/meta-data/hostname)
             ''}
 
@@ -47,10 +35,8 @@ with lib;
                 mkdir -m 0700 -p /root/.ssh
                 $wget http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key > /root/key.pub
                 if [ $? -eq 0 -a -e /root/key.pub ]; then
-                    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
+                    cat /root/key.pub >> /root/.ssh/authorized_keys
+                    echo "new key added to authorized_keys"
                     chmod 600 /root/.ssh/authorized_keys
                     rm -f /root/key.pub
                 fi
@@ -60,19 +46,22 @@ with lib;
             # the supplied user data, if available.  Otherwise sshd will
             # generate one normally.
             $wget http://169.254.169.254/2011-01-01/user-data > /root/user-data || true
+
+            mkdir -m 0755 -p /etc/ssh
+
             key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' /root/user-data)"
             key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' /root/user-data)"
             if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then
-                mkdir -m 0755 -p /etc/ssh
                 (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.
-            ip route add blackhole 169.254.169.254/32
-            ''}
+            key="$(sed 's/|/\n/g; s/SSH_HOST_ED25519_KEY://; t; d' /root/user-data)"
+            key_pub="$(sed 's/SSH_HOST_ED25519_KEY_PUB://; t; d' /root/user-data)"
+            if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_ed25519_key ]; then
+                (umask 077; echo "$key" > /etc/ssh/ssh_host_ed25519_key)
+                echo "$key_pub" > /etc/ssh/ssh_host_ed25519_key.pub
+            fi
           '';
 
         serviceConfig.Type = "oneshot";
@@ -89,7 +78,9 @@ 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
+            for i in /etc/ssh/ssh_host_*_key.pub; do
+                ${config.programs.ssh.package}/bin/ssh-keygen -l -f $i > /dev/console
+            done
             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..f21ddc12ca5a 100644
--- a/nixos/modules/virtualisation/google-compute-image.nix
+++ b/nixos/modules/virtualisation/google-compute-image.nix
@@ -30,7 +30,7 @@ in
               rm $out/disk.raw
               popd
             '';
-          diskImageBase = "nixos-${config.system.nixosVersion}-${pkgs.stdenv.system}.raw";
+          diskImageBase = "nixos-image-${config.system.nixosVersion}-${pkgs.stdenv.system}.raw";
           buildInputs = [ pkgs.utillinux pkgs.perl ];
           exportReferencesGraph =
             [ "closure" config.system.build.toplevel ];
@@ -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/growpart-util-linux-2.26.patch b/nixos/modules/virtualisation/growpart-util-linux-2.26.patch
new file mode 100644
index 000000000000..c782c2d7e4bd
--- /dev/null
+++ b/nixos/modules/virtualisation/growpart-util-linux-2.26.patch
@@ -0,0 +1,88 @@
+From 1895d10a7539d055a4e0206af1e7a9e5ea32a4f7 Mon Sep 17 00:00:00 2001
+From: Juerg Haefliger <juerg.haefliger@hp.com>
+Date: Wed, 25 Mar 2015 13:59:20 +0100
+Subject: [PATCH] Support new sfdisk version 2.26
+
+The sfdisk usage with version 2.26 changed. Specifically, the option
+--show-pt-geometry and functionality for CHS have been removed.
+Also, restoring a backup MBR now needs to be done using dd.
+---
+ bin/growpart | 28 ++++++++++------------------
+ 1 file changed, 10 insertions(+), 18 deletions(-)
+
+diff --git a/bin/growpart b/bin/growpart
+index 595c40b..d4c995b 100755
+--- a/bin/growpart
++++ b/bin/growpart
+@@ -28,7 +28,6 @@ PART=""
+ PT_UPDATE=false
+ DRY_RUN=0
+ 
+-MBR_CHS=""
+ MBR_BACKUP=""
+ GPT_BACKUP=""
+ _capture=""
+@@ -133,7 +132,8 @@ bad_Usage() {
+ }
+ 
+ mbr_restore() {
+-	sfdisk --no-reread "${DISK}" ${MBR_CHS} -I "${MBR_BACKUP}"
++	dd if="${MBR_BACKUP}-${DISK#/dev/}-0x00000000.bak" of="${DISK}" bs=1 \
++		conv=notrunc
+ }
+ 
+ sfdisk_worked_but_blkrrpart_failed() {
+@@ -148,34 +148,26 @@ sfdisk_worked_but_blkrrpart_failed() {
+ 
+ mbr_resize() {
+ 	RESTORE_HUMAN="${TEMP_D}/recovery"
+-	MBR_BACKUP="${TEMP_D}/orig.save"
++	MBR_BACKUP="${TEMP_D}/backup"
+ 
+ 	local change_out=${TEMP_D}/change.out
+ 	local dump_out=${TEMP_D}/dump.out
+ 	local new_out=${TEMP_D}/new.out
+ 	local dump_mod=${TEMP_D}/dump.mod
+-	local tmp="${TEMP_D}/tmp.out"
+-	local err="${TEMP_D}/err.out"
+ 
+-	local _devc cyl _w1 heads _w2 sectors _w3 tot dpart
++	local tot dpart
+ 	local pt_start pt_size pt_end max_end new_size change_info
+ 
+-	# --show-pt-geometry outputs something like
+-	#     /dev/sda: 164352 cylinders, 4 heads, 32 sectors/track
+-	rqe sfd_geom sfdisk "${DISK}" --show-pt-geometry >"${tmp}" &&
+-		read _devc cyl _w1 heads _w2 sectors _w3 <"${tmp}" &&
+-		MBR_CHS="-C ${cyl} -H ${heads} -S ${sectors}" ||
+-		fail "failed to get CHS from ${DISK}"
++	tot=$(sfdisk --list "${DISK}" | awk '{ print $(NF-1) ; exit }') ||
++		fail "failed to get total number of sectors from ${DISK}"
+ 
+-	tot=$((${cyl}*${heads}*${sectors}))
++	debug 1 "total number of sectors of ${DISK} is ${tot}"
+ 
+-	debug 1 "geometry is ${MBR_CHS}. total size=${tot}"
+-	rqe sfd_dump sfdisk ${MBR_CHS} --unit=S --dump "${DISK}" \
++	rqe sfd_dump sfdisk --dump "${DISK}" \
+ 		>"${dump_out}" ||
+ 		fail "failed to dump sfdisk info for ${DISK}"
+-
+ 	{
+-		echo "## sfdisk ${MBR_CHS} --unit=S --dump ${DISK}"
++		echo "## sfdisk --dump ${DISK}"
+ 		cat "${dump_out}"
+ 	}  >"${RESTORE_HUMAN}"
+ 	[ $? -eq 0 ] || fail "failed to save sfdisk -d output"
+@@ -237,7 +229,7 @@ mbr_resize() {
+ 		exit 0
+ 	fi
+ 
+-	LANG=C sfdisk --no-reread "${DISK}" ${MBR_CHS} --force \
++	LANG=C sfdisk --no-reread "${DISK}" --force \
+ 		-O "${MBR_BACKUP}" <"${new_out}" >"${change_out}" 2>&1
+ 	ret=$?
+ 	[ $ret -eq 0 ] || RESTORE_FUNC="mbr_restore"
+-- 
+2.1.4
+
diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix
index 7410609e0642..16aedbbb185d 100644
--- a/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixos/modules/virtualisation/libvirtd.nix
@@ -57,6 +57,17 @@ in
           '';
       };
 
+    virtualisation.libvirtd.extraOptions =
+      mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "--verbose" ];
+        description =
+          ''
+            Extra command line arguments passed to libvirtd on startup.
+          '';
+      };
+
     virtualisation.libvirtd.onShutdown =
       mkOption {
         type = types.enum ["shutdown" "suspend" ];
@@ -140,7 +151,7 @@ in
             done
           ''; # */
 
-        serviceConfig.ExecStart = ''@${pkgs.libvirt}/sbin/libvirtd libvirtd --config "${configFile}" --daemon --verbose'';
+        serviceConfig.ExecStart = ''@${pkgs.libvirt}/sbin/libvirtd libvirtd --config "${configFile}" --daemon ${concatStringsSep " " cfg.extraOptions}'';
         serviceConfig.Type = "forking";
         serviceConfig.KillMode = "process"; # when stopping, leave the VMs alone
 
diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
new file mode 100644
index 000000000000..488153334bc1
--- /dev/null
+++ b/nixos/modules/virtualisation/lxd.nix
@@ -0,0 +1,64 @@
+# Systemd services for lxd.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.virtualisation.lxd;
+
+in
+
+{
+  ###### interface
+
+  options = {
+
+    virtualisation.lxd.enable =
+      mkOption {
+        type = types.bool;
+        default = false;
+        description =
+          ''
+            This option enables lxd, a daemon that manages
+            containers. Users in the "lxd" group can interact with
+            the daemon (e.g. to start or stop containers) using the
+            <command>lxc</command> command line tool, among others.
+          '';
+      };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages =
+      [ pkgs.lxd ];
+
+    systemd.services.lxd =
+      { description = "LXD Container Management Daemon";
+
+        wantedBy = [ "multi-user.target" ];
+        after = [ "systemd-udev-settle.service" ];
+
+        # TODO(wkennington): Add lvm2 and thin-provisioning-tools
+        path = with pkgs; [ acl rsync gnutar xz btrfsProgs ];
+
+        serviceConfig.ExecStart = "@${pkgs.lxd}/bin/lxd lxd --syslog --group lxd";
+        serviceConfig.Type = "simple";
+        serviceConfig.KillMode = "process"; # when stopping, leave the containers alone
+      };
+
+    users.extraGroups.lxd.gid = config.ids.gids.lxd;
+
+    users.extraUsers.root = {
+      subUidRanges = [ { startUid = 1000000; count = 65536; } ];
+      subGidRanges = [ { startGid = 1000000; count = 65536; } ];
+    };
+
+  };
+
+}
diff --git a/nixos/modules/virtualisation/nixos-container-completion.sh b/nixos/modules/virtualisation/nixos-container-completion.sh
new file mode 100644
index 000000000000..0fe8ab811a17
--- /dev/null
+++ b/nixos/modules/virtualisation/nixos-container-completion.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+_nixos-container() {
+    local cur prev opts
+    COMPREPLY=()
+    cur="${COMP_WORDS[COMP_CWORD]}"
+    prev="${COMP_WORDS[COMP_CWORD-1]}"
+    opts="list create destroy start stop status update login root-login run show-ip show-host-key"
+    startstop_opts=$(nixos-container list)
+    update_opts="--config"
+
+    if [[ "$prev" == "nixos-container" ]]
+    then
+        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+        return 0
+    fi
+
+    if [[ $(echo "$opts" | grep "$prev") ]]
+    then
+        if [[ "$prev" == "start" || "$prev" == "stop" ]]
+        then
+            COMPREPLY=( $(compgen -W "${startstop_opts}" -- ${cur}) )
+            return 0
+        elif [[ "$prev" == "update" ]]
+        then
+            COMPREPLY=( $(compgen -W "${update_opts}" -- ${cur}) )
+            return 0
+        fi
+    fi
+}
+
+complete -F _nixos-container nixos-container
+
diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl
index f1d9e64ee38f..004385f728c6 100644
--- a/nixos/modules/virtualisation/nixos-container.pl
+++ b/nixos/modules/virtualisation/nixos-container.pl
@@ -290,7 +290,8 @@ elsif ($action eq "show-ip") {
 }
 
 elsif ($action eq "show-host-key") {
-    my $fn = "$root/etc/ssh/ssh_host_ecdsa_key.pub";
+    my $fn = "$root/etc/ssh/ssh_host_ed25519_key.pub";
+    $fn = "$root/etc/ssh/ssh_host_ecdsa_key.pub" unless -e $fn;
     exit 1 if ! -f $fn;
     print read_file($fn);
 }
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..a0231315236c 100644
--- a/nixos/modules/virtualisation/openvswitch.nix
+++ b/nixos/modules/virtualisation/openvswitch.nix
@@ -7,35 +7,45 @@ 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.
         '';
     };
 
+    resetOnStart = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to reset the Open vSwitch configuration database to a default
+        configuration on every start of the systemd <literal>ovsdb.service</literal>.
+        '';
+    };
 
-    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 +53,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 +61,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" ];
 
@@ -69,15 +76,15 @@ in
       description = "Open_vSwitch Database Server";
       wantedBy = [ "multi-user.target" ];
       after = [ "systemd-udev-settle.service" ];
-      wants = [ "vswitchd.service" ];
       path = [ cfg.package ];
       restartTriggers = [ db cfg.package ];
       # Create the config database
-      preStart = 
+      preStart =
         ''
         mkdir -p ${runDir}
         mkdir -p /var/db/openvswitch
         chmod +w /var/db/openvswitch
+        ${optionalString cfg.resetOnStart "rm -f /var/db/openvswitch/conf.db"}
         if [[ ! -e /var/db/openvswitch/conf.db ]]; then
           ${cfg.package}/bin/ovsdb-tool create \
             "/var/db/openvswitch/conf.db" \
@@ -85,33 +92,87 @@ 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";
+        # Use service type 'forking' to correctly determine when ovsdb-server is ready.
+        Type = "forking";
+      };
+      postStart = ''
         ${cfg.package}/bin/ovs-vsctl --timeout 3 --retry --no-wait init
-        '';
-
+      '';
     };
 
     systemd.services.vswitchd = {
       description = "Open_vSwitch Daemon";
+      wantedBy = [ "multi-user.target" ];
       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";
+        # Use service type 'forking' to correctly determine when vswitchd is ready.
+        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 = [ "ovsdb.service" ];
+      before = [ "vswitchd.service" "racoon.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";
+        # Use service type 'forking' to correctly determine when ovs-monitor-ipsec is ready.
+        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/parallels-guest.nix b/nixos/modules/virtualisation/parallels-guest.nix
index 2f40283b3e1d..204ab0b0df67 100644
--- a/nixos/modules/virtualisation/parallels-guest.nix
+++ b/nixos/modules/virtualisation/parallels-guest.nix
@@ -17,7 +17,7 @@ in
         type = types.bool;
         default = false;
         description = ''
-          This enables Parallel Tools for Linux guests, along with provided
+          This enables Parallels Tools for Linux guests, along with provided
           video, mouse and other hardware drivers.
         '';
       };
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/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix
index a0e4bd558e05..a025aee7cfeb 100644
--- a/nixos/modules/virtualisation/virtualbox-guest.nix
+++ b/nixos/modules/virtualisation/virtualbox-guest.nix
@@ -6,7 +6,7 @@ with lib;
 
 let
 
-  cfg = config.services.virtualboxGuest;
+  cfg = config.virtualisation.virtualbox.guest;
   kernel = config.boot.kernelPackages;
 
 in
@@ -15,20 +15,11 @@ in
 
   ###### interface
 
-  options = {
-
-    services.virtualboxGuest = {
-
-      enable = mkOption {
-        default = false;
-        description = "Whether to enable the VirtualBox service and other guest additions.";
-      };
-
-    };
-
+  options.virtualisation.virtualbox.guest.enable = mkOption {
+    default = false;
+    description = "Whether to enable the VirtualBox service and other guest additions.";
   };
 
-
   ###### implementation
 
   config = mkIf cfg.enable {
@@ -41,7 +32,8 @@ in
 
     boot.extraModulePackages = [ kernel.virtualboxGuestAdditions ];
 
-    boot.kernelModules = [ "vboxsf" ];
+    boot.supportedFilesystems = [ "vboxsf" ];
+    boot.initrd.supportedFilesystems = [ "vboxsf" ];
 
     users.extraGroups.vboxsf.gid = config.ids.gids.vboxsf;
 
@@ -54,7 +46,7 @@ in
 
         unitConfig.ConditionVirtualization = "oracle";
 
-        serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/sbin/VBoxService VBoxService --foreground";
+        serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/bin/VBoxService VBoxService --foreground";
       };
 
     services.xserver.videoDrivers = mkOverride 50 [ "virtualbox" ];
diff --git a/nixos/modules/programs/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index fc113a08a356..00486df5c4ba 100644
--- a/nixos/modules/programs/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -3,7 +3,7 @@
 with lib;
 
 let
-  cfg = config.services.virtualboxHost;
+  cfg = config.virtualisation.virtualbox.host;
   virtualbox = config.boot.kernelPackages.virtualbox.override {
     inherit (cfg) enableHardening;
   };
@@ -11,12 +11,12 @@ let
 in
 
 {
-  options.services.virtualboxHost = {
+  options.virtualisation.virtualbox.host = {
     enable = mkOption {
       type = types.bool;
       default = false;
       description = ''
-        Whether to enable host-side support for VirtualBox.
+        Whether to enable VirtualBox.
 
         <note><para>
           In order to pass USB devices from the host to the guests, the user
diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix
index 8232f6e50dfc..425726333c40 100644
--- a/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixos/modules/virtualisation/virtualbox-image.nix
@@ -11,97 +11,41 @@ in {
   options = {
     virtualbox = {
       baseImageSize = mkOption {
-        type = types.str;
-        default = "10G";
+        type = types.int;
+        default = 10 * 1024;
         description = ''
-          The size of the VirtualBox base image. The size string should be on
-          a format the qemu-img command accepts.
+          The size of the VirtualBox base image in MiB.
         '';
       };
     };
   };
 
   config = {
-    system.build.virtualBoxImage =
-      pkgs.vmTools.runInLinuxVM (
-        pkgs.runCommand "virtualbox-image"
-          { memSize = 768;
-            preVM =
-              ''
-                mkdir $out
-                diskImage=$out/image
-                ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "${cfg.baseImageSize}"
-                mv closure xchg/
-              '';
-            postVM =
-              ''
-                echo "creating VirtualBox disk image..."
-                ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vdi $diskImage $out/disk.vdi
-                rm $diskImage
-              '';
-            buildInputs = [ pkgs.utillinux pkgs.perl ];
-            exportReferencesGraph =
-              [ "closure" config.system.build.toplevel ];
+
+    system.build.virtualBoxImage = import ../../lib/make-disk-image.nix {
+      inherit pkgs lib config;
+      partitioned = true;
+      diskSize = cfg.baseImageSize;
+
+      configFile = pkgs.writeText "configuration.nix"
+        ''
+          {
+            imports = [ <nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix> ];
           }
-          ''
-            # Create a single / partition.
-            ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
-            ${pkgs.parted}/sbin/parted /dev/vda -- mkpart primary ext2 1M -1s
-            . /sys/class/block/vda1/uevent
-            mknod /dev/vda1 b $MAJOR $MINOR
-  
-            # Create an empty filesystem and mount it.
-            ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1
-            ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1
-            mkdir /mnt
-            mount /dev/vda1 /mnt
-  
-            # The initrd expects these directories to exist.
-            mkdir /mnt/dev /mnt/proc /mnt/sys
-            mount --bind /proc /mnt/proc
-            mount --bind /dev /mnt/dev
-            mount --bind /sys /mnt/sys
-  
-            # Copy all paths in the closure to the filesystem.
-            storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
-  
-            echo "filling Nix store..."
-            mkdir -p /mnt/nix/store
-            set -f
-            cp -prd $storePaths /mnt/nix/store/
-  
-            mkdir -p /mnt/etc/nix
-            echo 'build-users-group = ' > /mnt/etc/nix/nix.conf
-  
-            # 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
-  
-            # Create the system profile to allow nixos-rebuild to work.
-            chroot /mnt ${config.nix.package}/bin/nix-env \
-                -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel}
-  
-            # `nixos-rebuild' requires an /etc/NIXOS.
-            mkdir -p /mnt/etc/nixos
-            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
-  
-            # Generate the GRUB menu.
-            ln -s vda /dev/sda
-            chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
-  
-            umount /mnt/proc /mnt/dev /mnt/sys
-            umount /mnt
-          ''
-      );
-  
+        '';
+
+      postVM =
+        ''
+          echo "creating VirtualBox disk image..."
+          ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vdi $diskImage $out/disk.vdi
+          rm $diskImage
+        '';
+    };
+
     system.build.virtualBoxOVA = pkgs.runCommand "virtualbox-ova"
       { buildInputs = [ pkgs.linuxPackages.virtualbox ];
         vmName = "NixOS ${config.system.nixosVersion} (${pkgs.stdenv.system})";
-        fileName = "nixos-${config.system.nixosVersion}-${pkgs.stdenv.system}.ova";
+        fileName = "nixos-image-${config.system.nixosVersion}-${pkgs.stdenv.system}.ova";
       }
       ''
         echo "creating VirtualBox VM..."
@@ -109,7 +53,8 @@ in {
         VBoxManage createvm --name "$vmName" --register \
           --ostype ${if pkgs.stdenv.system == "x86_64-linux" then "Linux26_64" else "Linux26"}
         VBoxManage modifyvm "$vmName" \
-          --memory 1536 --acpi on --vram 10 \
+          --memory 1536 --acpi on --vram 32 \
+          ${optionalString (pkgs.stdenv.system == "i686-linux") "--pae on"} \
           --nictype1 virtio --nic1 nat \
           --audiocontroller ac97 --audio alsa \
           --rtcuseutc on \
@@ -117,17 +62,17 @@ in {
         VBoxManage storagectl "$vmName" --name SATA --add sata --portcount 4 --bootable on --hostiocache on
         VBoxManage storageattach "$vmName" --storagectl SATA --port 0 --device 0 --type hdd \
           --medium ${config.system.build.virtualBoxImage}/disk.vdi
-  
+
         echo "exporting VirtualBox VM..."
         mkdir -p $out
         VBoxManage export "$vmName" --output "$out/$fileName"
       '';
-  
+
     fileSystems."/".device = "/dev/disk/by-label/nixos";
-  
-    boot.loader.grub.version = 2;
+
     boot.loader.grub.device = "/dev/sda";
-  
-    services.virtualboxGuest.enable = true;
+
+    virtualisation.virtualbox.guest.enable = true;
+
   };
 }
diff --git a/nixos/modules/virtualisation/vmware-guest.nix b/nixos/modules/virtualisation/vmware-guest.nix
new file mode 100644
index 000000000000..ac2415a22b52
--- /dev/null
+++ b/nixos/modules/virtualisation/vmware-guest.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.vmwareGuest;
+  open-vm-tools = pkgs.open-vm-tools;
+in
+{
+  options = {
+    services.vmwareGuest.enable = mkEnableOption "VMWare Guest Support";
+  };
+
+  config = mkIf cfg.enable {
+    assertions = [ {
+      assertion = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
+      message = "VMWare guest is not currently supported on ${pkgs.stdenv.system}";
+    } ];
+
+    environment.systemPackages = [ open-vm-tools ];
+
+    systemd.services.vmware =
+      { description = "VMWare Guest Service";
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig.ExecStart = "${open-vm-tools}/bin/vmtoolsd";
+      };
+
+    services.xserver = {
+      videoDrivers = mkOverride 50 [ "vmware" ];
+
+      config = ''
+          Section "InputDevice"
+            Identifier "VMMouse"
+            Driver "vmmouse"
+          EndSection
+        '';
+
+      serverLayoutSection = ''
+          InputDevice "VMMouse"
+        '';
+
+      displayManager.sessionCommands = ''
+          ${open-vm-tools}/bin/vmware-user-suid-wrapper
+        '';
+    };
+  };
+}
diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix
index ea9f61aad6a6..a0b2d5363eb2 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;}; };
@@ -103,6 +121,10 @@ in
         "xenfs"
       ];
 
+    # The xenfs module is needed in system.activationScripts.xen, but
+    # the modprobe command there fails silently. Include xenfs in the
+    # initrd as a work around.
+    boot.initrd.kernelModules = [ "xenfs" ];
 
     # The radeonfb kernel module causes the screen to go black as soon
     # as it's loaded, so don't load it.
@@ -122,7 +144,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 +180,19 @@ 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";
+        }
+        { source = "${pkgs.xen}/etc/default/xendomains";
+          target = "default/xendomains";
+        }
       ];
 
     # Xen provides udev rules.
-    services.udev.packages = [ xen ];
+    services.udev.packages = [ pkgs.xen ];
 
     services.udev.path = [ pkgs.bridge-utils pkgs.iproute ];
 
@@ -178,7 +206,8 @@ in
         rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null
 
         mkdir -p /var/run
-        ${optionalString cfg.trace "mkdir -p /var/log/xen"}
+        mkdir -p /var/log/xen # Running xl requires /var/log/xen and /var/lib/xen,
+        mkdir -p /var/lib/xen # so we create them here unconditionally.
         grep -q control_d /proc/xen/capabilities
         '';
       serviceConfig.ExecStart = ''
@@ -259,17 +288,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" ];