summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/release-notes.xml2
-rw-r--r--nixos/doc/manual/release-notes/rl-1410.xml22
-rw-r--r--nixos/doc/manual/release-notes/rl-1411.xml35
-rw-r--r--nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix3
-rwxr-xr-xnixos/maintainers/scripts/ec2/create-ebs-amis.py90
-rw-r--r--nixos/modules/config/fonts/fontconfig.nix5
-rw-r--r--nixos/modules/config/pulseaudio.nix22
-rw-r--r--nixos/modules/config/update-users-groups.pl51
-rw-r--r--nixos/modules/config/users-groups.nix80
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-base.nix5
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical.nix69
-rw-r--r--nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix1
-rw-r--r--nixos/modules/installer/tools/tools.nix2
-rw-r--r--nixos/modules/misc/ids.nix15
-rwxr-xr-xnixos/modules/module-list.nix9
-rw-r--r--nixos/modules/profiles/base.nix1
-rw-r--r--nixos/modules/programs/environment.nix1
-rw-r--r--nixos/modules/programs/ssmtp.nix17
-rw-r--r--nixos/modules/programs/uim.nix4
-rw-r--r--nixos/modules/rename.nix2
-rw-r--r--nixos/modules/security/grsecurity.nix4
-rw-r--r--nixos/modules/security/sudo.nix12
-rw-r--r--nixos/modules/services/backup/rsnapshot.nix11
-rw-r--r--nixos/modules/services/databases/neo4j.nix10
-rw-r--r--nixos/modules/services/databases/postgresql.nix4
-rw-r--r--nixos/modules/services/hardware/thermald.nix2
-rw-r--r--nixos/modules/services/hardware/udev.nix14
-rw-r--r--nixos/modules/services/logging/logrotate.nix1
-rw-r--r--nixos/modules/services/logging/logstash.nix83
-rw-r--r--nixos/modules/services/logging/syslog-ng.nix30
-rw-r--r--nixos/modules/services/misc/gitolite.nix15
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix14
-rw-r--r--nixos/modules/services/misc/redmine.nix222
-rw-r--r--nixos/modules/services/monitoring/graphite.nix392
-rw-r--r--nixos/modules/services/monitoring/zabbix-server.nix13
-rw-r--r--nixos/modules/services/network-filesystems/nfsd.nix10
-rw-r--r--nixos/modules/services/network-filesystems/yandex-disk.nix4
-rw-r--r--nixos/modules/services/networking/atftpd.nix4
-rw-r--r--nixos/modules/services/networking/cjdns-hosts.sh11
-rw-r--r--nixos/modules/services/networking/cjdns.nix208
-rw-r--r--nixos/modules/services/networking/consul.nix166
-rw-r--r--nixos/modules/services/networking/git-daemon.nix32
-rw-r--r--nixos/modules/services/networking/i2pd.nix198
-rw-r--r--nixos/modules/services/networking/mailpile.nix76
-rw-r--r--nixos/modules/services/networking/nat.nix6
-rw-r--r--nixos/modules/services/networking/polipo.nix4
-rw-r--r--nixos/modules/services/networking/prosody.nix280
-rw-r--r--nixos/modules/services/networking/quassel.nix20
-rw-r--r--nixos/modules/services/networking/seeks.nix75
-rw-r--r--nixos/modules/services/scheduling/cron.nix26
-rw-r--r--nixos/modules/services/torrent/transmission.nix2
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix14
-rw-r--r--nixos/modules/services/web-servers/lighttpd/cgit.nix3
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix95
-rw-r--r--nixos/modules/services/web-servers/lighttpd/gitweb.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde4.nix20
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix1
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix10
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix3
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix23
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix3
-rw-r--r--nixos/modules/services/x11/window-managers/stumpwm.nix30
-rw-r--r--nixos/modules/services/x11/xserver.nix6
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl6
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh8
-rw-r--r--nixos/modules/system/boot/stage-1.nix7
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix4
-rw-r--r--nixos/modules/system/boot/systemd.nix10
-rw-r--r--nixos/modules/tasks/filesystems/jfs.nix19
-rw-r--r--nixos/modules/tasks/filesystems/zfs.nix1
-rw-r--r--nixos/modules/tasks/network-interfaces.nix55
-rw-r--r--nixos/modules/testing/test-instrumentation.nix2
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix9
-rw-r--r--nixos/modules/virtualisation/docker-image.nix12
-rw-r--r--nixos/modules/virtualisation/docker.nix6
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix2
-rw-r--r--nixos/release-combined.nix2
-rw-r--r--nixos/release-small.nix93
-rw-r--r--nixos/release.nix18
-rw-r--r--nixos/tests/bittorrent.nix4
-rw-r--r--nixos/tests/blivet.nix85
-rw-r--r--nixos/tests/cjdns.nix123
-rw-r--r--nixos/tests/gnome3.nix2
-rw-r--r--nixos/tests/gnome3_12.nix2
-rw-r--r--nixos/tests/installer.nix64
-rw-r--r--nixos/tests/jenkins.nix2
-rw-r--r--nixos/tests/kde4.nix2
-rw-r--r--nixos/tests/munin.nix2
-rw-r--r--nixos/tests/partition.nix4
-rw-r--r--nixos/tests/proxy.nix7
-rw-r--r--nixos/tests/run-in-machine.nix8
92 files changed, 2541 insertions, 616 deletions
diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml
index fb82d5adcefb..9034dba1fb5a 100644
--- a/nixos/doc/manual/release-notes/release-notes.xml
+++ b/nixos/doc/manual/release-notes/release-notes.xml
@@ -10,7 +10,7 @@
 <para>This section lists the release notes for each stable version of NixOS.</para>
 </partintro>
 
-<xi:include href="rl-1410.xml" />
+<xi:include href="rl-1411.xml" />
 <xi:include href="rl-1404.xml" />
 <xi:include href="rl-1310.xml" />
 
diff --git a/nixos/doc/manual/release-notes/rl-1410.xml b/nixos/doc/manual/release-notes/rl-1410.xml
deleted file mode 100644
index 09da15ce2361..000000000000
--- a/nixos/doc/manual/release-notes/rl-1410.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<chapter xmlns="http://docbook.org/ns/docbook"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:xi="http://www.w3.org/2001/XInclude"
-        version="5.0"
-        xml:id="sec-release-14.10">
-
-<title>Release 14.10 (“Caterpillar”, 2014/10/??)</title>
-
-<para>When upgrading from a previous release, please be aware of the
-following incompatible changes:
-
-<itemizedlist>
-
-  <listitem><para>The host side of a container virtual Ethernet pair
-  is now called <literal>ve-<replaceable>container-name</replaceable></literal>
-  rather than <literal>c-<replaceable>container-name</replaceable></literal>.</para></listitem>
-
-</itemizedlist>
-
-</para>
-
-</chapter>
\ No newline at end of file
diff --git a/nixos/doc/manual/release-notes/rl-1411.xml b/nixos/doc/manual/release-notes/rl-1411.xml
new file mode 100644
index 000000000000..e355118139dc
--- /dev/null
+++ b/nixos/doc/manual/release-notes/rl-1411.xml
@@ -0,0 +1,35 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+        xmlns:xlink="http://www.w3.org/1999/xlink"
+        xmlns:xi="http://www.w3.org/2001/XInclude"
+        version="5.0"
+        xml:id="sec-release-14.11">
+
+<title>Release 14.11 (“Caterpillar”, 2014/11/??)</title>
+
+<para>When upgrading from a previous release, please be aware of the
+following incompatible changes:
+
+<itemizedlist>
+
+  <listitem><para>The default version of Apache httpd is now 2.4. If
+  you use the <option>extraConfig</option> option to pass literal
+  Apache configuration text, you may need to update it — see <link
+  xlink:href="http://httpd.apache.org/docs/2.4/upgrading.html">Apache’s
+  documentation</link> for details. If you wish to continue to use
+  httpd 2.2, add the following line to your NixOS configuration:
+
+<programlisting>
+services.httpd.package = pkgs.apacheHttpd_2_2;
+</programlisting>
+
+  </para></listitem>
+
+  <listitem><para>The host side of a container virtual Ethernet pair
+  is now called <literal>ve-<replaceable>container-name</replaceable></literal>
+  rather than <literal>c-<replaceable>container-name</replaceable></literal>.</para></listitem>
+
+</itemizedlist>
+
+</para>
+
+</chapter>
diff --git a/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix b/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix
index d9feba164a76..530769cec5b7 100644
--- a/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix
+++ b/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix
@@ -19,7 +19,8 @@ in
 {
   imports = [ ./amazon-base-config.nix ];
   ec2.hvm = true;
-  boot.loader.grub.device = lib.mkOverride 0 "nodev";
+  boot.loader.grub.device = lib.mkOverride 0 "/dev/xvdg";
+  boot.kernelParams = [ "console=ttyS0" ];
 
   boot.initrd.extraUtilsCommands = ''
     cp -v ${pkgs.gawk}/bin/gawk $out/bin/gawk
diff --git a/nixos/maintainers/scripts/ec2/create-ebs-amis.py b/nixos/maintainers/scripts/ec2/create-ebs-amis.py
index 14607b9a3678..62525651ae03 100755
--- a/nixos/maintainers/scripts/ec2/create-ebs-amis.py
+++ b/nixos/maintainers/scripts/ec2/create-ebs-amis.py
@@ -19,8 +19,17 @@ parser.add_argument('--key', dest='key_name', action='store_true', help='Keypair
 args = parser.parse_args()
 
 instance_type = "m3.medium" if args.hvm else "m1.small"
-ebs_size = 8 if args.hvm else 20
 
+if args.hvm:
+    virtualization_type = "hvm"
+    root_block = "/dev/sda1"
+    image_type = 'hvm'
+else:
+    virtualization_type = "paravirtual"
+    root_block = "/dev/sda"
+    image_type = 'ebs'
+
+ebs_size = 20
 
 # Start a NixOS machine in the given region.
 f = open("ebs-creator-config.nix", "w")
@@ -76,10 +85,6 @@ if args.hvm:
     m.upload_file("./amazon-hvm-config.nix", "/mnt/etc/nixos/configuration.nix")
     m.upload_file("./amazon-hvm-install-config.nix", "/mnt/etc/nixos/amazon-hvm-install-config.nix")
     m.run_command("NIXOS_CONFIG=/etc/nixos/amazon-hvm-install-config.nix nixos-install")
-    m.run_command('nix-env -iA nixos.pkgs.grub')
-    m.run_command('cp /nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub')
-    m.run_command('echo "(hd1) /dev/xvdg" > device.map')
-    m.run_command('echo -e "root (hd1,0)\nsetup (hd1)" | grub --device-map=device.map --batch')
 else:
     m.upload_file("./amazon-base-config.nix", "/mnt/etc/nixos/configuration.nix")
     m.run_command("nixos-install")
@@ -87,7 +92,7 @@ else:
 m.run_command("umount /mnt")
 
 if args.hvm:
-    ami_name = "nixos-{0}-x86_64-ebs-hvm".format(version)
+    ami_name = "nixos-{0}-x86_64-hvm".format(version)
     description = "NixOS {0} (x86_64; EBS root; hvm)".format(version)
 else:
     ami_name = "nixos-{0}-x86_64-ebs".format(version)
@@ -102,58 +107,40 @@ def check():
 
 m.connect()
 volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m.resource_id, 'attachment.device': "/dev/sdg"})[0]
-if args.hvm:
-    instance = m._conn.run_instances( image_id="ami-5f491f36"
-                                    , instance_type=instance_type
-                                    , key_name=args.key_name
-                                    , placement=m.zone
-                                    , security_groups=["eelco-test"]).instances[0]
-    nixops.util.check_wait(lambda: instance.update() == 'running', max_tries=120)
-    instance.stop()
-    nixops.util.check_wait(lambda: instance.update() == 'stopped', max_tries=120)
-    old_root_volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': instance.id, 'attachment.device': "/dev/sda1"})[0]
-    old_root_volume.detach()
-    volume.detach()
-    nixops.util.check_wait(lambda: volume.update() == 'available', max_tries=120)
-    nixops.util.check_wait(lambda: old_root_volume.update() == 'available', max_tries=120)
-    volume.attach(instance.id, '/dev/sda1')
-    nixops.util.check_wait(lambda: volume.update() == 'in-use', max_tries=120)
-
-    ami_id = m._conn.create_image(instance.id, ami_name, description)
-    time.sleep(5)
-    image = m._conn.get_all_images([ami_id])[0]
-    nixops.util.check_wait(lambda: image.update() == 'available', max_tries=120)
-    instance.terminate()
 
-else:
-    # Create a snapshot.
-    snapshot = volume.create_snapshot(description=description)
-    print >> sys.stderr, "created snapshot {0}".format(snapshot.id)
+# Create a snapshot.
+snapshot = volume.create_snapshot(description=description)
+print >> sys.stderr, "created snapshot {0}".format(snapshot.id)
 
-    nixops.util.check_wait(check, max_tries=120)
+nixops.util.check_wait(check, max_tries=120)
 
-    m._conn.create_tags([snapshot.id], {'Name': ami_name})
+m._conn.create_tags([snapshot.id], {'Name': ami_name})
 
-    if not args.keep: depl.destroy_resources()
+if not args.keep: depl.destroy_resources()
 
-     # Register the image.
-    aki = m._conn.get_all_images(filters={'manifest-location': '*pv-grub-hd0_1.03-x86_64*'})[0]
-    print >> sys.stderr, "using kernel image {0} - {1}".format(aki.id, aki.location)
+# Register the image.
+aki = m._conn.get_all_images(filters={'manifest-location': 'ec2*pv-grub-hd0_1.03-x86_64*'})[0]
+print >> sys.stderr, "using kernel image {0} - {1}".format(aki.id, aki.location)
 
-    block_map = BlockDeviceMapping()
-    block_map['/dev/sda'] = BlockDeviceType(snapshot_id=snapshot.id, delete_on_termination=True)
-    block_map['/dev/sdb'] = BlockDeviceType(ephemeral_name="ephemeral0")
-    block_map['/dev/sdc'] = BlockDeviceType(ephemeral_name="ephemeral1")
-    block_map['/dev/sdd'] = BlockDeviceType(ephemeral_name="ephemeral2")
-    block_map['/dev/sde'] = BlockDeviceType(ephemeral_name="ephemeral3")
+block_map = BlockDeviceMapping()
+block_map[root_block] = BlockDeviceType(snapshot_id=snapshot.id, delete_on_termination=True, size=ebs_size, volume_type="gp2")
+block_map['/dev/sdb'] = BlockDeviceType(ephemeral_name="ephemeral0")
+block_map['/dev/sdc'] = BlockDeviceType(ephemeral_name="ephemeral1")
+block_map['/dev/sdd'] = BlockDeviceType(ephemeral_name="ephemeral2")
+block_map['/dev/sde'] = BlockDeviceType(ephemeral_name="ephemeral3")
 
-    ami_id = m._conn.register_image(
+common_args = dict(
         name=ami_name,
         description=description,
         architecture="x86_64",
-        root_device_name="/dev/sda",
-        kernel_id=aki.id,
-        block_device_map=block_map)
+        root_device_name=root_block,
+        block_device_map=block_map,
+        virtualization_type=virtualization_type,
+        delete_root_volume_on_termination=True
+        )
+if not args.hvm:
+    common_args['kernel_id']=aki.id
+ami_id = m._conn.register_image(**common_args)
 
 print >> sys.stderr, "registered AMI {0}".format(ami_id)
 
@@ -197,17 +184,12 @@ test_depl.nix_exprs = [os.path.abspath("./ebs-test.nix")]
 test_depl.deploy(create_only=True)
 test_depl.machines['machine'].run_command("nixos-version")
 
-if args.hvm:
-    image_type = 'hvm'
-else:
-    image_type = 'ebs'
-
 # Log the AMI ID.
 f = open("{0}.{1}.ami-id".format(args.region, image_type), "w")
 f.write("{0}".format(ami_id))
 f.close()
 
-for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'sa-east-1']:
+for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1', 'eu-central-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'sa-east-1']:
     if args.region != dest:
         print >> sys.stderr, "copying image from region {0} to {1}".format(args.region, dest)
         conn = boto.ec2.connect_to_region(dest)
diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
index cf70ca264d6a..7516d7ddf1a6 100644
--- a/nixos/modules/config/fonts/fontconfig.nix
+++ b/nixos/modules/config/fonts/fontconfig.nix
@@ -47,11 +47,6 @@ with lib;
         </fontconfig>
       '';
 
-    # FIXME: This variable is no longer needed, but we'll keep it
-    # around for a while for applications linked against old
-    # fontconfig builds.
-    environment.variables.FONTCONFIG_FILE = "/etc/fonts/fonts.conf";
-
     environment.systemPackages = [ pkgs.fontconfig ];
 
   };
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index 297b3a82d6c1..8b38489a8c19 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, pkgs_i686, ... }:
 
 with pkgs;
 with lib;
@@ -10,6 +10,10 @@ let
   systemWide = cfg.enable && cfg.systemWide;
   nonSystemWide = cfg.enable && !cfg.systemWide;
 
+  # 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);
+
   ids = config.ids;
 
   uid = ids.uids.pulseaudio;
@@ -28,21 +32,25 @@ let
   # Write an /etc/asound.conf that causes all ALSA applications to
   # be re-routed to the PulseAudio server through ALSA's Pulse
   # plugin.
-  alsaConf = writeText "asound.conf" ''
+  alsaConf = writeText "asound.conf" (''
     pcm_type.pulse {
-      lib ${alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so
+      libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ;
+      ${lib.optionalString enable32BitAlsaPlugins
+     "libs.32Bit = ${pkgs_i686.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ;"}
     }
     pcm.!default {
       type pulse
       hint.description "Default Audio Device (via PulseAudio)"
     }
     ctl_type.pulse {
-      lib ${alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so
+      libs.native = ${alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ;
+      ${lib.optionalString enable32BitAlsaPlugins
+     "libs.32Bit = ${pkgs_i686.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ;"}
     }
     ctl.!default {
       type pulse
     }
-  '';
+  '');
 
 in {
 
@@ -116,7 +124,9 @@ in {
     }
 
     (mkIf cfg.enable {
-      environment.systemPackages = [ cfg.package ];
+      environment.systemPackages = [
+        cfg.package
+      ] ++ lib.optionals enable32BitAlsaPlugins [ pkgs_i686.pulseaudio ];
 
       environment.etc = singleton {
         target = "asound.conf";
diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl
index 197b65e27c4b..d35ecb754bdb 100644
--- a/nixos/modules/config/update-users-groups.pl
+++ b/nixos/modules/config/update-users-groups.pl
@@ -6,6 +6,15 @@ use JSON;
 make_path("/var/lib/nixos", { mode => 0755 });
 
 
+sub hashPassword {
+    my ($password) = @_;
+    my $salt = "";
+    my @chars = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
+    $salt .= $chars[rand 64] for (1..8);
+    return crypt($password, '$6$' . $salt . '$');
+}
+
+
 # Functions for allocating free GIDs/UIDs. FIXME: respect ID ranges in
 # /etc/login.defs.
 sub allocId {
@@ -114,7 +123,7 @@ foreach my $g (@{$spec->{groups}}) {
 }
 
 # Update the persistent list of declarative groups.
-write_file($declGroupsFile, join(" ", sort(keys %groupsOut)));
+write_file($declGroupsFile, { binmode => ':utf8' }, join(" ", sort(keys %groupsOut)));
 
 # Merge in the existing /etc/group.
 foreach my $name (keys %groupsCur) {
@@ -131,7 +140,7 @@ foreach my $name (keys %groupsCur) {
 # Rewrite /etc/group. FIXME: acquire lock.
 my @lines = map { join(":", $_->{name}, $_->{password}, $_->{gid}, $_->{members}) . "\n" }
     (sort { $a->{gid} <=> $b->{gid} } values(%groupsOut));
-write_file("/etc/group.tmp", @lines);
+write_file("/etc/group.tmp", { binmode => ':utf8' }, @lines);
 rename("/etc/group.tmp", "/etc/group") or die;
 system("nscd --invalidate group");
 
@@ -160,6 +169,12 @@ foreach my $u (@{$spec->{users}}) {
     } else {
         $u->{uid} = allocUid($u->{isSystemUser}) if !defined $u->{uid};
 
+        if (defined $u->{initialPassword}) {
+            $u->{hashedPassword} = hashPassword($u->{initialPassword});
+        } elsif (defined $u->{initialHashedPassword}) {
+            $u->{hashedPassword} = $u->{initialHashedPassword};
+        }
+
         # Create a home directory.
         if ($u->{createHome}) {
             make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home};
@@ -174,6 +189,8 @@ foreach my $u (@{$spec->{users}}) {
         } else {
             warn "warning: password file ‘$u->{passwordFile}’ does not exist\n";
         }
+    } elsif (defined $u->{password}) {
+        $u->{hashedPassword} = hashPassword($u->{password});
     }
 
     $u->{fakePassword} = $existing->{fakePassword} // "x";
@@ -181,7 +198,7 @@ foreach my $u (@{$spec->{users}}) {
 }
 
 # Update the persistent list of declarative users.
-write_file($declUsersFile, join(" ", sort(keys %usersOut)));
+write_file($declUsersFile, { binmode => ':utf8' }, join(" ", sort(keys %usersOut)));
 
 # Merge in the existing /etc/passwd.
 foreach my $name (keys %usersCur) {
@@ -197,7 +214,7 @@ foreach my $name (keys %usersCur) {
 # Rewrite /etc/passwd. FIXME: acquire lock.
 @lines = map { join(":", $_->{name}, $_->{fakePassword}, $_->{uid}, $_->{gid}, $_->{description}, $_->{home}, $_->{shell}) . "\n" }
     (sort { $a->{uid} <=> $b->{uid} } (values %usersOut));
-write_file("/etc/passwd.tmp", @lines);
+write_file("/etc/passwd.tmp", { binmode => ':utf8' }, @lines);
 rename("/etc/passwd.tmp", "/etc/passwd") or die;
 system("nscd --invalidate passwd");
 
@@ -208,32 +225,22 @@ my %shadowSeen;
 
 foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow") : ()) {
     chomp $line;
-    my ($name, $password, @rest) = split(':', $line, -9);
+    my ($name, $hashedPassword, @rest) = split(':', $line, -9);
     my $u = $usersOut{$name};;
     next if !defined $u;
-    $password = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
-    push @shadowNew, join(":", $name, $password, @rest) . "\n";
+    $hashedPassword = "!" if !$spec->{mutableUsers};
+    $hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
+    push @shadowNew, join(":", $name, $hashedPassword, @rest) . "\n";
     $shadowSeen{$name} = 1;
 }
 
 foreach my $u (values %usersOut) {
     next if defined $shadowSeen{$u->{name}};
-    my $password = "!";
-    $password = $u->{hashedPassword} if defined $u->{hashedPassword};
+    my $hashedPassword = "!";
+    $hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword};
     # FIXME: set correct value for sp_lstchg.
-    push @shadowNew, join(":", $u->{name}, $password, "1::::::") . "\n";
+    push @shadowNew, join(":", $u->{name}, $hashedPassword, "1::::::") . "\n";
 }
 
-write_file("/etc/shadow.tmp", { perms => 0600 }, @shadowNew);
+write_file("/etc/shadow.tmp", { binmode => ':utf8', perms => 0600 }, @shadowNew);
 rename("/etc/shadow.tmp", "/etc/shadow") or die;
-
-
-# Call chpasswd to apply password. FIXME: generate the hashes directly
-# and merge into the /etc/shadow updating above.
-foreach my $u (@{$spec->{users}}) {
-    if (defined $u->{password}) {
-        my $pid = open(PW, "| chpasswd") or die;
-        print PW "$u->{name}:$u->{password}\n";
-        close PW or die "unable to change password of user ‘$u->{name}’: $?\n";
-    }
-}
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 0d3273fe0539..256c5888cb94 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -8,19 +8,19 @@ let
   cfg = config.users;
 
   passwordDescription = ''
-    The options <literal>hashedPassword</literal>,
-    <literal>password</literal> and <literal>passwordFile</literal>
+    The options <option>hashedPassword</option>,
+    <option>password</option> and <option>passwordFile</option>
     controls what password is set for the user.
-    <literal>hashedPassword</literal> overrides both
-    <literal>password</literal> and <literal>passwordFile</literal>.
-    <literal>password</literal> overrides <literal>passwordFile</literal>.
+    <option>hashedPassword</option> overrides both
+    <option>password</option> and <option>passwordFile</option>.
+    <option>password</option> overrides <option>passwordFile</option>.
     If none of these three options are set, no password is assigned to
     the user, and the user will not be able to do password logins.
-    If the option <literal>users.mutableUsers</literal> is true, the
+    If the option <option>users.mutableUsers</option> is true, the
     password defined in one of the three options will only be set when
     the user is created for the first time. After that, you are free to
     change the password with the ordinary user management commands. If
-    <literal>users.mutableUsers</literal> is false, you cannot change
+    <option>users.mutableUsers</option> is false, you cannot change
     user passwords, they will always be set according to the password
     options.
   '';
@@ -155,7 +155,7 @@ let
         default = false;
         description = ''
           If true, the user's shell will be set to
-          <literal>cfg.defaultUserShell</literal>.
+          <option>users.defaultUserShell</option>.
         '';
       };
 
@@ -163,7 +163,7 @@ let
         type = with types; uniq (nullOr str);
         default = null;
         description = ''
-          Specifies the (hashed) password for the user.
+          Specifies the hashed password for the user.
           ${passwordDescription}
         '';
       };
@@ -184,13 +184,44 @@ let
         type = with types; uniq (nullOr string);
         default = null;
         description = ''
-          The path to a file that contains the user's password. The password
+          The full path to a file that contains the user's password. The password
           file is read on each system activation. The file should contain
           exactly one line, which should be the password in an encrypted form
           that is suitable for the <literal>chpasswd -e</literal> command.
           ${passwordDescription}
         '';
       };
+
+      initialHashedPassword = mkOption {
+        type = with types; uniq (nullOr str);
+        default = null;
+        description = ''
+          Specifies the initial hashed password for the user, i.e. the
+          hashed password assigned if the user does not already
+          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.
+        '';
+      };
+
+      initialPassword = mkOption {
+        type = with types; uniq (nullOr str);
+        default = null;
+        description = ''
+          Specifies the initial password for the user, i.e. the
+          password assigned if the user does not already 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. The same caveat applies: the password specified here
+          is world-readable in the Nix store, so it should only be
+          used for guest accounts or passwords that will be changed
+          promptly.
+        '';
+      };
+
     };
 
     config = mkMerge
@@ -204,6 +235,14 @@ let
           useDefaultShell = mkDefault true;
           isSystemUser = mkDefault false;
         })
+        # If !mutableUsers, setting ‘initialPassword’ is equivalent to
+        # setting ‘password’ (and similarly for hashed passwords).
+        (mkIf (!cfg.mutableUsers && config.initialPassword != null) {
+          password = mkDefault config.initialPassword;
+        })
+        (mkIf (!cfg.mutableUsers && config.initialHashedPassword != null) {
+          hashedPassword = mkDefault config.initialHashedPassword;
+        })
       ];
 
   };
@@ -306,7 +345,8 @@ let
     users = mapAttrsToList (n: u:
       { inherit (u)
           name uid group description home shell createHome isSystemUser
-          password passwordFile hashedPassword;
+          password passwordFile hashedPassword
+          initialPassword initialHashedPassword;
       }) cfg.extraUsers;
     groups = mapAttrsToList (n: g:
       { inherit (g) name gid;
@@ -386,24 +426,12 @@ in {
       options = [ groupOpts ];
     };
 
+    # FIXME: obsolete - will remove.
     security.initialRootPassword = mkOption {
       type = types.str;
       default = "!";
       example = "";
-      description = ''
-        The (hashed) password for the root account set on initial
-        installation. The empty string denotes that root can login
-        locally without a password (but not via remote services such
-        as SSH, or indirectly via <command>su</command> or
-        <command>sudo</command>). The string <literal>!</literal>
-        prevents root from logging in using a password.
-        Note that setting this option sets
-        <literal>users.extraUsers.root.hashedPassword</literal>.
-        Also, if <literal>users.mutableUsers</literal> is false
-        you cannot change the root password manually, so in that case
-        the name of this option is a bit misleading, since it will define
-        the root password beyond the user initialisation phase.
-      '';
+      visible = false;
     };
 
   };
@@ -421,7 +449,7 @@ in {
         shell = mkDefault cfg.defaultUserShell;
         group = "root";
         extraGroups = [ "grsecurity" ];
-        hashedPassword = mkDefault config.security.initialRootPassword;
+        initialHashedPassword = mkDefault config.security.initialRootPassword;
       };
       nobody = {
         uid = ids.uids.nobody;
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
index 4d87c20559d6..3001214f90fb 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
@@ -42,6 +42,9 @@ with lib;
   # Get a console as soon as the initrd loads fbcon on EFI boot.
   boot.initrd.kernelModules = [ "fbcon" ];
 
+  # Add support for cow filesystems and their utilities
+  boot.supportedFilesystems = [ "zfs" "btrfs" ];
+
   # Allow the user to log in as root without a password.
-  security.initialRootPassword = "";
+  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 65aa11670893..b1e1d16c610d 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix
@@ -11,6 +11,9 @@ with lib;
   # Provide wicd for easy wireless configuration.
   #networking.wicd.enable = true;
 
+  # Include gparted for partitioning disks
+  environment.systemPackages = [ pkgs.gparted ];
+  
   # KDE complains if power management is disabled (to be precise, if
   # there is no power management backend such as upower).
   powerManagement.enable = true;
@@ -27,4 +30,70 @@ with lib;
       AutoLoginUser=root
       AutoLoginPass=""
     '';
+
+  # Custom kde-workspace adding some icons on the desktop
+
+  system.activationScripts.installerDesktop = let
+    openManual = pkgs.writeScript "nixos-manual.sh" ''
+      #!${pkgs.stdenv.shell}
+      cd ${config.system.build.manual.manual}/share/doc/nixos/
+      konqueror ./index.html
+    '';
+
+    desktopFile = pkgs.writeText "nixos-manual.desktop" ''
+      [Desktop Entry]
+      Version=1.0
+      Type=Application
+      Name=NixOS Manual
+      Exec=${openManual}
+      Icon=konqueror
+    '';
+
+  in ''
+    mkdir -p /root/Desktop
+    ln -sfT ${desktopFile} /root/Desktop/nixos-manual.desktop
+    ln -sfT ${pkgs.kde4.konsole}/share/applications/kde4/konsole.desktop /root/Desktop/konsole.desktop
+    ln -sfT ${pkgs.gparted}/share/applications/gparted.desktop /root/Desktop/gparted.desktop
+  '';
+
+  services.xserver.desktopManager.kde4.kdeWorkspacePackage = let
+    pkg = pkgs.kde4.kde_workspace;
+
+    plasmaInit = pkgs.writeText "00-defaultLayout.js" ''
+      loadTemplate("org.kde.plasma-desktop.defaultPanel")
+
+      for (var i = 0; i < screenCount; ++i) {
+      	var desktop = new Activity
+        desktop.name = i18n("Desktop")
+        desktop.screen = i
+        desktop.wallpaperPlugin = 'image'
+        desktop.wallpaperMode = 'SingleImage'
+
+        var folderview = desktop.addWidget("folderview");
+        folderview.writeConfig("url", "desktop:/");
+        
+        //Create more panels for other screens
+        if (i > 0){
+          var panel = new Panel
+          panel.screen = i
+          panel.location = 'bottom'
+          panel.height = screenGeometry(i).height > 1024 ? 35 : 27
+          var tasks = panel.addWidget("tasks")
+          tasks.writeConfig("showOnlyCurrentScreen", true);
+        }
+      }
+    '';
+
+  in
+    pkgs.stdenv.mkDerivation {
+      inherit (pkg) name meta;
+
+      buildCommand = ''
+        mkdir -p $out
+        cp -prf ${pkg}/* $out/
+        chmod a+w $out/share/apps/plasma-desktop/init
+        cp -f ${plasmaInit} $out/share/apps/plasma-desktop/init/00-defaultLayout.js
+      '';
+    };
+
 }
diff --git a/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix b/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
index 7d3346e4ea1f..bbf0311c04d6 100644
--- a/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
+++ b/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
@@ -76,7 +76,6 @@ in
       pkgs.ntfsprogs # for resizing NTFS partitions
       pkgs.btrfsProgs
       pkgs.jfsutils
-      pkgs.jfsrec
 
       # Some compression/archiver tools.
       pkgs.unzip
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix
index 91a30695a7a5..2c796250a982 100644
--- a/nixos/modules/installer/tools/tools.nix
+++ b/nixos/modules/installer/tools/tools.nix
@@ -1,7 +1,7 @@
 # This module generates nixos-install, nixos-rebuild,
 # nixos-generate-config, etc.
 
-{ config, pkgs, modulesPath, lib, ... }:
+{ config, pkgs, modulesPath, ... }:
 
 let
 
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index cd5e6019cefb..7388cfc9a072 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -150,8 +150,14 @@
       zookeeper = 140;
       dnsmasq = 141;
       uhub = 142;
-      yandexdisk=143;
-      collectd=144;
+      yandexdisk = 143;
+      collectd = 144;
+      consul = 145;
+      mailpile = 146;
+      redmine = 147;
+      seeks = 148;
+      prosody = 149;
+      i2pd = 150;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -272,6 +278,11 @@
       riemann = 137;
       riemanndash = 138;
       uhub = 142;
+      mailpile = 146;
+      redmine = 147;
+      seeks = 148;
+      prosody = 149;
+      i2pd = 150;
 
       # When adding a gid, make sure it doesn't match an existing uid. And don't use gids above 399!
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 470b78381988..01afea464f84 100755
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -111,7 +111,7 @@
   ./services/databases/monetdb.nix
   ./services/databases/mongodb.nix
   ./services/databases/mysql.nix
-  ./services/databases/neo4j.nix 
+  ./services/databases/neo4j.nix
   ./services/databases/openldap.nix
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
@@ -175,6 +175,7 @@
   ./services/misc/nixos-manual.nix
   ./services/misc/nix-ssh-serve.nix
   ./services/misc/phd.nix
+  ./services/misc/redmine.nix
   ./services/misc/rippled.nix
   ./services/misc/rogue.nix
   ./services/misc/siproxd.nix
@@ -215,6 +216,7 @@
   ./services/networking/cjdns.nix
   ./services/networking/cntlm.nix
   ./services/networking/connman.nix
+  ./services/networking/consul.nix
   ./services/networking/ddclient.nix
   ./services/networking/dhcpcd.nix
   ./services/networking/dhcpd.nix
@@ -229,10 +231,12 @@
   ./services/networking/gvpe.nix
   ./services/networking/haproxy.nix
   ./services/networking/hostapd.nix
+  ./services/networking/i2pd.nix
   ./services/networking/ifplugd.nix
   ./services/networking/iodined.nix
   ./services/networking/ircd-hybrid/default.nix
   ./services/networking/kippo.nix
+  ./services/networking/mailpile.nix
   ./services/networking/minidlna.nix
   ./services/networking/murmur.nix
   ./services/networking/nat.nix
@@ -249,6 +253,7 @@
   ./services/networking/polipo.nix
   ./services/networking/prayer.nix
   ./services/networking/privoxy.nix
+  ./services/networking/prosody.nix
   ./services/networking/quassel.nix
   ./services/networking/radicale.nix
   ./services/networking/radvd.nix
@@ -256,6 +261,7 @@
   ./services/networking/rpcbind.nix
   ./services/networking/sabnzbd.nix
   ./services/networking/searx.nix
+  ./services/networking/seeks.nix
   ./services/networking/spiped.nix
   ./services/networking/ssh/lshd.nix
   ./services/networking/ssh/sshd.nix
@@ -360,6 +366,7 @@
   ./tasks/filesystems/cifs.nix
   ./tasks/filesystems/ext.nix
   ./tasks/filesystems/f2fs.nix
+  ./tasks/filesystems/jfs.nix
   ./tasks/filesystems/nfs.nix
   ./tasks/filesystems/reiserfs.nix
   ./tasks/filesystems/unionfs-fuse.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 7a6f76572058..3d1412b56859 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -34,7 +34,6 @@
     pkgs.xfsprogs
     pkgs.jfsutils
     pkgs.f2fs-tools
-    #pkgs.jfsrec # disabled because of Boost dependency
 
     # Some compression/archiver tools.
     pkgs.unzip
diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix
index 623a428fc1a6..d79aff5dc553 100644
--- a/nixos/modules/programs/environment.nix
+++ b/nixos/modules/programs/environment.nix
@@ -45,7 +45,6 @@ in
         PKG_CONFIG_PATH = [ "/lib/pkgconfig" ];
         TERMINFO_DIRS = [ "/share/terminfo" ];
         PERL5LIB = [ "/lib/perl5/site_perl" ];
-        ALSA_PLUGIN_DIRS = [ "/lib/alsa-lib" ];
         KDEDIRS = [ "" ];
         STRIGI_PLUGIN_PATH = [ "/lib/strigi/" ];
         QT_PLUGIN_PATH = [ "/lib/qt4/plugins" "/lib/kde4/plugins" ];
diff --git a/nixos/modules/programs/ssmtp.nix b/nixos/modules/programs/ssmtp.nix
index 34eafd4fa846..7b00efbb4686 100644
--- a/nixos/modules/programs/ssmtp.nix
+++ b/nixos/modules/programs/ssmtp.nix
@@ -20,6 +20,7 @@ in
     networking.defaultMailServer = {
 
       directDelivery = mkOption {
+        type = types.bool;
         default = false;
         example = true;
         description = ''
@@ -35,6 +36,7 @@ in
       };
 
       hostName = mkOption {
+        type = types.str;
         example = "mail.example.org";
         description = ''
           The host name of the default mail server to use to deliver
@@ -42,7 +44,17 @@ in
         '';
       };
 
+      root = mkOption {
+        type = types.str;
+        default = "";
+        example = "root@example.org";
+        description = ''
+          The e-mail to which mail for users with UID &lt; 1000 is forwarded.
+        '';
+      };
+
       domain = mkOption {
+        type = types.str;
         default = "";
         example = "example.org";
         description = ''
@@ -51,6 +63,7 @@ in
       };
 
       useTLS = mkOption {
+        type = types.bool;
         default = false;
         example = true;
         description = ''
@@ -60,6 +73,7 @@ in
       };
 
       useSTARTTLS = mkOption {
+        type = types.bool;
         default = false;
         example = true;
         description = ''
@@ -70,6 +84,7 @@ in
       };
 
       authUser = mkOption {
+        type = types.str;
         default = "";
         example = "foo@example.org";
         description = ''
@@ -78,6 +93,7 @@ in
       };
 
       authPass = mkOption {
+        type = types.str;
         default = "";
         example = "correctHorseBatteryStaple";
         description = ''
@@ -96,6 +112,7 @@ in
       ''
         MailHub=${cfg.hostName}
         FromLineOverride=YES
+        ${if cfg.root != "" then "root=${cfg.root}" else ""}
         ${if cfg.domain != "" then "rewriteDomain=${cfg.domain}" else ""}
         UseTLS=${if cfg.useTLS then "YES" else "NO"}
         UseSTARTTLS=${if cfg.useSTARTTLS then "YES" else "NO"}
diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix
index 237da3415dc3..fc25ba6f9694 100644
--- a/nixos/modules/programs/uim.nix
+++ b/nixos/modules/programs/uim.nix
@@ -1,6 +1,6 @@
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
 
-with pkgs.lib;
+with lib;
 
 let
   cfg = config.uim;
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 019fbc721b17..ea7d9763ce64 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -130,5 +130,7 @@ in zipModules ([]
 ++ obsolete' [ "boot" "initrd" "luks" "enable" ]
 ++ obsolete' [ "programs" "bash" "enable" ]
 ++ obsolete' [ "services" "samba" "defaultShare" ]
+++ obsolete' [ "services" "syslog-ng" "serviceName" ]
+++ obsolete' [ "services" "syslog-ng" "listenToJournal" ]
 
 )
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index 9e5983691370..3773d822b16b 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -30,7 +30,7 @@ in
         type = types.bool;
         default = false;
         description = ''
-          Enable the stable grsecurity patch, based on Linux 3.2.
+          Enable the stable grsecurity patch, based on Linux 3.14.
         '';
       };
 
@@ -38,7 +38,7 @@ in
         type = types.bool;
         default = false;
         description = ''
-          Enable the testing grsecurity patch, based on Linux 3.13.
+          Enable the testing grsecurity patch, based on Linux 3.17.
         '';
       };
 
diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix
index cbd1628caaec..4c6a1c26426e 100644
--- a/nixos/modules/security/sudo.nix
+++ b/nixos/modules/security/sudo.nix
@@ -46,6 +46,14 @@ in
           <filename>sudoers</filename> file.
         '';
     };
+
+    security.sudo.extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        Extra configuration text appended to <filename>sudoers</filename>.
+      '';
+    };
   };
 
 
@@ -55,7 +63,8 @@ in
 
     security.sudo.configFile =
       ''
-        # Don't edit this file. Set the NixOS option ‘security.sudo.configFile’ instead.
+        # Don't edit this file. Set the NixOS options ‘security.sudo.configFile’
+        # and security.sudo.extraConfig instead.
 
         # Environment variables to keep for root and %wheel.
         Defaults:root,%wheel env_keep+=TERMINFO_DIRS
@@ -69,6 +78,7 @@ in
 
         # Users in the "wheel" group can do anything.
         %wheel      ALL=(ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL
+        ${cfg.extraConfig}
       '';
 
     security.setuidPrograms = [ "sudo" "sudoedit" ];
diff --git a/nixos/modules/services/backup/rsnapshot.nix b/nixos/modules/services/backup/rsnapshot.nix
index 091b5cfd4d59..fb25bd9dd1e8 100644
--- a/nixos/modules/services/backup/rsnapshot.nix
+++ b/nixos/modules/services/backup/rsnapshot.nix
@@ -39,11 +39,20 @@ in
           as retain options.
         '';
       };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.rsnapshot;
+        example = literalExample "pkgs.rsnapshotGit";
+        description = ''
+          RSnapshot package to use.
+        '';
+      };
     };
   };
 
   config = mkIf cfg.enable (let
-    myRsnapshot = pkgs.rsnapshot.override { configFile = rsnapshotCfg; };
+    myRsnapshot = cfg.package.override { configFile = rsnapshotCfg; };
     rsnapshotCfg = with pkgs; writeText "gen-rsnapshot.conf" (''
         config_version	1.2
         cmd_cp	${coreutils}/bin/cp
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index 2ef49a95166e..575034c93ab2 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -19,7 +19,7 @@ let
     org.neo4j.server.webadmin.rrdb.location=${cfg.dataDir}/data/rrd
     org.neo4j.server.webadmin.data.uri=/db/data/
     org.neo4j.server.webadmin.management.uri=/db/manage/
-    org.neo4j.server.db.tuning.properties=${pkgs.neo4j}/share/neo4j/conf/neo4j.properties
+    org.neo4j.server.db.tuning.properties=${cfg.package}/share/neo4j/conf/neo4j.properties
     org.neo4j.server.manage.console_engines=shell
     ${cfg.extraServerConfig}
   '';
@@ -46,6 +46,12 @@ in {
       type = types.uniq types.bool;
     };
 
+    package = mkOption {
+      description = "Neo4j package to use.";
+      default = pkgs.neo4j;
+      type = types.package;
+    };
+
     host = mkOption {
       description = "Neo4j listen address.";
       default = "127.0.0.1";
@@ -119,7 +125,7 @@ in {
       after = [ "network-interfaces.target" ];
       environment = { NEO4J_INSTANCE = cfg.dataDir; };
       serviceConfig = {
-        ExecStart = "${pkgs.neo4j}/bin/neo4j console";
+        ExecStart = "${cfg.package}/bin/neo4j console";
         User = "neo4j";
         PermissionsStartOnly = true;
       };
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index 01c55479b2b4..de14c56f7971 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -225,14 +225,14 @@ in
         # Wait for PostgreSQL to be ready to accept connections.
         postStart =
           ''
-            while ! psql postgres -c "" 2> /dev/null; do
+            while ! psql --port=${toString cfg.port} postgres -c "" 2> /dev/null; do
                 if ! kill -0 "$MAINPID"; then exit 1; fi
                 sleep 0.1
             done
 
             if test -e "${cfg.dataDir}/.first_startup"; then
               ${optionalString (cfg.initialScript != null) ''
-                cat "${cfg.initialScript}" | psql postgres
+                cat "${cfg.initialScript}" | psql --port=${toString cfg.port} postgres
               ''}
               rm -f "${cfg.dataDir}/.first_startup"
             fi
diff --git a/nixos/modules/services/hardware/thermald.nix b/nixos/modules/services/hardware/thermald.nix
index 5233794a20cc..88c3f99aed4e 100644
--- a/nixos/modules/services/hardware/thermald.nix
+++ b/nixos/modules/services/hardware/thermald.nix
@@ -19,6 +19,8 @@ in {
 
   ###### implementation
   config = mkIf cfg.enable {
+    services.dbus.packages = [ pkgs.thermald ];
+
     systemd.services.thermald = {
       description = "Thermal Daemon Service";
       wantedBy = [ "multi-user.target" ];
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 068d14217a2c..095a97338d52 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -168,7 +168,6 @@ in
     hardware.firmware = mkOption {
       type = types.listOf types.path;
       default = [];
-      example = [ "/root/my-firmware" ];
       description = ''
         List of directories containing firmware files.  Such files
         will be loaded automatically if the kernel asks for them
@@ -177,10 +176,10 @@ in
         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 /root/test-firmware 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.
+        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.
       '';
       apply = list: pkgs.buildEnv {
         name = "firmware";
@@ -244,6 +243,11 @@ in
           echo "regenerating udev hardware database..."
           ${config.systemd.package}/bin/udevadm hwdb --update && ln -sfn ${config.systemd.package} /var/lib/udev/prev-systemd
         fi
+
+        # 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
+        fi
       '';
 
     systemd.services.systemd-udevd =
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index 6887ab1e8052..0186452de95e 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -21,6 +21,7 @@ in
 
       config = mkOption {
         default = "";
+        type = types.lines;
         description = ''
           The contents of the logrotate config file
         '';
diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix
index df81ac142dc3..117ee1c900f5 100644
--- a/nixos/modules/services/logging/logstash.nix
+++ b/nixos/modules/services/logging/logstash.nix
@@ -4,6 +4,16 @@ with lib;
 
 let
   cfg = config.services.logstash;
+  pluginPath = lib.concatStringsSep ":" cfg.plugins;
+  havePluginPath = lib.length cfg.plugins > 0;
+  ops = lib.optionalString;
+  verbosityFlag = {
+    debug = "--debug";
+    info  = "--verbose";
+    warn  = ""; # intentionally empty
+    error = "--quiet";
+    fatal = "--silent";
+  }."${cfg.logLevel}";
 
 in
 
@@ -20,12 +30,56 @@ in
         description = "Enable logstash.";
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.logstash;
+        example = literalExample "pkgs.logstash";
+        description = "Logstash package to use.";
+      };
+
+      plugins = mkOption {
+        type = types.listOf types.path;
+        default = [ ];
+        example = literalExample "[ pkgs.logstash-contrib ]";
+        description = "The paths to find other logstash plugins in.";
+      };
+
+      logLevel = mkOption {
+        type = types.enum [ "debug" "info" "warn" "error" "fatal" ];
+        default = "warn";
+        description = "Logging verbosity level.";
+      };
+
+      watchdogTimeout = mkOption {
+        type = types.int;
+        default = 10;
+        description = "Set watchdog timeout value in seconds.";
+      };
+
+      filterWorkers = mkOption {
+        type = types.int;
+        default = 1;
+        description = "The quantity of filter workers to run.";
+      };
+
       enableWeb = mkOption {
         type = types.bool;
         default = false;
         description = "Enable the logstash web interface.";
       };
 
+      address = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        description = "Address on which to start webserver.";
+      };
+
+      port = mkOption {
+        type = types.str;
+        default = "9292";
+        description = "Port on which to start webserver.";
+      };
+
       inputConfig = mkOption {
         type = types.lines;
         default = ''stdin { type => "example" }'';
@@ -79,19 +133,26 @@ in
       wantedBy = [ "multi-user.target" ];
       environment = { JAVA_HOME = jre; };
       serviceConfig = {
-        ExecStart = "${logstash}/bin/logstash agent -f ${writeText "logstash.conf" ''
-          input {
-            ${cfg.inputConfig}
-          }
+        ExecStart =
+          "${cfg.package}/bin/logstash agent " +
+          "-w ${toString cfg.filterWorkers} " +
+          ops havePluginPath "--pluginpath ${pluginPath} " +
+          "${verbosityFlag} " +
+          "--watchdog-timeout ${toString cfg.watchdogTimeout} " +
+          "-f ${writeText "logstash.conf" ''
+            input {
+              ${cfg.inputConfig}
+            }
 
-          filter {
-            ${cfg.filterConfig}
-          }
+            filter {
+              ${cfg.filterConfig}
+            }
 
-          output {
-            ${cfg.outputConfig}
-          }
-        ''} ${optionalString cfg.enableWeb "-- web"}";
+            output {
+              ${cfg.outputConfig}
+            }
+          ''} " +
+          ops cfg.enableWeb "-- web -a ${cfg.address} -p ${cfg.port}";
       };
     };
   };
diff --git a/nixos/modules/services/logging/syslog-ng.nix b/nixos/modules/services/logging/syslog-ng.nix
index 4a16b19134a0..2bf6d1ff7904 100644
--- a/nixos/modules/services/logging/syslog-ng.nix
+++ b/nixos/modules/services/logging/syslog-ng.nix
@@ -7,8 +7,7 @@ let
   cfg = config.services.syslog-ng;
 
   syslogngConfig = pkgs.writeText "syslog-ng.conf" ''
-    @version: 3.5
-    @include "scl.conf"
+    ${cfg.configHeader}
     ${cfg.extraConfig}
   '';
 
@@ -44,15 +43,6 @@ in {
           The package providing syslog-ng binaries.
         '';
       };
-      serviceName = mkOption {
-        type = types.str;
-        default = "syslog-ng";
-        description = ''
-          The name of the systemd service that runs syslog-ng. Set this to
-          <literal>syslog</literal> if you want journald to automatically
-          forward all logs to syslog-ng.
-        '';
-      };
       extraModulePaths = mkOption {
         type = types.listOf types.str;
         default = [];
@@ -72,16 +62,28 @@ in {
           Configuration added to the end of <literal>syslog-ng.conf</literal>.
         '';
       };
+      configHeader = mkOption {
+        type = types.lines;
+        default = ''
+          @version: 3.6
+          @include "scl.conf"
+        '';
+        description = ''
+          The very first lines of the configuration file. Should usually contain
+          the syslog-ng version header.
+        '';
+      };
     };
   };
 
   config = mkIf cfg.enable {
-    systemd.services."${cfg.serviceName}" = {
-      wantedBy = [ "multi-user.target" ];
+    systemd.services.syslog-ng = {
+      description = "syslog-ng daemon";
       preStart = "mkdir -p /{var,run}/syslog-ng";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "multi-user.target" ]; # makes sure hostname etc is set
       serviceConfig = {
         Type = "notify";
-        Sockets = "syslog.socket";
         StandardOutput = "null";
         Restart = "on-failure";
         ExecStart = "${cfg.package}/sbin/syslog-ng ${concatStringsSep " " syslogngOptions}";
diff --git a/nixos/modules/services/misc/gitolite.nix b/nixos/modules/services/misc/gitolite.nix
index 961af48e0f86..462b68aa0a1c 100644
--- a/nixos/modules/services/misc/gitolite.nix
+++ b/nixos/modules/services/misc/gitolite.nix
@@ -15,14 +15,21 @@ in
         default = false;
         description = ''
           Enable gitolite management under the
-          <literal>gitolite</literal> user. The Gitolite home
-          directory is <literal>/var/lib/gitolite</literal>. After
+          <literal>gitolite</literal> user. After
           switching to a configuration with Gitolite enabled, you can
           then run <literal>git clone
           gitolite@host:gitolite-admin.git</literal> to manage it further.
         '';
       };
 
+      dataDir = mkOption {
+        type = types.str;
+        default = "/var/lib/gitolite";
+        description = ''
+          Gitolite home directory (used to store all the repositories).
+        '';
+      };
+
       adminPubkey = mkOption {
         type = types.str;
         description = ''
@@ -45,7 +52,7 @@ in
   config = mkIf cfg.enable {
     users.extraUsers.gitolite = {
       description     = "Gitolite user";
-      home            = "/var/lib/gitolite";
+      home            = cfg.dataDir;
       createHome      = true;
       uid             = config.ids.uids.gitolite;
       useDefaultShell = true;
@@ -61,7 +68,7 @@ in
 
       path = [ pkgs.gitolite pkgs.git pkgs.perl pkgs.bash pkgs.openssh ];
       script = ''
-        cd /var/lib/gitolite
+        cd ${cfg.dataDir}
         mkdir -p .gitolite/logs
         if [ ! -d repositories ]; then
           gitolite setup -pk ${pubkeyFile}
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index c98c0511b566..4b398979fbaa 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -36,6 +36,7 @@ let
         # /etc/nixos/configuration.nix.  Do not edit it!
         build-users-group = nixbld
         build-max-jobs = ${toString (cfg.maxJobs)}
+        build-cores = ${toString (cfg.buildCores)}
         build-use-chroot = ${if cfg.useChroot then "true" else "false"}
         build-chroot-dirs = ${toString cfg.chrootDirs} /bin/sh=${sh} $(echo $extraPaths)
         binary-caches = ${toString cfg.binaryCaches}
@@ -74,6 +75,19 @@ in
         ";
       };
 
+      buildCores = mkOption {
+        type = types.int;
+        default = 1;
+        example = 64;
+        description = ''
+          This option defines the maximum number of concurrent tasks during
+          one build. It affects, e.g., -j option for make. The default is 1.
+          Some builds may become non-deterministic with this option; use with
+          care! Packages will only be affected if enableParallelBuilding is
+          set for them.
+        '';
+      };
+
       useChroot = mkOption {
         type = types.bool;
         default = false;
diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix
new file mode 100644
index 000000000000..d7e64590f503
--- /dev/null
+++ b/nixos/modules/services/misc/redmine.nix
@@ -0,0 +1,222 @@
+{ config, lib, pkgs, ... }:
+
+# TODO: support non-postgresql
+
+with lib;
+
+let
+  cfg = config.services.redmine;
+
+  ruby = pkgs.ruby;
+  rubyLibs = pkgs.rubyLibs;
+
+  databaseYml = ''
+    production:
+      adapter: postgresql
+      database: ${cfg.databaseName}
+      host: ${cfg.databaseHost}
+      password: ${cfg.databasePassword}
+      username: ${cfg.databaseUsername}
+      encoding: utf8
+  '';
+
+  configurationYml = ''
+    default:
+      # Absolute path to the directory where attachments are stored.
+      # The default is the 'files' directory in your Redmine instance.
+      # Your Redmine instance needs to have write permission on this
+      # directory.
+      # Examples:
+      # attachments_storage_path: /var/redmine/files
+      # attachments_storage_path: D:/redmine/files
+      attachments_storage_path: ${cfg.stateDir}/files
+
+      # Absolute path to the SCM commands errors (stderr) log file.
+      # The default is to log in the 'log' directory of your Redmine instance.
+      # Example:
+      # scm_stderr_log_file: /var/log/redmine_scm_stderr.log
+      scm_stderr_log_file: ${cfg.stateDir}/redmine_scm_stderr.log
+
+      ${cfg.extraConfig}
+  '';
+
+  unpackTheme = unpack "theme";
+  unpackPlugin = unpack "plugin";
+  unpack = id: (name: source:
+    pkgs.stdenv.mkDerivation {
+      name = "redmine-${id}-${name}";
+      buildInputs = [ pkgs.unzip ];
+      buildCommand = ''
+        mkdir -p $out
+        cd $out
+        unpackFile ${source}
+      '';
+    });
+
+in {
+
+  options = {
+    services.redmine = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the redmine service.
+        '';
+      };
+
+      stateDir = mkOption {
+        type = types.str;
+        default = "/var/redmine";
+        description = "The state directory, logs and plugins are stored here";
+      };
+
+      extraConfig = mkOption {
+        type = types.str;
+        default = "";
+        description = "Extra configuration in configuration.yml";
+      };
+
+      themes = mkOption {
+        type = types.attrsOf types.path;
+        default = {};
+        description = "Set of themes";
+      };
+
+      plugins = mkOption {
+        type = types.attrsOf types.path;
+        default = {};
+        description = "Set of plugins";
+      };
+
+      #databaseType = mkOption {
+      #  type = types.str;
+      #  default = "postgresql";
+      #  description = "Type of database";
+      #};
+
+      databaseHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = "Database hostname";
+      };
+
+      databasePassword = mkOption {
+        type = types.str;
+        default = "";
+        description = "Database user password";
+      };
+
+      databaseName = mkOption {
+        type = types.str;
+        default = "redmine";
+        description = "Database name";
+      };
+
+      databaseUsername = mkOption {
+        type = types.str;
+        default = "redmine";
+        description = "Database user";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    assertions = [
+      { assertion = cfg.databasePassword != "";
+        message = "databasePassword must be set";
+      }
+    ];
+
+    users.extraUsers = [
+      { name = "redmine";
+        group = "redmine";
+        uid = config.ids.uids.redmine;
+      } ];
+
+    users.extraGroups = [
+      { name = "redmine";
+        gid = config.ids.gids.redmine;
+      } ];
+
+    systemd.services.redmine = {
+      after = [ "network.target" "postgresql.service" ];
+      wantedBy = [ "multi-user.target" ];
+      environment.RAILS_ENV = "production";
+      environment.RAILS_ETC = "${cfg.stateDir}/config";
+      environment.RAILS_LOG = "${cfg.stateDir}/log";
+      environment.RAILS_VAR = "${cfg.stateDir}/var";
+      environment.RAILS_CACHE = "${cfg.stateDir}/cache";
+      environment.RAILS_PLUGINS = "${cfg.stateDir}/plugins";
+      environment.RAILS_PUBLIC = "${cfg.stateDir}/public";
+      environment.RAILS_TMP = "${cfg.stateDir}/tmp";
+      environment.SCHEMA = "${cfg.stateDir}/cache/schema.db";
+      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 = "${rubyLibs.bundler}/lib/ruby/gems/1.9";
+      path = with pkgs; [
+        imagemagickBig
+        subversion
+        mercurial
+        cvs
+        config.services.postgresql.package
+        bazaar
+        gitAndTools.git
+        # once we build binaries for darc enable it
+        #darcs
+      ];
+      preStart = ''
+        # TODO: use env vars
+        for i in plugins public/plugin_assets db files log config cache var/files tmp; do
+          mkdir -p ${cfg.stateDir}/$i
+        done
+
+        chown -R redmine:redmine ${cfg.stateDir}
+        chmod -R 755 ${cfg.stateDir}
+
+        rm -rf ${cfg.stateDir}/public/*
+        cp -R ${pkgs.redmine}/share/redmine/public/* ${cfg.stateDir}/public/
+        for theme in ${concatStringsSep " " (mapAttrsToList unpackTheme cfg.themes)}; do
+          ln -fs $theme/* ${cfg.stateDir}/public/themes/
+        done
+
+        rm -rf ${cfg.stateDir}/plugins/*
+        for plugin in ${concatStringsSep " " (mapAttrsToList unpackPlugin cfg.plugins)}; do
+          ln -fs $plugin/* ${cfg.stateDir}/plugins/''${plugin##*-redmine-plugin-}
+        done
+
+        ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.stateDir}/config/database.yml
+        ln -fs ${pkgs.writeText "configuration.yml" configurationYml} ${cfg.stateDir}/config/configuration.yml
+
+        if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then
+          if ! test -e "${cfg.stateDir}/db-created"; then
+            psql postgres -c "CREATE ROLE redmine WITH LOGIN NOCREATEDB NOCREATEROLE NOCREATEUSER ENCRYPTED PASSWORD '${cfg.databasePassword}'"
+            ${config.services.postgresql.package}/bin/createdb --owner redmine redmine || true
+            touch "${cfg.stateDir}/db-created"
+          fi
+        fi
+
+        cd ${pkgs.redmine}/share/redmine/
+        ${ruby}/bin/rake db:migrate
+        ${ruby}/bin/rake redmine:plugins:migrate
+        ${ruby}/bin/rake redmine:load_default_data
+        ${ruby}/bin/rake generate_secret_token
+      '';
+
+      serviceConfig = {
+        PermissionsStartOnly = true; # preStart must be run as root
+        Type = "simple";
+        User = "redmine";
+        Group = "redmine";
+        TimeoutSec = "300";
+        WorkingDirectory = "${pkgs.redmine}/share/redmine";
+        ExecStart="${ruby}/bin/ruby ${pkgs.redmine}/share/redmine/script/rails server webrick -e production -P ${cfg.stateDir}/redmine.pid";
+      };
+
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 3d97c31b7a17..bbbbcbccb9be 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -24,6 +24,8 @@ let
     GRAPHITE_URL = cfg.seyren.graphiteUrl;
   } // cfg.seyren.extraConfig;
 
+  pagerConfig = pkgs.writeText "alarms.yaml" cfg.pager.alerts;
+
   configDir = pkgs.buildEnv {
     name = "graphite-config";
     paths = lists.filter (el: el != null) [
@@ -83,13 +85,21 @@ in {
 
     api = {
       enable = mkOption {
-        description = "Whether to enable graphite api.";
+        description = ''
+          Whether to enable graphite api. Graphite api is lightweight alternative
+          to graphite web, with api and without dashboard. It's advised to use
+          grafana as alternative dashboard and influxdb as alternative to
+          graphite carbon.
+
+          For more information visit
+          <link xlink:href="http://graphite-api.readthedocs.org/en/latest/"/>
+        '';
         default = false;
         type = types.uniq types.bool;
       };
 
       finders = mkOption {
-        description = "List of finder plugins load.";
+        description = "List of finder plugins to load.";
         default = [];
         example = [ pkgs.python27Packages.graphite_influxdb ];
         type = types.listOf types.package;
@@ -296,175 +306,247 @@ in {
         example = literalExample ''
           {
             GRAPHITE_USERNAME = "user";
-            GRAPHITE_PASSWORD = "pass"; 
+            GRAPHITE_PASSWORD = "pass";
           }
         '';
       };
     };
-  };
 
-  ###### implementation
+    pager = {
+      enable = mkOption {
+        description = ''
+          Whether to enable graphite-pager service. For more information visit
+          <link xlink:href="https://github.com/seatgeek/graphite-pager"/>
+        '';
+        default = false;
+        type = types.uniq types.bool;
+      };
 
-  config = mkIf (
-    cfg.carbon.enableAggregator ||
-    cfg.carbon.enableCache ||
-    cfg.carbon.enableRelay ||
-    cfg.web.enable ||
-    cfg.api.enable ||
-    cfg.seyren.enable
-  ) {
-    systemd.services.carbonCache = {
-      enable = cfg.carbon.enableCache;
-      description = "Graphite Data Storage Backend";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
-      environment = carbonEnv;
-      serviceConfig = {
-        ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-cache"}";
-        User = "graphite";
-        Group = "graphite";
-        PermissionsStartOnly = true;
-      };
-      preStart = ''
-        mkdir -p ${cfg.dataDir}/whisper
-        chmod 0700 ${cfg.dataDir}/whisper
-        chown -R graphite:graphite ${cfg.dataDir}
-      '';
-    };
+      redisUrl = mkOption {
+        description = "Redis connection string.";
+        default = "redis://localhost:${toString config.services.redis.port}/";
+        type = types.str;
+      };
 
-    systemd.services.carbonAggregator = {
-      enable = cfg.carbon.enableAggregator;
-      description = "Carbon Data Aggregator";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
-      environment = carbonEnv;
-      serviceConfig = {
-        ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-aggregator"}";
-        User = "graphite";
-        Group = "graphite";
+      graphiteUrl = mkOption {
+        description = "URL to your graphite service.";
+        default = "http://${cfg.web.host}:${toString cfg.web.port}";
+        type = types.str;
       };
-    };
 
-    systemd.services.carbonRelay = {
-      enable = cfg.carbon.enableRelay;
-      description = "Carbon Data Relay";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
-      environment = carbonEnv;
-      serviceConfig = {
-        ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-relay"}";
-        User = "graphite";
-        Group = "graphite";
+      alerts = mkOption {
+        description = "Alerts configuration for graphite-pager.";
+        default = ''
+          alerts:
+            - target: constantLine(100)
+              warning: 90
+              critical: 200
+              name: Test
+        '';
+        example = literalExample ''
+          pushbullet_key: pushbullet_api_key
+          alerts:
+            - target: stats.seatgeek.app.deal_quality.venue_info_cache.hit
+              warning: .5
+              critical: 1
+              name: Deal quality venue cache hits
+        '';
+        type = types.lines;
       };
     };
+  };
 
-    systemd.services.graphiteWeb = {
-      enable = cfg.web.enable;
-      description = "Graphite Web Interface";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
-      path = [ pkgs.perl ];
-      environment = {
-        PYTHONPATH = "${pkgs.python27Packages.graphite_web}/lib/python2.7/site-packages";
-        DJANGO_SETTINGS_MODULE = "graphite.settings";
-        GRAPHITE_CONF_DIR = configDir;
-        GRAPHITE_STORAGE_DIR = dataDir;
-      };
-      serviceConfig = {
-        ExecStart = ''
-          ${pkgs.python27Packages.waitress}/bin/waitress-serve \
-          --host=${cfg.web.host} --port=${toString cfg.web.port} \
-          --call django.core.handlers.wsgi:WSGIHandler'';
-        User = "graphite";
-        Group = "graphite";
-        PermissionsStartOnly = true;
-      };
-      preStart = ''
-        if ! test -e ${dataDir}/db-created; then
-          mkdir -p ${dataDir}/{whisper/,log/webapp/}
-          chmod 0700 ${dataDir}/{whisper/,log/webapp/}
-
-          # populate database
-          ${pkgs.python27Packages.graphite_web}/bin/manage-graphite.py syncdb --noinput
-
-          # create index
-          ${pkgs.python27Packages.graphite_web}/bin/build-index.sh
-
-          touch ${dataDir}/db-created
+  ###### implementation
 
+  config = mkMerge [
+    (mkIf cfg.carbon.enableCache {
+      systemd.services.carbonCache = {
+        description = "Graphite Data Storage Backend";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" ];
+        environment = carbonEnv;
+        serviceConfig = {
+          ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-cache"}";
+          User = "graphite";
+          Group = "graphite";
+          PermissionsStartOnly = true;
+        };
+        preStart = ''
+          mkdir -p ${cfg.dataDir}/whisper
+          chmod 0700 ${cfg.dataDir}/whisper
           chown -R graphite:graphite ${cfg.dataDir}
-        fi
-      '';
-    };
-
-    systemd.services.graphiteApi = {
-      enable = cfg.api.enable;
-      description = "Graphite Api Interface";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
-      environment = {
-        PYTHONPATH =
-          "${cfg.api.package}/lib/python2.7/site-packages:" +
-          concatMapStringsSep ":" (f: f + "/lib/python2.7/site-packages") cfg.api.finders;
-        GRAPHITE_API_CONFIG = graphiteApiConfig;
-        LD_LIBRARY_PATH = "${pkgs.cairo}/lib";
-      };
-      serviceConfig = {
-        ExecStart = ''
-          ${pkgs.python27Packages.waitress}/bin/waitress-serve \
-          --host=${cfg.api.host} --port=${toString cfg.api.port} \
-          graphite_api.app:app 
         '';
-        User = "graphite";
-        Group = "graphite";
-        PermissionsStartOnly = true;
       };
-      preStart = ''
-        if ! test -e ${dataDir}/db-created; then
-          mkdir -p ${dataDir}/cache/
-          chmod 0700 ${dataDir}/cache/
-
-          touch ${dataDir}/db-created
-
-          chown -R graphite:graphite ${cfg.dataDir}
-        fi
-      '';
-    };
-
-    systemd.services.seyren = {
-      enable = cfg.seyren.enable;
-      description = "Graphite Alerting Dashboard";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" "mongodb.service" ];
-      environment = seyrenConfig;
-      serviceConfig = {
-        ExecStart = "${pkgs.seyren}/bin/seyren -httpPort ${toString cfg.seyren.port}";
-        WorkingDirectory = dataDir;
-        User = "graphite";
-        Group = "graphite"; 
-      };
-      preStart = ''
-        if ! test -e ${dataDir}/db-created; then
-          mkdir -p ${dataDir}
-          chown -R graphite:graphite ${dataDir}
-        fi
-      '';
-    };
-
-    services.mongodb.enable = mkDefault cfg.seyren.enable;
+    })
+
+    (mkIf cfg.carbon.enableAggregator {
+      systemd.services.carbonAggregator = {
+        enable = cfg.carbon.enableAggregator;
+        description = "Carbon Data Aggregator";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" ];
+        environment = carbonEnv;
+        serviceConfig = {
+          ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-aggregator"}";
+          User = "graphite";
+          Group = "graphite";
+        };
+      };
+    })
+
+    (mkIf cfg.carbon.enableRelay {
+      systemd.services.carbonRelay = {
+        description = "Carbon Data Relay";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" ];
+        environment = carbonEnv;
+        serviceConfig = {
+          ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-relay"}";
+          User = "graphite";
+          Group = "graphite";
+        };
+      };
+    })
+
+    (mkIf (cfg.carbon.enableCache || cfg.carbon.enableAggregator || cfg.carbon.enableRelay) {
+      environment.systemPackages = [
+        pkgs.pythonPackages.carbon
+      ];
+    })
+
+    (mkIf cfg.web.enable {
+      systemd.services.graphiteWeb = {
+        description = "Graphite Web Interface";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" ];
+        path = [ pkgs.perl ];
+        environment = {
+          PYTHONPATH = "${pkgs.python27Packages.graphite_web}/lib/python2.7/site-packages";
+          DJANGO_SETTINGS_MODULE = "graphite.settings";
+          GRAPHITE_CONF_DIR = configDir;
+          GRAPHITE_STORAGE_DIR = dataDir;
+        };
+        serviceConfig = {
+          ExecStart = ''
+            ${pkgs.python27Packages.waitress}/bin/waitress-serve \
+            --host=${cfg.web.host} --port=${toString cfg.web.port} \
+            --call django.core.handlers.wsgi:WSGIHandler'';
+          User = "graphite";
+          Group = "graphite";
+          PermissionsStartOnly = true;
+        };
+        preStart = ''
+          if ! test -e ${dataDir}/db-created; then
+            mkdir -p ${dataDir}/{whisper/,log/webapp/}
+            chmod 0700 ${dataDir}/{whisper/,log/webapp/}
+
+            # populate database
+            ${pkgs.python27Packages.graphite_web}/bin/manage-graphite.py syncdb --noinput
+
+            # create index
+            ${pkgs.python27Packages.graphite_web}/bin/build-index.sh
+
+            touch ${dataDir}/db-created
+
+            chown -R graphite:graphite ${cfg.dataDir}
+          fi
+        '';
+      };
 
-    environment.systemPackages = [
-      pkgs.pythonPackages.carbon
-      pkgs.python27Packages.graphite_web
-      pkgs.python27Packages.waitress
-    ];
+      environment.systemPackages = [ pkgs.python27Packages.graphite_web ];
+    })
+
+    (mkIf cfg.api.enable {
+      systemd.services.graphiteApi = {
+        description = "Graphite Api Interface";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" ];
+        environment = {
+          PYTHONPATH =
+            "${cfg.api.package}/lib/python2.7/site-packages:" +
+            concatMapStringsSep ":" (f: f + "/lib/python2.7/site-packages") cfg.api.finders;
+          GRAPHITE_API_CONFIG = graphiteApiConfig;
+          LD_LIBRARY_PATH = "${pkgs.cairo}/lib";
+        };
+        serviceConfig = {
+          ExecStart = ''
+            ${pkgs.python27Packages.waitress}/bin/waitress-serve \
+            --host=${cfg.api.host} --port=${toString cfg.api.port} \
+            graphite_api.app:app
+          '';
+          User = "graphite";
+          Group = "graphite";
+          PermissionsStartOnly = true;
+        };
+        preStart = ''
+          if ! test -e ${dataDir}/db-created; then
+            mkdir -p ${dataDir}/cache/
+            chmod 0700 ${dataDir}/cache/
+
+            touch ${dataDir}/db-created
+
+            chown -R graphite:graphite ${cfg.dataDir}
+          fi
+        '';
+      };
+    })
+
+    (mkIf cfg.seyren.enable {
+      systemd.services.seyren = {
+        description = "Graphite Alerting Dashboard";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" "mongodb.service" ];
+        environment = seyrenConfig;
+        serviceConfig = {
+          ExecStart = "${pkgs.seyren}/bin/seyren -httpPort ${toString cfg.seyren.port}";
+          WorkingDirectory = dataDir;
+          User = "graphite";
+          Group = "graphite";
+        };
+        preStart = ''
+          if ! test -e ${dataDir}/db-created; then
+            mkdir -p ${dataDir}
+            chown -R graphite:graphite ${dataDir}
+          fi
+        '';
+      };
 
-    users.extraUsers = singleton {
-      name = "graphite";
-      uid = config.ids.uids.graphite;
-      description = "Graphite daemon user";
-      home = dataDir;
-    };
-    users.extraGroups.graphite.gid = config.ids.gids.graphite;
-  };
+      services.mongodb.enable = mkDefault true;
+    })
+
+    (mkIf cfg.pager.enable {
+      systemd.services.graphitePager = {
+        description = "Graphite Pager Alerting Daemon";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" "redis.service" ];
+        environment = {
+          REDIS_URL = cfg.pager.redisUrl;
+          GRAPHITE_URL = cfg.pager.graphiteUrl;
+        };
+        serviceConfig = {
+          ExecStart = "${pkgs.pythonPackages.graphite_pager}/bin/graphite-pager --config ${pagerConfig}";
+          User = "graphite";
+          Group = "graphite";
+        };
+      };
+
+      services.redis.enable = mkDefault true;
+
+      environment.systemPackages = [ pkgs.pythonPackages.graphite_pager ];
+    })
+
+    (mkIf (
+      cfg.carbon.enableCache || cfg.carbon.enableAggregator || cfg.carbon.enableRelay ||
+      cfg.web.enable || cfg.api.enable ||
+      cfg.seyren.enable || cfg.pager.enable
+     ) {
+      users.extraUsers = singleton {
+        name = "graphite";
+        uid = config.ids.uids.graphite;
+        description = "Graphite daemon user";
+        home = dataDir;
+      };
+      users.extraGroups.graphite.gid = config.ids.gids.graphite;
+    })
+  ];
 }
diff --git a/nixos/modules/services/monitoring/zabbix-server.nix b/nixos/modules/services/monitoring/zabbix-server.nix
index ca283ea2a99f..acd1279ddf47 100644
--- a/nixos/modules/services/monitoring/zabbix-server.nix
+++ b/nixos/modules/services/monitoring/zabbix-server.nix
@@ -32,6 +32,8 @@ let
       ${optionalString (cfg.dbPassword != "") ''
         DBPassword = ${cfg.dbPassword}
       ''}
+
+      ${config.services.zabbixServer.extraConfig}
     '';
 
   useLocalPostgres = cfg.dbServer == "localhost" || cfg.dbServer == "";
@@ -46,6 +48,7 @@ in
 
     services.zabbixServer.enable = mkOption {
       default = false;
+      type = types.bool;
       description = ''
         Whether to run the Zabbix server on this machine.
       '';
@@ -53,6 +56,7 @@ in
 
     services.zabbixServer.dbServer = mkOption {
       default = "localhost";
+      type = types.str;
       description = ''
         Hostname or IP address of the database server.
         Use an empty string ("") to use peer authentication.
@@ -61,9 +65,18 @@ in
 
     services.zabbixServer.dbPassword = mkOption {
       default = "";
+      type = types.str;
       description = "Password used to connect to the database server.";
     };
 
+    services.zabbixServer.extraConfig = mkOption {
+      default = "";
+      type = types.lines;
+      description = ''
+        Configuration that is injected verbatim into the configuration file.
+      '';
+    };
+
   };
 
   ###### implementation
diff --git a/nixos/modules/services/network-filesystems/nfsd.nix b/nixos/modules/services/network-filesystems/nfsd.nix
index 57d56cd72877..893df51fc1f6 100644
--- a/nixos/modules/services/network-filesystems/nfsd.nix
+++ b/nixos/modules/services/network-filesystems/nfsd.nix
@@ -64,6 +64,13 @@ in
             Use fixed port for rpc.mountd, usefull if server is behind firewall.
           '';
         };
+
+        lockdPort = mkOption {
+          default = 0;
+          description = ''
+            Fix the lockd port number. This can help setting firewall rules for NFS.
+          '';
+        };
       };
 
     };
@@ -104,6 +111,9 @@ in
             # Create a state directory required by NFSv4.
             mkdir -p /var/lib/nfs/v4recovery
 
+            ${pkgs.procps}/sbin/sysctl -w fs.nfs.nlm_tcpport=${builtins.toString cfg.lockdPort}
+            ${pkgs.procps}/sbin/sysctl -w fs.nfs.nlm_udpport=${builtins.toString cfg.lockdPort}
+
             rpc.nfsd \
               ${if cfg.hostName != null then "-H ${cfg.hostName}" else ""} \
               ${builtins.toString cfg.nproc}
diff --git a/nixos/modules/services/network-filesystems/yandex-disk.nix b/nixos/modules/services/network-filesystems/yandex-disk.nix
index df9626d17c92..982b6ca5ea7b 100644
--- a/nixos/modules/services/network-filesystems/yandex-disk.nix
+++ b/nixos/modules/services/network-filesystems/yandex-disk.nix
@@ -1,6 +1,6 @@
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
 
-with pkgs.lib;
+with lib;
 
 let
 
diff --git a/nixos/modules/services/networking/atftpd.nix b/nixos/modules/services/networking/atftpd.nix
index ab9f8650f0f8..47465ba948a9 100644
--- a/nixos/modules/services/networking/atftpd.nix
+++ b/nixos/modules/services/networking/atftpd.nix
@@ -1,8 +1,8 @@
 # NixOS module for atftpd TFTP server
 
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
 
-with pkgs.lib;
+with lib;
 
 let
 
diff --git a/nixos/modules/services/networking/cjdns-hosts.sh b/nixos/modules/services/networking/cjdns-hosts.sh
new file mode 100644
index 000000000000..8a2b47e52143
--- /dev/null
+++ b/nixos/modules/services/networking/cjdns-hosts.sh
@@ -0,0 +1,11 @@
+pubs=($pubs)
+hosts=($hosts)
+
+lines="''\n"
+for ((i = 0; i < ${#pubs[*]}; i++)); do
+    addr=$($cjdns/bin/publictoip6 ${pubs[i]})
+    lines="${lines}$addr ${hosts[i]}\n"
+done
+lines="${lines}''"
+
+echo -ne $lines > $out
diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix
index 7192b8b7a0e0..be0acb27324a 100644
--- a/nixos/modules/services/networking/cjdns.nix
+++ b/nixos/modules/services/networking/cjdns.nix
@@ -4,8 +4,46 @@ with lib;
 
 let
 
+  pkg = pkgs.cjdns;
+
   cfg = config.services.cjdns;
 
+  connectToSubmodule =
+  { options, ... }:
+  { options =
+    { password = mkOption {
+      type = types.str;
+      description = "Authorized password to the opposite end of the tunnel.";
+      };
+      publicKey = mkOption {
+        type = types.str;
+        description = "Public key at the opposite end of the tunnel.";
+      };
+      hostname = mkOption {
+        default = "";
+        example = "foobar.hype";
+        type = types.str;
+        description = "Optional hostname to add to /etc/hosts; prevents reverse lookup failures.";
+      };
+    };
+  };
+
+  peers = mapAttrsToList (n: v: v) (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo);
+
+  pubs  = toString (map (p: if p.hostname == "" then "" else p.publicKey) peers);
+  hosts = toString (map (p: if p.hostname == "" then "" else p.hostname)  peers);
+
+  cjdnsHosts =
+    if hosts != "" then
+      import (pkgs.stdenv.mkDerivation {
+        name = "cjdns-hosts";
+        builder = ./cjdns-hosts.sh;
+
+        inherit (pkgs) cjdns;
+        inherit pubs hosts;
+      })
+    else "";
+
   # would be nice to  merge 'cfg' with a //,
   # but the json nesting is wacky.
   cjdrouteConf = builtins.toJSON ( {
@@ -44,7 +82,7 @@ in
 
       enable = mkOption {
         type = types.bool;
-	default = false;
+        default = false;
         description = ''
           Whether to enable the cjdns network encryption
           and routing engine. A file at /etc/cjdns.keys will
@@ -53,84 +91,80 @@ in
         '';
       };
 
+      confFile = mkOption {
+        type = types.str;
+        default = "";
+        example = "/etc/cjdroute.conf";
+        description = ''
+          Ignore all other cjdns options and load configuration from this file.
+        '';
+      };
+
       authorizedPasswords = mkOption {
         type = types.listOf types.str;
-	default = [ ];
-	example = [
+        default = [ ];
+        example = [
           "snyrfgkqsc98qh1y4s5hbu0j57xw5s0"
-	  "z9md3t4p45mfrjzdjurxn4wuj0d8swv"
-	  "49275fut6tmzu354pq70sr5b95qq0vj"
+          "z9md3t4p45mfrjzdjurxn4wuj0d8swv"
+          "49275fut6tmzu354pq70sr5b95qq0vj"
         ];
-	description = ''
-	  Any remote cjdns nodes that offer these passwords on 
-	  connection will be allowed to route through this node.
+        description = ''
+          Any remote cjdns nodes that offer these passwords on 
+          connection will be allowed to route through this node.
         '';
       };
     
       admin = {
         bind = mkOption {
           type = types.string;
-	  default = "127.0.0.1:11234";
-	  description = ''
+          default = "127.0.0.1:11234";
+          description = ''
             Bind the administration port to this address and port.
-	  '';
+          '';
         };
       };
 
       UDPInterface = {
         bind = mkOption {
           type = types.string;
-	  default = "";
+          default = "";
           example = "192.168.1.32:43211";
           description = ''
-	    Address and port to bind UDP tunnels to.
-	  '';
- 	};
+            Address and port to bind UDP tunnels to.
+          '';
+         };
         connectTo = mkOption {
-          type = types.attrsOf ( types.submodule (
-	    { options, ... }:
-            { options = {
-                # TODO make host an option, and add it to networking.extraHosts
-                password = mkOption {
-                  type = types.str;
-                  description = "Authorized password to the opposite end of the tunnel.";
-                };
-                publicKey = mkOption {
-                  type = types.str;
-                  description = "Public key at the opposite end of the tunnel.";
-                };
-              };
-            }
-          ));
-	  default = { };
+          type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
+          default = { };
           example = {
             "192.168.1.1:27313" = {
-	      password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+              hostname = "homer.hype";
+              password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
               publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
             };
           };
           description = ''
-	    Credentials for making UDP tunnels.
-	  '';
-	};
+            Credentials for making UDP tunnels.
+          '';
+        };
       };
 
       ETHInterface = {
         bind = mkOption {
-	  default = "";
-	  example = "eth0";
-	  description = ''
-	    Bind to this device for native ethernet operation.
-	  '';
-        };
+        default = "";
+        example = "eth0";
+        description = ''
+          Bind to this device for native ethernet operation.
+        '';
+      };
 
         beacon = mkOption {
-	  type = types.int;
+          type = types.int;
           default = 2;
           description = ''
             Auto-connect to other cjdns nodes on the same network.
             Options:
-	      0: Disabled.
+              0: Disabled.
               1: Accept beacons, this will cause cjdns to accept incoming
                  beacon messages and try connecting to the sender.
               2: Accept and send beacons, this will cause cjdns to broadcast
@@ -142,32 +176,20 @@ in
         };
 
         connectTo = mkOption {
-          type = types.attrsOf ( types.submodule (
-	    { options, ... }:
-            { options = {
-                password = mkOption {
-                  type = types.str;
-                  description = "Authorized password to the opposite end of the tunnel.";
-                };
-                publicKey = mkOption {
-                  type = types.str;
-                  description = "Public key at the opposite end of the tunnel.";
-                };
-              };
-            }
-          ));
-	  default = { };
+          type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
+          default = { };
           example = {
             "01:02:03:04:05:06" = {
-	      password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+              hostname = "homer.hype";
+              password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
               publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
             };
           };
-	  description = ''
-	    Credentials for connecting look similar to UDP credientials
+          description = ''
+            Credentials for connecting look similar to UDP credientials
             except they begin with the mac address.
-	  '';
-	};
+          '';
+        };
       };
 
     };
@@ -182,37 +204,51 @@ in
 
     systemd.services.cjdns = {
       description = "encrypted networking for everybody";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
-
-      script = ''
-        source /etc/cjdns.keys
-        echo '${cjdrouteConf}' | sed \
-	  -e "s/@CJDNS_ADMIN_PASSWORD@/$CJDNS_ADMIN_PASSWORD/g" \
-          -e "s/@CJDNS_PRIVATE_KEY@/$CJDNS_PRIVATE_KEY/g" \
-            | ${pkgs.cjdns}/bin/cjdroute
+      wantedBy = [ "network.target" ];
+      after = [ "networkSetup.service" "network-interfaces.target" ];
+
+      preStart = if cfg.confFile != "" then "" else ''
+        [ -e /etc/cjdns.keys ] && source /etc/cjdns.keys
+
+        if [ -z "$CJDNS_PRIVATE_KEY" ]; then
+            shopt -s lastpipe
+            ${pkg}/bin/makekeys | { read private ipv6 public; }
+
+            umask 0077
+            echo "CJDNS_PRIVATE_KEY=$private" >> /etc/cjdns.keys
+            echo -e "CJDNS_IPV6=$ipv6\nCJDNS_PUBLIC_KEY=$public" > /etc/cjdns.public
+
+            chmod 600 /etc/cjdns.keys
+            chmod 444 /etc/cjdns.public
+        fi
+
+        if [ -z "$CJDNS_ADMIN_PASSWORD" ]; then
+            echo "CJDNS_ADMIN_PASSWORD=$(${pkgs.coreutils}/bin/head -c 96 /dev/urandom | ${pkgs.coreutils}/bin/tr -dc A-Za-z0-9)" \
+                >> /etc/cjdns.keys
+        fi
       '';
 
+      script = (
+        if cfg.confFile != "" then "${pkg}/bin/cjdroute < ${cfg.confFile}" else
+          ''
+            source /etc/cjdns.keys
+            echo '${cjdrouteConf}' | sed \
+                -e "s/@CJDNS_ADMIN_PASSWORD@/$CJDNS_ADMIN_PASSWORD/g" \
+                -e "s/@CJDNS_PRIVATE_KEY@/$CJDNS_PRIVATE_KEY/g" \
+                | ${pkg}/bin/cjdroute
+         ''
+      );
+
       serviceConfig = {
         Type = "forking";
-	Restart = "on-failure";
+        Restart = "on-failure";
       };
     };
 
-    system.activationScripts.cjdns = ''
-      grep -q "CJDNS_PRIVATE_KEY=" /etc/cjdns.keys || \
-        echo "CJDNS_PRIVATE_KEY=$(${pkgs.cjdns}/bin/makekey)" \
-	  >> /etc/cjdns.keys
-
-      grep -q "CJDNS_ADMIN_PASSWORD=" /etc/cjdns.keys || \
-        echo "CJDNS_ADMIN_PASSWORD=$(${pkgs.coreutils}/bin/head -c 96 /dev/urandom | ${pkgs.coreutils}/bin/tr -dc A-Za-z0-9)" \
-	  >> /etc/cjdns.keys
-
-      chmod 600 /etc/cjdns.keys
-    '';
+    networking.extraHosts = "${cjdnsHosts}";
 
     assertions = [
-      { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" );
+      { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile == "" );
         message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined.";
       }
       { assertion = config.networking.enableIPv6;
@@ -222,4 +258,4 @@ in
 
   };
 
-}
\ No newline at end of file
+}
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
new file mode 100644
index 000000000000..ebc836814089
--- /dev/null
+++ b/nixos/modules/services/networking/consul.nix
@@ -0,0 +1,166 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+let
+
+  dataDir = "/var/lib/consul";
+  cfg = config.services.consul;
+
+  configOptions = {
+    data_dir = dataDir;
+    rejoin_after_leave = true;
+  }
+  // (if cfg.webUi then { ui_dir = "${pkgs.consul.ui}"; } else { })
+  // cfg.extraConfig;
+
+  configFiles = [ "/etc/consul.json" "/etc/consul-addrs.json" ]
+    ++ cfg.extraConfigFiles;
+
+  devices = attrValues (filterAttrs (_: i: i != null) cfg.interface);
+  systemdDevices = flip map devices
+    (i: "sys-subsystem-net-devices-${utils.escapeSystemdPath i}.device");
+in
+{
+  options = {
+
+    services.consul = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enables the consul daemon.
+        '';
+      };
+
+      webUi = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enables the web interface on the consul http port.
+        '';
+      };
+
+      interface = {
+
+        advertise = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          description = ''
+            The name of the interface to pull the advertise_addr from.
+          '';
+        };
+
+        bind = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          description = ''
+            The name of the interface to pull the bind_addr from.
+          '';
+        };
+
+      };
+
+      forceIpv4 = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether we should force the interfaces to only pull ipv4 addresses.
+        '';
+      };
+
+      dropPrivileges = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether the consul agent should be run as a non-root consul user.
+        '';
+      };
+
+      extraConfig = mkOption {
+        default = { };
+        description = ''
+          Extra configuration options which are serialized to json and added
+          to the config.json file.
+        '';
+      };
+
+      extraConfigFiles = mkOption {
+        default = [ ];
+        type = types.listOf types.str;
+        description = ''
+          Additional configuration files to pass to consul
+          NOTE: These will not trigger the service to be restarted when altered.
+        '';
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers."consul" = {
+      description = "Consul agent daemon user";
+      uid = config.ids.uids.consul;
+    };
+
+    environment = {
+      etc."consul.json".text = builtins.toJSON configOptions;
+      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;
+        ExecStop = "${pkgs.consul}/bin/consul leave";
+        ExecReload = "${pkgs.consul}/bin/consul reload";
+        PermissionsStartOnly = true;
+        User = if cfg.dropPrivileges then "consul" else null;
+      };
+
+      path = with pkgs; [ iproute gnugrep gawk ];
+      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
+            ADDR="$(getAddrOnce $1)"
+          done
+          echo "$ADDR"
+        }
+        echo "{" > /etc/consul-addrs.json
+      ''
+      + concatStrings (flip mapAttrsToList cfg.interface (name: i:
+        optionalString (i != null) ''
+          echo "    \"${name}_addr\": \"$(getAddr "${i}")\"," >> /etc/consul-addrs.json
+        ''))
+      + ''
+        echo "    \"\": \"\"" >> /etc/consul-addrs.json
+        echo "}" >> /etc/consul-addrs.json
+      '';
+    };
+
+  };
+}
diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix
index 5864efaca51f..566936a7d0fa 100644
--- a/nixos/modules/services/networking/git-daemon.nix
+++ b/nixos/modules/services/networking/git-daemon.nix
@@ -3,7 +3,6 @@ with lib;
 let
 
   cfg = config.services.gitDaemon;
-  gitUser = "git";
 
 in
 {
@@ -14,6 +13,7 @@ in
     services.gitDaemon = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = ''
           Enable Git daemon, which allows public hosting  of git repositories
@@ -28,6 +28,7 @@ in
       };
 
       basePath = mkOption {
+        type = types.str;
         default = "";
         example = "/srv/git/";
         description = ''
@@ -38,6 +39,7 @@ in
       };
 
       exportAll = mkOption {
+        type = types.bool;
         default = false;
         description = ''
           Publish all directories that look like Git repositories (have the objects
@@ -52,6 +54,7 @@ in
       };
 
       repositories = mkOption {
+        type = types.listOf types.str;
         default = [];
         example = [ "/srv/git" "/home/user/git/repo2" ];
         description = ''
@@ -64,21 +67,36 @@ in
       };
 
       listenAddress = mkOption {
+        type = types.str;
         default = "";
         example = "example.com";
         description = "Listen on a specific IP address or hostname.";
       };
 
       port = mkOption {
+        type = types.int;
         default = 9418;
         description = "Port to listen on.";
       };
 
       options = mkOption {
+        type = types.str;
         default = "";
         description = "Extra configuration options to be passed to Git daemon.";
       };
 
+      user = mkOption {
+        type = types.str;
+        default = "git";
+        description = "User under which Git daemon would be running.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "git";
+        description = "Group under which Git daemon would be running.";
+      };
+
     };
   };
 
@@ -86,14 +104,14 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton
-      { name = gitUser;
+    users.extraUsers = if cfg.user != "git" then {} else singleton
+      { name = "git";
         uid = config.ids.uids.git;
         description = "Git daemon user";
       };
 
-    users.extraGroups = singleton
-      { name = gitUser;
+    users.extraGroups = if cfg.group != "git" then {} else singleton
+      { name = "git";
         gid = config.ids.gids.git;
       };
 
@@ -103,8 +121,8 @@ in
       exec = "${pkgs.git}/bin/git daemon --reuseaddr "
         + (optionalString (cfg.basePath != "") "--base-path=${cfg.basePath} ")
         + (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ")
-        + "--port=${toString cfg.port} --user=${gitUser} --group=${gitUser} ${cfg.options} "
-        + "--verbose " + (optionalString cfg.exportAll "--export-all")  + concatStringsSep " " cfg.repositories;
+        + "--port=${toString cfg.port} --user=${cfg.user} --group=${cfg.group} ${cfg.options} "
+        + "--verbose " + (optionalString cfg.exportAll "--export-all ")  + concatStringsSep " " cfg.repositories;
     };
 
   };
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
new file mode 100644
index 000000000000..d0127fd3f75e
--- /dev/null
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -0,0 +1,198 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.i2pd;
+
+  homeDir = "/var/lib/i2pd";
+
+  extip = "EXTIP=$(${pkgs.curl}/bin/curl -sf "http://jsonip.com" | ${pkgs.gawk}/bin/awk -F'\"' '{print $4}')";
+
+  i2pSh = pkgs.writeScriptBin "i2pd" ''
+    #!/bin/sh
+    ${if isNull cfg.extIp then extip else ""}
+    ${pkgs.i2pd}/bin/i2p --log=1 --daemon=0 --service=0 \
+      --v6=${if cfg.enableIPv6 then "1" else "0"} \
+      --unreachable=${if cfg.unreachable then "1" else "0"} \
+      --host=${if isNull cfg.extIp then "$EXTIP" else cfg.extIp} \
+      ${if isNull cfg.port then "" else "--port=${toString cfg.port}"} \
+      --httpproxyport=${toString cfg.proxy.httpPort} \
+      --socksproxyport=${toString cfg.proxy.socksPort} \
+      --ircport=${toString cfg.irc.port} \
+      --ircdest=${cfg.irc.dest} \
+      --irckeys=${cfg.irc.keyFile} \
+      --eepport=${toString cfg.eep.port} \
+      ${if isNull cfg.sam.port then "" else "--samport=${toString cfg.sam.port}"} \
+      --eephost=${cfg.eep.host} \
+      --eepkeys=${cfg.eep.keyFile}
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.i2pd = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enables I2Pd as a running service upon activation.
+        '';
+      };
+
+      extIp = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Your external IP.
+        '';
+      };
+
+      unreachable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If the router is declared to be unreachable and needs introduction nodes.
+        '';
+      };
+
+      port = mkOption {
+        type = with types; nullOr int;
+        default = null;
+        description = ''
+          I2P listen port. If no one is given the router will pick between 9111 and 30777.
+        '';
+      };
+
+      enableIPv6 = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enables IPv6 connectivity. Disabled by default.
+        '';
+      };
+
+      http = {
+        port = mkOption {
+          type = types.int;
+          default = 7070;
+          description = ''
+            HTTP listen port.
+          '';
+        };
+      };
+
+      proxy = {
+        httpPort = mkOption {
+          type = types.int;
+          default = 4446;
+          description = ''
+            HTTP proxy listen port.
+          '';
+        };
+        socksPort = mkOption {
+          type = types.int;
+          default = 4447;
+          description = ''
+            SOCKS proxy listen port.
+          '';
+        };
+      };
+
+      irc = {
+        dest = mkOption {
+          type = types.str;
+          default = "irc.postman.i2p";
+          description = ''
+            Destination I2P tunnel endpoint address of IRC server. irc.postman.i2p by default.
+          '';
+        };
+        port = mkOption {
+          type = types.int;
+          default = 6668;
+          description = ''
+            Local IRC tunnel endoint port to listen on. 6668 by default.
+          '';
+        };
+        keyFile = mkOption {
+          type = types.str;
+          default = "privKeys.dat";
+          description = ''
+            File name containing destination keys. privKeys.dat by default.
+          '';
+        };
+      };
+
+      eep = {
+        host = mkOption {
+          type = types.str;
+          default = "127.0.0.1";
+          description = ''
+            Address to forward incoming traffic to. 127.0.0.1 by default.
+          '';
+        };
+        port = mkOption {
+          type = types.int;
+          default = 80;
+          description = ''
+            Port to forward incoming trafic to. 80 by default.
+          '';
+        };
+        keyFile = mkOption {
+          type = types.str;
+          default = "privKeys.dat";
+          description = ''
+            File name containing destination keys. privKeys.dat by default.
+          '';
+        };
+      };
+
+      sam = {
+        port = mkOption {
+          type = with types; nullOr int;
+          default = null;
+          description = ''
+            Local SAM tunnel endpoint. Usually 7656. SAM is disabled if not specified.
+          '';
+        };
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers.i2pd = {
+      group = "i2pd";
+      description = "I2Pd User";
+      home = homeDir;
+      createHome = true;
+      uid = config.ids.uids.i2pd;
+    };
+
+    users.extraGroups.i2pd.gid = config.ids.gids.i2pd;
+
+    systemd.services.i2pd = {
+      description = "Minimal I2P router";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig =
+      {
+        User = "i2pd";
+        WorkingDirectory = homeDir;
+        Restart = "on-abort";
+        ExecStart = "${i2pSh}/bin/i2pd";
+      };
+    };
+  };
+}
+#
\ No newline at end of file
diff --git a/nixos/modules/services/networking/mailpile.nix b/nixos/modules/services/networking/mailpile.nix
new file mode 100644
index 000000000000..e164d41483c7
--- /dev/null
+++ b/nixos/modules/services/networking/mailpile.nix
@@ -0,0 +1,76 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.mailpile;
+
+  hostname = cfg.hostname;
+  port = cfg.port;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.mailpile = {
+      enable = mkOption {
+        default = false;
+        description = "
+          Whether to enable Mailpile the mail client.
+        ";
+      };
+      hostname = mkOption {
+        default = "localhost";
+        description = "Listen to this hostname or ip.";
+      };
+      port = mkOption {
+        default = "33411";
+        description = "Listen on this port.";
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.mailpile.enable {
+
+    users.extraUsers.mailpile =
+      { uid = config.ids.uids.mailpile;
+        description = "Mailpile user";
+        createHome = true;
+        home = "/var/lib/mailpile";
+      };
+
+    users.extraGroups.mailpile =
+      { gid = config.ids.gids.mailpile;
+      };
+
+    systemd.services.mailpile =
+      {
+        description = "Mailpile server.";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          User = "mailpile";
+          ExecStart = "${pkgs.mailpile}/bin/mailpile --www ${hostname}:${port} --wait";
+          # mixed - first send SIGINT to main process,
+          # then after 2min send SIGKILL to whole group if neccessary
+          KillMode = "mixed";
+          KillSignal = "SIGINT";  # like Ctrl+C - safe mailpile shutdown
+          TimeoutSec = 120;  # wait 2min untill SIGKILL
+        };
+        environment.MAILPILE_HOME = "/var/lib/mailpile/.local/share/Mailpile";
+      };
+
+    environment.systemPackages = [ pkgs.mailpile ];
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix
index bdb79ce2a901..9d163e60d5ea 100644
--- a/nixos/modules/services/networking/nat.nix
+++ b/nixos/modules/services/networking/nat.nix
@@ -157,9 +157,9 @@ in
 
     boot = {
       kernelModules = [ "nf_nat_ftp" ];
-      kernel.sysctl = mkOverride 99 {
-        "net.ipv4.conf.all.forwarding" = true;
-        "net.ipv4.conf.default.forwarding" = true;
+      kernel.sysctl = {
+        "net.ipv4.conf.all.forwarding" = mkOverride 99 true;
+        "net.ipv4.conf.default.forwarding" = mkOverride 99 true;
       };
     };
 
diff --git a/nixos/modules/services/networking/polipo.nix b/nixos/modules/services/networking/polipo.nix
index 05ded84625d0..51179d9120fe 100644
--- a/nixos/modules/services/networking/polipo.nix
+++ b/nixos/modules/services/networking/polipo.nix
@@ -103,12 +103,8 @@ in
       description = "caching web proxy";
       after = [ "network.target" "nss-lookup.target" ];
       wantedBy = [ "multi-user.target"];
-      preStart = ''
-         ${pkgs.coreutils}/bin/chown polipo:polipo /var/cache/polipo -R
-      '';
       serviceConfig = {
         ExecStart  = "${pkgs.polipo}/bin/polipo -c ${polipoConfig}";
-        ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
         User = "polipo";
       };
     };
diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix
new file mode 100644
index 000000000000..f82f8bfddbb7
--- /dev/null
+++ b/nixos/modules/services/networking/prosody.nix
@@ -0,0 +1,280 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.prosody;
+
+  sslOpts = { ... }: {
+
+    options = {
+
+      # TODO: require attribute
+      key = mkOption {
+        type = types.str;
+        description = "Path to the key file";
+      };
+
+      # TODO: require attribute
+      cert = mkOption {
+        type = types.str;
+        description = "Path to the certificate file";
+      };
+    };
+  };
+
+  moduleOpts = {
+
+    roster = mkOption {
+      default = true;
+      description = "Allow users to have a roster";
+    };
+
+    saslauth = mkOption {
+      default = true;
+      description = "Authentication for clients and servers. Recommended if you want to log in.";
+    };
+
+    tls = mkOption {
+      default = true;
+      description = "Add support for secure TLS on c2s/s2s connections";
+    };
+
+    dialback = mkOption {
+      default = true;
+      description = "s2s dialback support";
+    };
+
+    disco = mkOption {
+      default = true;
+      description = "Service discovery";
+    };
+
+    legacyauth = mkOption {
+      default = true;
+      description = "Legacy authentication. Only used by some old clients and bots";
+    };
+
+    version = mkOption {
+      default = true;
+      description = "Replies to server version requests";
+    };
+
+    uptime = mkOption {
+      default = true;
+      description = "Report how long server has been running";
+    };
+
+    time = mkOption {
+      default = true;
+      description = "Let others know the time here on this server";
+    };
+
+    ping = mkOption {
+      default = true;
+      description = "Replies to XMPP pings with pongs";
+    };
+
+    console = mkOption {
+      default = false;
+      description = "telnet to port 5582";
+    };
+
+    bosh = mkOption {
+      default = false;
+      description = "Enable BOSH clients, aka 'Jabber over HTTP'";
+    };
+
+    httpserver = mkOption {
+      default = false;
+      description = "Serve static files from a directory over HTTP";
+    };
+
+    websocket = mkOption {
+      default = false;
+      description = "Enable WebSocket support";
+    };
+
+  };
+
+  createSSLOptsStr = o:
+    if o ? key && o ? cert then
+      ''ssl = { key = "${o.key}"; certificate = "${o.cert}"; };''
+    else "";
+
+  vHostOpts = { ... }: {
+
+    options = {
+
+      # TODO: require attribute
+      domain = mkOption {
+        type = types.str;
+        description = "Domain name";
+      };
+
+      enabled = mkOption {
+        default = false;
+        description = "Whether to enable the virtual host";
+      };
+
+      ssl = mkOption {
+        description = "Paths to SSL files";
+        default = null;
+        options = [ sslOpts ];
+      };
+
+      extraConfig = mkOption {
+        default = '''';
+        description = "Additional virtual host specific configuration";
+      };
+
+    };
+
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.prosody = {
+
+      enable = mkOption {
+        default = false;
+        description = "Whether to enable the prosody server";
+      };
+
+      allowRegistration = mkOption {
+        default = false;
+        description = "Allow account creation";
+      };
+
+      modules = moduleOpts;
+
+      extraModules = mkOption {
+        description = "Enable custom modules";
+        default = [];
+      };
+
+      virtualHosts = mkOption {
+
+        description = "Define the virtual hosts";
+
+        type = types.loaOf types.optionSet;
+
+        example = {
+          myhost = {
+            domain = "my-xmpp-example-host.org";
+            enabled = true;
+          };
+        };
+
+        default = {
+          localhost = {
+            domain = "localhost";
+            enabled = true;
+          };
+        };
+
+        options = [ vHostOpts ];
+      };
+
+      ssl = mkOption {
+        description = "Paths to SSL files";
+        default = null;
+        options = [ sslOpts ];
+      };
+
+      admins = mkOption {
+        description = "List of administrators of the current host";
+        example = [ "admin1@example.com" "admin2@example.com" ];
+        default = [];
+      };
+
+      extraConfig = mkOption {
+        default = '''';
+        description = "Additional prosody configuration";
+      };
+
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.prosody ];
+
+    environment.etc."prosody/prosody.cfg.lua".text = ''
+
+      pidfile = "/var/lib/prosody/prosody.pid"
+
+
+      log = "*syslog"
+
+      data_path = "/var/lib/prosody"
+
+      allow_registration = ${ if cfg.allowRegistration then "true" else "false" };
+
+      ${ optionalString cfg.modules.console "console_enabled = true;" }
+
+      ${ optionalString  (cfg.ssl != null) (createSSLOptsStr cfg.ssl) }
+
+      admins = { ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.admins) } };
+
+      modules_enabled = {
+
+        ${ lib.concatStringsSep "\n\ \ " (lib.mapAttrsToList
+          (name: val: optionalString val ''"${name}";'')
+        cfg.modules) }
+
+        ${ optionalString cfg.allowRegistration "\"register\"\;" }
+
+        ${ lib.concatStringsSep "\n" (map (x: "\"${x}\";") cfg.extraModules)}
+
+        "posix";
+      };
+
+      ${ cfg.extraConfig }
+
+      ${ lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
+        VirtualHost "${v.domain}"
+          enabled = ${if v.enabled then "true" else "false"};
+          ${ optionalString (v.ssl != null) (createSSLOptsStr v.ssl) }
+          ${ v.extraConfig }
+        '') cfg.virtualHosts) }
+    '';
+
+    users.extraUsers.prosody = {
+      uid = config.ids.uids.prosody;
+      description = "Prosody user";
+      createHome = true;
+      group = "prosody";
+      home = "/var/lib/prosody";
+    };
+
+    users.extraGroups.prosody = {
+      gid = config.ids.gids.prosody;
+    };
+
+    systemd.services.prosody = {
+
+      description = "Prosody XMPP server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "prosody";
+        PIDFile = "/var/lib/prosody/prosody.pid";
+        ExecStart = "${pkgs.prosody}/bin/prosodyctl start";
+      };
+
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix
index 749e5dcebb61..579d62884c78 100644
--- a/nixos/modules/services/networking/quassel.nix
+++ b/nixos/modules/services/networking/quassel.nix
@@ -74,21 +74,23 @@ in
         gid = config.ids.gids.quassel;
       }];
 
-    jobs.quassel =
+    systemd.services.quassel =
       { description = "Quassel IRC client daemon";
 
-        startOn = "ip-up";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
 
         preStart = ''
-            mkdir -p ${cfg.dataDir}
-            chown ${user} ${cfg.dataDir}
+          mkdir -p ${cfg.dataDir}
+          chown ${user} ${cfg.dataDir}
         '';
 
-        exec = ''
-            ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${user} \
-                -c '${quassel}/bin/quasselcore --listen=${cfg.interface}\
-                    --port=${toString cfg.portNumber} --configdir=${cfg.dataDir}'
-        '';
+        serviceConfig =
+        {
+          ExecStart = "${quassel}/bin/quasselcore --listen=${cfg.interface} --port=${toString cfg.portNumber} --configdir=${cfg.dataDir}";
+          User = user;
+          PermissionsStartOnly = true;
+        };
       };
 
   };
diff --git a/nixos/modules/services/networking/seeks.nix b/nixos/modules/services/networking/seeks.nix
new file mode 100644
index 000000000000..155ecbb98ef3
--- /dev/null
+++ b/nixos/modules/services/networking/seeks.nix
@@ -0,0 +1,75 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.seeks;
+
+  confDir = cfg.confDir;
+
+  seeks = pkgs.seeks.override { seeks_confDir = confDir; };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.seeks = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = "
+          Whether to enable the Seeks server.
+        ";
+      };
+
+      confDir = mkOption {
+        default = "";
+        type = types.str;
+        description = "
+          The Seeks server configuration. If it is not specified,
+          a default configuration is used (${seeks}/etc/seeks).
+        ";
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.seeks.enable {
+
+    users.extraUsers.seeks =
+      { uid = config.ids.uids.seeks;
+        description = "Seeks user";
+        createHome = true;
+        home = "/var/lib/seeks";
+      };
+
+    users.extraGroups.seeks =
+      { gid = config.ids.gids.seeks;
+      };
+
+    systemd.services.seeks =
+      {
+        description = "Seeks server, the p2p search engine.";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          User = "seeks";
+          ExecStart = "${seeks}/bin/seeks";
+        };
+      };
+
+    environment.systemPackages = [ seeks ];
+
+  };
+
+}
diff --git a/nixos/modules/services/scheduling/cron.nix b/nixos/modules/services/scheduling/cron.nix
index 9ce0bcbec7eb..ded3010ec5ae 100644
--- a/nixos/modules/services/scheduling/cron.nix
+++ b/nixos/modules/services/scheduling/cron.nix
@@ -25,6 +25,10 @@ let
     sendmailPath = "/var/setuid-wrappers/sendmail";
   };
 
+  allFiles = map (f: "\"${f}\"") (
+    [ "${systemCronJobsFile}" ] ++ config.services.cron.cronFiles
+  );
+
 in
 
 {
@@ -71,6 +75,15 @@ in
         '';
       };
 
+      cronFiles = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          A list of extra crontab files that will be read and appended to the main
+          crontab file when the cron service starts.
+        '';
+      };
+
     };
 
   };
@@ -78,14 +91,7 @@ in
 
   ###### implementation
 
-  config = mkIf config.services.cron.enable {
-
-    environment.etc = singleton
-      # The system-wide crontab.
-      { source = systemCronJobsFile;
-        target = "crontab";
-        mode = "0600"; # Cron requires this.
-      };
+  config = mkIf (config.services.cron.enable && allFiles != []) {
 
     security.setuidPrograms = [ "crontab" ];
 
@@ -100,6 +106,10 @@ in
 
         preStart =
           ''
+            rm -f /etc/crontab
+            cat ${toString allFiles} > /etc/crontab
+            chmod 0600 /etc/crontab
+
             mkdir -m 710 -p /var/cron
 
             # By default, allow all users to create a crontab.  This
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 02db4a7a5b2b..1b38ea3b679b 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -88,7 +88,7 @@ in
   config = mkIf cfg.enable {
     systemd.services.transmission = {
       description = "Transmission BitTorrent Service";
-      after = [ "network.target" ] ++ optional apparmor "apparmor.service";
+      after = [ "local-fs.target" "network.target" ] ++ optional apparmor "apparmor.service";
       requires = mkIf apparmor [ "apparmor.service" ];
       wantedBy = [ "multi-user.target" ];
 
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 85458a2ab565..1f0729c1b715 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -109,6 +109,9 @@ let
       "mpm_${mainCfg.multiProcessingModule}"
       "authz_core"
       "unixd"
+      "cache" "cache_disk"
+      "slotmem_shm"
+      "socache_shmcb"
     ]
     ++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
     ++ optional enableSSL "ssl"
@@ -160,9 +163,9 @@ let
 
 
   sslConf = ''
-    SSLSessionCache shm:${mainCfg.stateDir}/ssl_scache(512000)
+    SSLSessionCache ${if version24 then "shmcb" else "shm"}:${mainCfg.stateDir}/ssl_scache(512000)
 
-    SSLMutex posixsem
+    ${if version24 then "Mutex" else "SSLMutex"} posixsem
 
     SSLRandomSeed startup builtin
     SSLRandomSeed connect builtin
@@ -420,8 +423,7 @@ in
 
       package = mkOption {
         type = types.package;
-        default = pkgs.apacheHttpd.override { mpm = mainCfg.multiProcessingModule; };
-        example = literalExample "pkgs.apacheHttpd_2_4";
+        default = pkgs.apacheHttpd;
         description = ''
           Overridable attribute of the Apache HTTP Server package to use.
         '';
@@ -593,11 +595,11 @@ in
   ###### implementation
 
   config = mkIf config.services.httpd.enable {
-  
+
     assertions = [ { assertion = mainCfg.enableSSL == true
                                -> mainCfg.sslServerCert != null
                                     && mainCfg.sslServerKey != null;
-                     message = "SSL is enabled for HTTPD, but sslServerCert and/or sslServerKey haven't been specified."; }
+                     message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; }
                  ];
 
     users.extraUsers = optionalAttrs (mainCfg.user == "wwwrun") (singleton
diff --git a/nixos/modules/services/web-servers/lighttpd/cgit.nix b/nixos/modules/services/web-servers/lighttpd/cgit.nix
index d4663781fd84..34b2fa600ad9 100644
--- a/nixos/modules/services/web-servers/lighttpd/cgit.nix
+++ b/nixos/modules/services/web-servers/lighttpd/cgit.nix
@@ -44,6 +44,9 @@ in
     # make the cgitrc manpage available
     environment.systemPackages = [ pkgs.cgit ];
 
+    # declare module dependencies
+    services.lighttpd.enableModules = [ "mod_cgi" "mod_alias" "mod_setenv" ];
+
     services.lighttpd.extraConfig = ''
       $HTTP["url"] =~ "^/cgit" {
           cgi.assign = (
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index fc9487ab4859..06f310eeb933 100644
--- a/nixos/modules/services/web-servers/lighttpd/default.nix
+++ b/nixos/modules/services/web-servers/lighttpd/default.nix
@@ -8,12 +8,54 @@ let
 
   cfg = config.services.lighttpd;
 
-  needModRedirect = cfg.gitweb.enable;
-  needModAlias = cfg.cgit.enable || cfg.gitweb.enable;
-  needModSetenv = cfg.cgit.enable || cfg.gitweb.enable;
-  needModCgi = cfg.cgit.enable || cfg.gitweb.enable;
-  needModStatus = cfg.mod_status;
-  needModUserdir = cfg.mod_userdir;
+  # List of known lighttpd modules, ordered by how the lighttpd documentation
+  # recommends them being imported:
+  # http://redmine.lighttpd.net/projects/1/wiki/Server_modulesDetails
+  #
+  # Some modules are always imported and should not appear in the config:
+  # disallowedModules = [ "mod_indexfile" "mod_dirlisting" "mod_staticfile" ];
+  #
+  # Get full module list: "ls -1 $lighttpd/lib/*.so"
+  allKnownModules = [
+    "mod_rewrite"
+    "mod_redirect"
+    "mod_alias"
+    "mod_access"
+    "mod_auth"
+    "mod_status"
+    "mod_simple_vhost"
+    "mod_evhost"
+    "mod_userdir"
+    "mod_secdownload"
+    "mod_fastcgi"
+    "mod_proxy"
+    "mod_cgi"
+    "mod_ssi"
+    "mod_compress"
+    "mod_usertrack"
+    "mod_expire"
+    "mod_rrdtool"
+    "mod_accesslog"
+    # Remaining list of modules, order assumed to be unimportant.
+    "mod_cml"
+    "mod_dirlisting"
+    "mod_evasive"
+    "mod_extforward"
+    "mod_flv_streaming"
+    "mod_magnet"
+    "mod_mysql_vhost"
+    "mod_rewrite"
+    "mod_scgi"
+    "mod_setenv"
+    "mod_trigger_b4_dl"
+    "mod_webdav"
+  ];
+
+  maybeModuleString = moduleName:
+    if elem moduleName cfg.enableModules then ''"${moduleName}"'' else "";
+
+  modulesIncludeString = concatStringsSep ",\n"
+    (filter (x: x != "") (map maybeModuleString allKnownModules));
 
   configFile = if cfg.configText != "" then
     pkgs.writeText "lighttpd.conf" ''
@@ -38,13 +80,7 @@ let
       # been loaded already. So if two services were to put the same module in
       # server.modules += (), that would break the lighttpd configuration.
       server.modules = (
-          ${optionalString needModRedirect ''"mod_redirect",''}
-          ${optionalString needModAlias ''"mod_alias",''}
-          ${optionalString needModSetenv ''"mod_setenv",''}
-          ${optionalString needModCgi ''"mod_cgi",''}
-          ${optionalString needModStatus ''"mod_status",''}
-          ${optionalString needModUserdir ''"mod_userdir",''}
-          "mod_accesslog"
+          ${modulesIncludeString}
       )
 
       # Logging (logs end up in systemd journal)
@@ -117,6 +153,19 @@ in
         '';
       };
 
+      enableModules = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "mod_cgi" "mod_status" ];
+        description = ''
+          List of lighttpd modules to enable. Sub-services take care of
+          enabling modules as needed, so this option is mainly for when you
+          want to add custom stuff to
+          <option>services.lighttpd.extraConfig</option> that depends on a
+          certain module.
+        '';
+      };
+
       mod_status = mkOption {
         default = false;
         type = types.uniq types.bool;
@@ -152,6 +201,26 @@ in
 
   config = mkIf cfg.enable {
 
+    assertions = [
+      { assertion = all (x: elem x allKnownModules) cfg.enableModules;
+        message = ''
+          One (or more) modules in services.lighttpd.enableModules are
+          unrecognized.
+
+          Known modules: ${toString allKnownModules}
+
+          services.lighttpd.enableModules: ${toString cfg.enableModules}
+        '';
+      }
+    ];
+
+    services.lighttpd.enableModules = mkMerge
+      [ (mkIf cfg.mod_status [ "mod_status" ])
+        (mkIf cfg.mod_userdir [ "mod_userdir" ])
+        # always load mod_accesslog so that we can log to the journal
+        [ "mod_accesslog" ]
+      ];
+
     systemd.services.lighttpd = {
       description = "Lighttpd Web Server";
       after = [ "network.target" ];
diff --git a/nixos/modules/services/web-servers/lighttpd/gitweb.nix b/nixos/modules/services/web-servers/lighttpd/gitweb.nix
index c407a1d89778..ef7072ecba3a 100644
--- a/nixos/modules/services/web-servers/lighttpd/gitweb.nix
+++ b/nixos/modules/services/web-servers/lighttpd/gitweb.nix
@@ -44,6 +44,9 @@ in
 
   config = mkIf cfg.enable {
 
+    # declare module dependencies
+    services.lighttpd.enableModules = [ "mod_cgi" "mod_redirect" "mod_alias" "mod_setenv" ];
+
     services.lighttpd.extraConfig = ''
       $HTTP["url"] =~ "^/gitweb" {
           cgi.assign = (
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 5f46e2f1ef84..5ac1a9591fdf 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -81,7 +81,7 @@ in {
     services.upower.enable = config.powerManagement.enable;
     services.upower.package = gnome3.upower;
 
-    fonts.fonts = [ pkgs.dejavu_fonts ];
+    fonts.fonts = [ pkgs.dejavu_fonts pkgs.cantarell_fonts ];
 
     services.xserver.desktopManager.session = singleton
       { name = "gnome3";
diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix
index 669ddbd904f0..5c783fdbcedd 100644
--- a/nixos/modules/services/x11/desktop-managers/kde4.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde4.nix
@@ -7,6 +7,7 @@ let
   xcfg = config.services.xserver;
   cfg = xcfg.desktopManager.kde4;
   xorg = pkgs.xorg;
+  kde_workspace = config.services.xserver.desktopManager.kde4.kdeWorkspacePackage;
 
   # Disable Nepomuk and Strigi by default.  As of KDE 4.7, they don't
   # really work very well (e.g. searching files often fails to find
@@ -61,6 +62,13 @@ in
         example = ["gstreamer" "vlc"];
         description = "Which phonon multimedia backend kde should use";
       };
+
+      kdeWorkspacePackage = mkOption {
+        internal = true;
+        default = pkgs.kde4.kde_workspace;
+        type = types.package;
+        description = "Custom kde-workspace, used for NixOS rebranding.";
+      };
     };
 
     environment.kdePackages = mkOption {
@@ -108,13 +116,13 @@ in
             fi
 
             # Start KDE.
-            exec ${pkgs.kde4.kdebase_workspace}/bin/startkde
+            exec ${kde_workspace}/bin/startkde
           '';
       };
 
     security.setuidOwners = singleton
       { program = "kcheckpass";
-        source = "${pkgs.kde4.kdebase_workspace}/lib/kde4/libexec/kcheckpass";
+        source = "${kde_workspace}/lib/kde4/libexec/kcheckpass";
         owner = "root";
         group = "root";
         setuid = true;
@@ -124,7 +132,7 @@ in
         [ pkgs.kde4.kdelibs
 
           pkgs.kde4.kde_baseapps # Splitted kdebase
-          pkgs.kde4.kde_workspace
+          kde_workspace
           pkgs.kde4.kde_runtime
           pkgs.kde4.konsole
           pkgs.kde4.kate
@@ -146,8 +154,10 @@ in
           pkgs.strigi # used by nepomuk
           pkgs.mysql # used by akonadi
         ]
-      ++ [ nepomukConfig ] ++ phononBackendPackages
-      ++ config.environment.kdePackages;
+      ++ lib.optional config.hardware.pulseaudio.enable pkgs.kde4.kmix  # Perhaps this should always be enabled
+      ++ lib.optional config.hardware.bluetooth.enable pkgs.kde4.bluedevil
+      ++ lib.optional config.networking.networkmanager.enable pkgs.kde4.plasma-nm
+      ++ [ nepomukConfig ] ++ phononBackendPackages;
 
     environment.pathsToLink = [ "/share" ];
 
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index a31f66176cc9..6a14a163c19a 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -56,6 +56,7 @@ in
         pkgs.xfce.xfce4session
         pkgs.xfce.xfce4settings
         pkgs.xfce.xfce4mixer
+        pkgs.xfce.xfce4volumed
         pkgs.xfce.xfce4screenshooter
         pkgs.xfce.xfconf
         pkgs.xfce.xfdesktop
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 004ea6ef49ac..6b01cde9e2b4 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -68,18 +68,20 @@ let
       # Start PulseAudio if enabled.
       ${optionalString (config.hardware.pulseaudio.enable) ''
         ${optionalString (!config.hardware.pulseaudio.systemWide)
-          "${pkgs.pulseaudio}/bin/pulseaudio --start"
+          "${config.hardware.pulseaudio.package}/bin/pulseaudio --start"
         }
 
         # Publish access credentials in the root window.
-        ${pkgs.pulseaudio}/bin/pactl load-module module-x11-publish "display=$DISPLAY"
+        ${config.hardware.pulseaudio.package}/bin/pactl load-module module-x11-publish "display=$DISPLAY"
 
         # Keep track of devices.  Mostly useful for Phonon/KDE.
-        ${pkgs.pulseaudio}/bin/pactl load-module module-device-manager "do_routing=1"
+        ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
       ''}
 
       # Load X defaults.
-      if test -e ~/.Xdefaults; then
+      if test -e ~/.Xresources; then
+          ${xorg.xrdb}/bin/xrdb -merge ~/.Xresources
+      elif test -e ~/.Xdefaults; then
           ${xorg.xrdb}/bin/xrdb -merge ~/.Xdefaults
       fi
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index f8ce06738fee..98e3fd6d6a5d 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -28,11 +28,10 @@ let
     buildCommand = ''
       mkdir -p $out/gtk-3.0/
 
-      # This wrapper ensures that we actually get fonts
+      # This wrapper ensures that we actually get ?? (fonts should be OK now)
       makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
         $out/greeter \
         --set XDG_DATA_DIRS ${pkgs.gnome2.gnome_icon_theme}/share \
-        --set FONTCONFIG_FILE /etc/fonts/fonts.conf \
         --set XDG_CONFIG_HOME $out/
 
       # We need this to ensure that it actually tries to find icons from gnome-icon-theme
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
index f5b394b6d98b..9e44ce811c3e 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -7,9 +7,9 @@ let cfg = config.services.xserver.synaptics;
     enabledTapConfig = ''
       Option "MaxTapTime" "180"
       Option "MaxTapMove" "220"
-      Option "TapButton1" "${builtins.elemAt cfg.buttonsMap 0}"
-      Option "TapButton2" "${builtins.elemAt cfg.buttonsMap 1}"
-      Option "TapButton3" "${builtins.elemAt cfg.buttonsMap 2}"
+      Option "TapButton1" "${builtins.elemAt cfg.fingersMap 0}"
+      Option "TapButton2" "${builtins.elemAt cfg.fingersMap 1}"
+      Option "TapButton3" "${builtins.elemAt cfg.fingersMap 2}"
     '';
     disabledTapConfig = ''
       Option "MaxTapTime" "0"
@@ -25,12 +25,14 @@ in {
     services.xserver.synaptics = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         example = true;
         description = "Whether to enable touchpad support.";
       };
 
       dev = mkOption {
+        type = types.nullOr types.str;
         default = null;
         example = "/dev/input/event0";
         description =
@@ -59,41 +61,56 @@ in {
       };
 
       twoFingerScroll = mkOption {
+        type = types.bool;
         default = false;
         description = "Whether to enable two-finger drag-scrolling.";
       };
 
       vertEdgeScroll = mkOption {
+        type = types.bool;
         default = ! cfg.twoFingerScroll;
         description = "Whether to enable vertical edge drag-scrolling.";
       };
 
       tapButtons = mkOption {
+        type = types.bool;
         default = true;
         example = false;
         description = "Whether to enable tap buttons.";
       };
 
       buttonsMap = mkOption {
+        type = types.listOf types.int;
         default = [1 2 3];
         example = [1 3 2];
         description = "Remap touchpad buttons.";
         apply = map toString;
       };
 
+      fingersMap = mkOption {
+        type = types.listOf types.int;
+        default = [1 2 3];
+        example = [1 3 2];
+        description = "Remap several-fingers taps.";
+        apply = map toString;
+      };
+
       palmDetect = mkOption {
+        type = types.bool;
         default = false;
         example = true;
         description = "Whether to enable palm detection (hardware support required)";
       };
 
       horizontalScroll = mkOption {
+        type = types.bool;
         default = true;
         example = false;
         description = "Whether to enable horizontal scrolling (on touchpad)";
       };
 
       additionalOptions = mkOption {
+        type = types.str;
         default = "";
         example = ''
           Option "RTCornerButton" "2"
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index 45a4e947e0aa..4f2a2309b60c 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -18,6 +18,7 @@ in
       ./i3.nix
       ./herbstluftwm.nix
       ./bspwm.nix
+      ./stumpwm.nix
     ];
 
   options = {
@@ -60,4 +61,4 @@ in
   config = {
     services.xserver.displayManager.session = cfg.session;
   };
-}
+}
\ No newline at end of file
diff --git a/nixos/modules/services/x11/window-managers/stumpwm.nix b/nixos/modules/services/x11/window-managers/stumpwm.nix
new file mode 100644
index 000000000000..a876f13fd214
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/stumpwm.nix
@@ -0,0 +1,30 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.xserver.windowManager.stumpwm;
+in
+
+{
+  options = {
+    services.xserver.windowManager.stumpwm = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = "Enable the stumpwm tiling window manager.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager.session = singleton {
+      name = "stumpwm";
+      start = "
+        ${pkgs.stumpwm}/bin/stumpwm
+      ";
+    };
+    environment.systemPackages = [ pkgs.stumpwm ];
+  };
+}
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index c08afe2041f4..f911d3c81f90 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -399,8 +399,8 @@ in
     services.xserver.drivers = flip concatMap cfg.videoDrivers (name:
       let driver =
         attrByPath [name]
-          (if (hasAttr ("xf86video" + name) xorg)
-           then { modules = [(getAttr ("xf86video" + name) xorg) ]; }
+          (if xorg ? ${"xf86video" + name}
+           then { modules = [xorg.${"xf86video" + name}]; }
            else null)
           knownVideoDrivers;
       in optional (driver != null) ({ inherit name; driverName = name; } // driver));
@@ -458,7 +458,7 @@ in
         restartIfChanged = false;
 
         environment =
-          { FONTCONFIG_FILE = "/etc/fonts/fonts.conf"; # !!! cleanup
+          {
             XKB_BINDIR = "${xorg.xkbcomp}/bin"; # Needed for the Xkb extension.
             XORG_DRI_DRIVER_PATH = "/run/opengl-driver/lib/dri"; # !!! Depends on the driver selected at runtime.
             LD_LIBRARY_PATH = concatStringsSep ":" (
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 12012698efe3..c0e0ae23d387 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -321,6 +321,10 @@ system("@systemd@/bin/systemctl", "reset-failed");
 # Make systemd reload its units.
 system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3;
 
+# Signal dbus to reload its configuration before starting other units.
+# Other units may rely on newly installed policy files under /etc/dbus-1
+system("@systemd@/bin/systemctl", "reload", "dbus.service");
+
 # Restart changed services (those that have to be restarted rather
 # than stopped and started).
 my @restart = unique(split('\n', read_file($restartListFile, err_mode => 'quiet') // ""));
@@ -350,8 +354,6 @@ if (scalar @reload > 0) {
     unlink($reloadListFile);
 }
 
-# Signal dbus to reload its configuration.
-system("@systemd@/bin/systemctl", "reload", "dbus.service");
 
 # Print failed and new units.
 my (@failed, @new, @restarting);
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index f14f105ef239..5a9beeeafa1d 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -368,6 +368,14 @@ exec 3>&-
 @postMountCommands@
 
 
+# Emit a udev rule for /dev/root to prevent systemd from complaining.
+eval $(udevadm info --export --export-prefix=ROOT_ --device-id-of-file=$targetRoot || true)
+if [ "$ROOT_MAJOR" -a "$ROOT_MINOR" -a "$ROOT_MAJOR" != 0 ]; then
+    mkdir -p /run/udev/rules.d
+    echo 'ACTION=="add|change", SUBSYSTEM=="block", ENV{MAJOR}=="'$ROOT_MAJOR'", ENV{MINOR}=="'$ROOT_MINOR'", SYMLINK+="root"' > /run/udev/rules.d/61-dev-root-link.rules
+fi
+
+
 # Stop udevd.
 udevadm control --exit || true
 
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 1ec11e70e845..e101bbfe72ce 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -128,6 +128,7 @@ let
       cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/
       cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/
       cp -v ${pkgs.mdadm}/lib/udev/rules.d/*.rules $out/
+      cp -v ${pkgs.bcache-tools}/lib/udev/rules.d/*.rules $out/
 
       for i in $out/*.rules; do
           substituteInPlace $i \
@@ -137,7 +138,8 @@ let
             --replace ${pkgs.utillinux}/sbin/blkid ${extraUtils}/bin/blkid \
             --replace /sbin/blkid ${extraUtils}/bin/blkid \
             --replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \
-            --replace /sbin/mdadm ${extraUtils}/bin/mdadm
+            --replace /sbin/mdadm ${extraUtils}/bin/mdadm \
+            --replace /bin/sh ${extraUtils}/bin/sh
       done
 
       # Work around a bug in QEMU, which doesn't implement the "READ
@@ -346,9 +348,6 @@ in
       (isYes "BLK_DEV_INITRD")
     ];
 
-    # Prevent systemd from waiting for the /dev/root symlink.
-    systemd.units."dev-root.device".text = "";
-
     boot.initrd.supportedFilesystems = map (fs: fs.fsType) fileSystems;
 
   };
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index 48c3564ba078..07f3cb9e952c 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -6,8 +6,8 @@ let
 
   checkService = v:
     let assertValueOneOf = name: values: attr:
-          let val = getAttr name attr;
-          in optional ( hasAttr name attr && !elem val values) "Systemd service field `${name}' cannot have value `${val}'.";
+          let val = attr.${name};
+          in optional (attr ? ${name} && !elem val values) "Systemd service field `${name}' cannot have value `${val}'.";
         checkType = assertValueOneOf "Type" ["simple" "forking" "oneshot" "dbus" "notify" "idle"];
         checkRestart = assertValueOneOf "Restart" ["no" "on-success" "on-failure" "on-abort" "always"];
         errors = concatMap (c: c v) [checkType checkRestart];
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index f2f7989ab4de..c1205dc0c447 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -10,15 +10,19 @@ let
 
   systemd = cfg.package;
 
+
   makeUnit = name: unit:
+    let
+      pathSafeName = lib.replaceChars ["@" "\\"] ["-" "-"] name;
+    in
     if unit.enable then
-      pkgs.runCommand "unit" { preferLocalBuild = true; inherit (unit) text; }
+      pkgs.runCommand "unit-${pathSafeName}" { preferLocalBuild = true; inherit (unit) text; }
         ''
           mkdir -p $out
           echo -n "$text" > $out/${shellEscape name}
         ''
     else
-      pkgs.runCommand "unit" { preferLocalBuild = true; }
+      pkgs.runCommand "unit-${pathSafeName}-disabled" { preferLocalBuild = true; }
         ''
           mkdir -p $out
           ln -s /dev/null $out/${shellEscape name}
@@ -321,7 +325,7 @@ let
           [Service]
           ${let env = cfg.globalEnvironment // def.environment;
             in concatMapStrings (n:
-              let s = "Environment=\"${n}=${getAttr n env}\"\n";
+              let s = "Environment=\"${n}=${env.${n}}\"\n";
               in if stringLength s >= 2048 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)}
           ${if def.reloadIfChanged then ''
             X-ReloadIfChanged=true
diff --git a/nixos/modules/tasks/filesystems/jfs.nix b/nixos/modules/tasks/filesystems/jfs.nix
new file mode 100644
index 000000000000..b7091ce9b184
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/jfs.nix
@@ -0,0 +1,19 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  inInitrd = any (fs: fs == "jfs") config.boot.initrd.supportedFilesystems;
+in
+{
+  config = mkIf (any (fs: fs == "jfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.jfsutils ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "jfs" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd ''
+      cp -v ${pkgs.jfsutils}/sbin/fsck.jfs "$out/bin/"
+    '';
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix
index 1c4bbc16b499..eb72bfba33c0 100644
--- a/nixos/modules/tasks/filesystems/zfs.nix
+++ b/nixos/modules/tasks/filesystems/zfs.nix
@@ -155,6 +155,7 @@ in
       systemd.services."zpool-import" = {
         description = "Import zpools";
         after = [ "systemd-udev-settle.service" ];
+        wantedBy = [ "local-fs.target" ];
         serviceConfig = {
           Type = "oneshot";
           RemainAfterExit = true;
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 97b37b0714cd..22b52f77b145 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -345,10 +345,20 @@ in
 
         interfaces = mkOption {
           example = [ "enp4s0f0" "enp4s0f1" "wlan0" ];
-          type = types.listOf types.string;
+          type = types.listOf types.str;
           description = "The interfaces to bond together";
         };
 
+        lacp_rate = mkOption {
+          default = null;
+          example = "fast";
+          type = types.nullOr types.str;
+          description = ''
+            Option specifying the rate in which we'll ask our link partner
+            to transmit LACPDU packets in 802.3ad mode.
+          '';
+        };
+
         miimon = mkOption {
           default = null;
           example = 100;
@@ -364,7 +374,7 @@ in
         mode = mkOption {
           default = null;
           example = "active-backup";
-          type = types.nullOr types.string;
+          type = types.nullOr types.str;
           description = ''
             The mode which the bond will be running. The default mode for
             the bonding driver is balance-rr, optimizing for throughput.
@@ -373,6 +383,16 @@ in
           '';
         };
 
+        xmit_hash_policy = mkOption {
+          default = null;
+          example = "layer2+3";
+          type = types.nullOr types.str;
+          description = ''
+            Selects the transmit hash policy to use for slave selection in
+            balance-xor, 802.3ad, and tlb modes.
+          '';
+        };
+
       };
     };
 
@@ -753,34 +773,41 @@ in
             wantedBy = [ "network.target" (subsystemDevice n) ];
             bindsTo = deps;
             after = deps;
+            before = [ "${n}-cfg.service" ];
             serviceConfig.Type = "oneshot";
             serviceConfig.RemainAfterExit = true;
             path = [ pkgs.ifenslave pkgs.iproute ];
             script = ''
-              # Remove Dead Interfaces
-              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
-
-              ip link add "${n}" type bond
+              ip link add name "${n}" type bond
 
               # !!! There must be a better way to wait for the interface
               while [ ! -d /sys/class/net/${n} ]; do sleep 0.1; done;
 
+              # Ensure the link is down so that we can set options
+              ip link set "${n}" down
+
               # Set the miimon and mode options
               ${optionalString (v.miimon != null)
-                "echo ${toString v.miimon} > /sys/class/net/${n}/bonding/miimon"}
+                "echo \"${toString v.miimon}\" >/sys/class/net/${n}/bonding/miimon"}
               ${optionalString (v.mode != null)
-                "echo \"${v.mode}\" > /sys/class/net/${n}/bonding/mode"}
+                "echo \"${v.mode}\" >/sys/class/net/${n}/bonding/mode"}
+              ${optionalString (v.lacp_rate != null)
+                "echo \"${v.lacp_rate}\" >/sys/class/net/${n}/bonding/lacp_rate"}
+              ${optionalString (v.xmit_hash_policy != null)
+                "echo \"${v.xmit_hash_policy}\" >/sys/class/net/${n}/bonding/xmit_hash_policy"}
 
-              # Bring up the bridge and enslave the specified interfaces
+              # Bring up the bond and enslave the specified interfaces
               ip link set "${n}" up
               ${flip concatMapStrings v.interfaces (i: ''
                 ifenslave "${n}" "${i}"
               '')}
             '';
             postStop = ''
-              ip link set "${n}" down
-              ifenslave -d "${n}"
-              ip link delete "${n}"
+              ${flip concatMapStrings v.interfaces (i: ''
+                ifenslave -d "${n}" "${i}" >/dev/null 2>&1 || true
+              '')}
+              ip link set "${n}" down >/dev/null 2>&1 || true
+              ip link del "${n}" >/dev/null 2>&1 || true
             '';
           });
 
@@ -798,7 +825,7 @@ in
             script = ''
               # Remove Dead Interfaces
               ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
-              ip link add "${n}" type sit \
+              ip link add name "${n}" type sit \
                 ${optionalString (v.remote != null) "remote \"${v.remote}\""} \
                 ${optionalString (v.local != null) "local \"${v.local}\""} \
                 ${optionalString (v.ttl != null) "ttl ${toString v.ttl}"} \
@@ -824,7 +851,7 @@ in
             script = ''
               # Remove Dead Interfaces
               ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
-              ip link add link "${v.interface}" "${n}" type vlan id "${toString v.id}"
+              ip link add link "${v.interface}" name "${n}" type vlan id "${toString v.id}"
               ip link set "${n}" up
             '';
             postStop = ''
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index 54a376c9560e..4b4284d85319 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -98,7 +98,7 @@ let kernel = config.boot.kernelPackages.kernel; in
     networking.usePredictableInterfaceNames = false;
 
     # Make it easy to log in as root when running the test interactively.
-    security.initialRootPassword = mkDefault "";
+    users.extraUsers.root.initialHashedPassword = mkOverride 150 "";
 
   };
 
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index e129e496fe36..d175bac3074d 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -70,10 +70,10 @@ in
 
             # 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.
@@ -191,10 +191,5 @@ in
     environment.systemPackages = [ pkgs.cryptsetup ];
 
     boot.initrd.supportedFilesystems = [ "unionfs-fuse" ];
-
-    # Prevent logging in as root without a password.  This doesn't really matter,
-    # since the only PAM services that allow logging in with a null
-    # password are local ones that are inaccessible on EC2 machines.
-    security.initialRootPassword = mkDefault "!";
   };
 }
diff --git a/nixos/modules/virtualisation/docker-image.nix b/nixos/modules/virtualisation/docker-image.nix
index 13b861dc9884..cabb1712b6c0 100644
--- a/nixos/modules/virtualisation/docker-image.nix
+++ b/nixos/modules/virtualisation/docker-image.nix
@@ -38,8 +38,8 @@ in {
     '';
 
 
-  # docker image config
-  require = [
+  # Docker image config.
+  imports = [
     ../installer/cd-dvd/channel.nix
     ../profiles/minimal.nix
     ../profiles/clone-config.nix
@@ -47,16 +47,16 @@ in {
 
   boot.isContainer = true;
 
-  # Iptables do not work in docker
+  # Iptables do not work in Docker.
   networking.firewall.enable = false;
 
   services.openssh.enable = true;
 
-  # Socket activated ssh presents problem in docker
+  # Socket activated ssh presents problem in Docker.
   services.openssh.startWhenNeeded = false;
 
-  # Allow the user to login as root without password
-  security.initialRootPassword = "";
+  # Allow the user to login as root without password.
+  users.extraUsers.root.initialHashedPassword = mkOverride 150 "";
 
   # Some more help text.
   services.mingetty.helpLine =
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index 1ce066cdc73d..11d3f576728f 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -7,6 +7,8 @@ with lib;
 let
 
   cfg = config.virtualisation.docker;
+  pro = config.nix.proxy;
+  proxy_env = optionalAttrs (pro != "") { Environment = "\"http_proxy=${pro}\""; };
 
 in
 
@@ -73,7 +75,7 @@ in
           #  goes in config bundled with docker itself
           LimitNOFILE = 1048576;
           LimitNPROC = 1048576;
-        };
+        } // proxy_env;
       };
 
       systemd.sockets.docker = {
@@ -99,7 +101,7 @@ in
           #  goes in config bundled with docker itself
           LimitNOFILE = 1048576;
           LimitNPROC = 1048576;
-        };
+        } // proxy_env;
 
         # Presumably some containers are running we don't want to interrupt
         restartIfChanged = false;
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 33f48d65d43e..a7610b3e11a0 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -383,7 +383,7 @@ in
 
     # When building a regular system configuration, override whatever
     # video driver the host uses.
-    services.xserver.videoDrivers = mkVMOverride [ "vesa" ];
+    services.xserver.videoDrivers = mkVMOverride [ "modesetting" ];
     services.xserver.defaultDepth = mkVMOverride 0;
     services.xserver.resolutions = mkVMOverride [ { x = 1024; y = 768; } ];
     services.xserver.monitorSection =
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index ca7ca2afb65f..5173c33cab71 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -47,12 +47,10 @@ in rec {
         (all nixos.iso_graphical)
         (all nixos.ova)
 
-        #(all nixos.tests.efi-installer.simple)
         #(all nixos.tests.containers)
         (all nixos.tests.firefox)
         (all nixos.tests.firewall)
         (all nixos.tests.gnome3)
-        #(all nixos.tests.installer.efi)
         (all nixos.tests.installer.grub1)
         (all nixos.tests.installer.lvm)
         (all nixos.tests.installer.separateBoot)
diff --git a/nixos/release-small.nix b/nixos/release-small.nix
new file mode 100644
index 000000000000..07cd672843ea
--- /dev/null
+++ b/nixos/release-small.nix
@@ -0,0 +1,93 @@
+# This jobset is used to generate a NixOS channel that contains a
+# small subset of Nixpkgs, mostly useful for servers that need fast
+# security updates.
+
+{ nixpkgs ? { outPath = ./..; revCount = 56789; shortRev = "gfedcba"; }
+, stableBranch ? false
+, supportedSystems ? [ "x86_64-linux" ] # no i686-linux
+}:
+
+let
+
+  nixpkgsSrc = nixpkgs; # urgh
+
+  pkgs = import ./.. {};
+
+  lib = pkgs.lib;
+
+  nixos' = import ./release.nix {
+    inherit stableBranch supportedSystems;
+    nixpkgs = nixpkgsSrc;
+  };
+
+  nixpkgs' = builtins.removeAttrs (import ../pkgs/top-level/release.nix {
+    inherit supportedSystems;
+    nixpkgs = nixpkgsSrc;
+  }) [ "unstable" ];
+
+in rec {
+
+  nixos = {
+    inherit (nixos') channel manual iso_minimal dummy;
+    tests = {
+      inherit (nixos'.tests)
+        containers
+        firewall
+        ipv6
+        login
+        misc
+        nat
+        nfs3
+        openssh
+        proxy
+        simple;
+      installer = {
+        inherit (nixos'.tests.installer)
+          grub1
+          lvm
+          separateBoot
+          simple;
+      };
+    };
+  };
+
+  nixpkgs = {
+    inherit (nixpkgs')
+      apacheHttpd_2_2
+      apacheHttpd_2_4
+      cmake
+      cryptsetup
+      emacs
+      gettext
+      git
+      imagemagick
+      linux
+      mysql51
+      mysql55
+      nginx
+      nodejs
+      openjdk
+      openssh
+      php
+      postgresql92
+      postgresql93
+      python
+      rsyslog
+      stdenv
+      subversion
+      tarball
+      vim;
+  };
+
+  tested = pkgs.releaseTools.aggregate {
+    name = "nixos-${nixos.channel.version}";
+    meta = {
+      description = "Release-critical builds for the NixOS channel";
+      maintainers = [ lib.maintainers.eelco ];
+    };
+    constituents =
+      let all = x: map (system: x.${system}) supportedSystems; in
+      [ nixpkgs.tarball ] ++ lib.collect lib.isDerivation nixos;
+  };
+
+}
diff --git a/nixos/release.nix b/nixos/release.nix
index 7337ad7e3f45..5a89b38acc77 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -132,6 +132,10 @@ in rec {
   manpages = buildFromConfig ({ pkgs, ... }: { }) (config: config.system.build.manual.manpages);
 
 
+  # Build the initial ramdisk so Hydra can keep track of its size over time.
+  initialRamdisk = buildFromConfig ({ pkgs, ... }: { }) (config: config.system.build.initialRamdisk);
+
+
   iso_minimal = forAllSystems (system: makeIso {
     module = ./modules/installer/cd-dvd/installation-cd-minimal.nix;
     type = "minimal";
@@ -188,12 +192,15 @@ in rec {
 
   # Ensure that all packages used by the minimal NixOS config end up in the channel.
   dummy = forAllSystems (system: pkgs.runCommand "dummy"
-    { propagatedBuildInputs = (import lib/eval-config.nix {
+    { toplevel = (import lib/eval-config.nix {
         inherit system;
-        modules = lib.singleton ({ config, pkgs, ... }: { });
-      }).config.environment.systemPackages;
+        modules = lib.singleton ({ config, pkgs, ... }:
+          { fileSystems."/".device  = lib.mkDefault "/dev/sda1";
+            boot.loader.grub.device = lib.mkDefault "/dev/sda";
+          });
+      }).config.system.build.toplevel;
     }
-    "mkdir $out; fixupPhase");
+    "mkdir $out; ln -s $toplevel $out/dummy");
 
 
   # Provide a tarball that can be unpacked into an SD card, and easily
@@ -227,11 +234,12 @@ in rec {
   # ‘nix-build tests/login.nix -A result’.
   tests.avahi = callTest tests/avahi.nix {};
   tests.bittorrent = callTest tests/bittorrent.nix {};
+  tests.blivet = callTest tests/blivet.nix {};
+  tests.cjdns = callTest tests/cjdns.nix {};
   tests.containers = callTest tests/containers.nix {};
   tests.firefox = callTest tests/firefox.nix {};
   tests.firewall = callTest tests/firewall.nix {};
   tests.gnome3 = callTest tests/gnome3.nix {};
-  tests.installer.efi = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).efi.test);
   tests.installer.grub1 = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).grub1.test);
   tests.installer.lvm = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).lvm.test);
   tests.installer.rebuildCD = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).rebuildCD.test);
diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix
index c4a00ee507b2..3500ad8ccc31 100644
--- a/nixos/tests/bittorrent.nix
+++ b/nixos/tests/bittorrent.nix
@@ -28,7 +28,7 @@ in
   nodes =
     { tracker =
         { config, pkgs, ... }:
-        { environment.systemPackages = [ pkgs.transmission ];
+        { environment.systemPackages = [ pkgs.transmission pkgs.opentracker ];
 
           # We need Apache on the tracker to serve the torrents.
           services.httpd.enable = true;
@@ -86,7 +86,7 @@ in
 
       # Start the tracker.  !!! use a less crappy tracker
       $tracker->waitForUnit("network.target");
-      $tracker->succeed("bittorrent-tracker --port 6969 --dfile /tmp/dstate >&2 &");
+      $tracker->succeed("opentracker -p 6969 >&2 &");
       $tracker->waitForOpenPort(6969);
 
       # Start the initial seeder.
diff --git a/nixos/tests/blivet.nix b/nixos/tests/blivet.nix
new file mode 100644
index 000000000000..acaf4fec614f
--- /dev/null
+++ b/nixos/tests/blivet.nix
@@ -0,0 +1,85 @@
+import ./make-test.nix ({ pkgs, ... }: with pkgs.pythonPackages; rec {
+  name = "blivet";
+
+  machine = {
+    environment.systemPackages = [ pkgs.python blivet mock ];
+    boot.supportedFilesystems = [ "btrfs" "jfs" "reiserfs" "xfs" ];
+    virtualisation.memorySize = 768;
+  };
+
+  debugBlivet       = false;
+  debugProgramCalls = false;
+
+  pythonTestRunner = pkgs.writeText "run-blivet-tests.py" ''
+    import sys
+    import logging
+
+    from unittest import TestLoader
+    from unittest.runner import TextTestRunner
+
+    ${pkgs.lib.optionalString debugProgramCalls ''
+      blivet_program_log = logging.getLogger("program")
+      blivet_program_log.setLevel(logging.DEBUG)
+      blivet_program_log.addHandler(logging.StreamHandler(sys.stderr))
+    ''}
+
+    ${pkgs.lib.optionalString debugBlivet ''
+      blivet_log = logging.getLogger("blivet")
+      blivet_log.setLevel(logging.DEBUG)
+      blivet_log.addHandler(logging.StreamHandler(sys.stderr))
+    ''}
+
+    runner = TextTestRunner(verbosity=2, failfast=False, buffer=False)
+    result = runner.run(TestLoader().discover('tests/', pattern='*_test.py'))
+    sys.exit(not result.wasSuccessful())
+  '';
+
+  blivetTest = pkgs.writeScript "blivet-test.sh" ''
+    #!${pkgs.stdenv.shell} -e
+
+    # Use the hosts temporary directory, because we have a tmpfs within the VM
+    # and we don't want to increase the memory size of the VM for no reason.
+    mkdir -p /tmp/xchg/bigtmp
+    TMPDIR=/tmp/xchg/bigtmp
+    export TMPDIR
+
+    mkPythonPath() {
+      nix-store -qR "$@" \
+        | sed -e 's|$|/lib/${pkgs.python.libPrefix}/site-packages|'
+    }
+
+    cp -Rd "${blivet.src}/tests" .
+
+    # Skip SELinux tests
+    rm -f tests/formats_test/selinux_test.py
+
+    # Race conditions in growing/shrinking during resync
+    rm -f tests/devicelibs_test/mdraid_*
+
+    # Deactivate small BTRFS device test, because it fails with newer btrfsprogs
+    sed -i -e '/^class *BTRFSAsRootTestCase3(/,/^[^ ]/ {
+      /^class *BTRFSAsRootTestCase3(/d
+      /^$/d
+      /^ /d
+    }' tests/devicelibs_test/btrfs_test.py
+
+    # How on earth can these tests ever work even upstream? O_o
+    sed -i -e '/def testDiskChunk[12]/,/^ *[^ ]/{n; s/^ */&return # /}' \
+      tests/partitioning_test.py
+
+    # fix hardcoded temporary directory
+    sed -i \
+      -e '1i import tempfile' \
+      -e 's|_STORE_FILE_PATH = .*|_STORE_FILE_PATH = tempfile.gettempdir()|' \
+      tests/loopbackedtestcase.py
+
+    PYTHONPATH=".:$(mkPythonPath "${blivet}" "${mock}" | paste -sd :)" \
+      python "${pythonTestRunner}"
+  '';
+
+  testScript = ''
+    $machine->waitForUnit("multi-user.target");
+    $machine->succeed("${blivetTest}");
+    $machine->execute("rm -rf /tmp/xchg/bigtmp");
+  '';
+})
diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix
new file mode 100644
index 000000000000..7bb3863c683f
--- /dev/null
+++ b/nixos/tests/cjdns.nix
@@ -0,0 +1,123 @@
+let
+  carolKey = "2d2a338b46f8e4a8c462f0c385b481292a05f678e19a2b82755258cf0f0af7e2";
+  carolPubKey = "n932l3pjvmhtxxcdrqq2qpw5zc58f01vvjx01h4dtd1bb0nnu2h0.k";
+  carolPassword = "678287829ce4c67bc8b227e56d94422ee1b85fa11618157b2f591de6c6322b52";
+  carolIp4 = "192.168.0.9";
+  
+  basicConfig =
+    { config, pkgs, ... }:
+    { services.cjdns.enable = true;
+    
+      # Turning off DHCP isn't very realistic but makes
+      # the sequence of address assignment less stochastic.
+      networking.useDHCP = false;
+      
+      networking.interfaces.eth1.prefixLength = 24;
+      # CJDNS output is incompatible with the XML log.
+      systemd.services.cjdns.serviceConfig.StandardOutput = "null";
+      #networking.firewall.enable = true;
+      networking.firewall.allowPing = true;
+      #networking.firewall.rejectPackets = true;
+    };
+
+in
+
+import ./make-test.nix {
+  name = "cjdns";
+
+  nodes = rec
+    { # Alice finds peers over over ETHInterface.
+      alice =
+        { config, ... }:
+        { imports = [ basicConfig ];
+
+          services.cjdns.ETHInterface.bind = "eth1";
+
+          services.httpd.enable = true;
+          services.httpd.adminAddr = "foo@example.org";
+          networking.firewall.allowedTCPPorts = [ 80 ];
+        };
+
+      # Bob explicitly connects to Carol over UDPInterface.
+      bob =
+        { config, lib, nodes, ... }:
+        
+        let carolIp4 = lib.mkForce nodes.carol.config.networking.interfaces.eth1; in
+        
+          { imports = [ basicConfig ];
+          
+          networking.interfaces.eth1.ipAddress = "192.168.0.2";
+          
+          services.cjdns =
+            { UDPInterface =
+                { bind = "0.0.0.0:1024";
+                  connectTo."192.168.0.1:1024}" =
+                    { hostname = "carol.hype";
+                      password = carolPassword;
+                      publicKey = carolPubKey;
+                    };
+                };
+            };
+        };
+
+      # Carol listens on ETHInterface and UDPInterface,
+      # but knows neither Alice or Bob.
+      carol =
+        { config, lib, nodes, ... }:
+          let
+            carolIp4 = (lib.mkForce nodes.carol.config.networking.interfaces.eth1);
+          in
+          { imports = [ basicConfig ];
+
+          environment.etc."cjdns.keys".text = ''
+            CJDNS_PRIVATE_KEY=${carolKey}
+            CJDNS_ADMIN_PASSWORD=FOOBAR
+          '';
+
+          networking.interfaces.eth1.ipAddress = "192.168.0.1";
+                    
+          services.cjdns =
+            { authorizedPasswords = [ carolPassword ];
+              ETHInterface.bind = "eth1";
+              UDPInterface.bind = "192.168.0.1:1024";
+            };
+          networking.firewall.allowedUDPPorts = [ 1024 ];
+        };
+
+    };
+
+  testScript =
+    ''
+      startAll;
+
+      $alice->waitForUnit("cjdns.service");
+      $bob->waitForUnit("cjdns.service");
+      $carol->waitForUnit("cjdns.service");
+
+      sub cjdnsIp {
+          my ($machine) = @_;
+          my $ip = (split /[ \/]+/, $machine->succeed("ip -o -6 addr show dev tun0"))[3];
+          $machine->log("has ip $ip");
+          return $ip;
+      }
+
+      my $aliceIp6 = cjdnsIp $alice;
+      my $bobIp6   = cjdnsIp $bob;
+      my $carolIp6 = cjdnsIp $carol;
+
+      # ping a few times each to let the routing table establish itself
+      
+      $alice->succeed("ping6 -c 4 $carolIp6");
+      $bob->succeed("ping6 -c 4 carol.hype");
+
+      $carol->succeed("ping6 -c 4 $aliceIp6");
+      $carol->succeed("ping6 -c 4 $bobIp6");
+      
+      $alice->succeed("ping6 -c 4 $bobIp6");
+      $bob->succeed("ping6 -c 4 $aliceIp6");
+
+      $alice->waitForUnit("httpd.service");
+
+      $bob->succeed("curl --fail -g http://[$aliceIp6]");
+    '';
+}
diff --git a/nixos/tests/gnome3.nix b/nixos/tests/gnome3.nix
index df30283e3155..6f2925e52fa4 100644
--- a/nixos/tests/gnome3.nix
+++ b/nixos/tests/gnome3.nix
@@ -11,6 +11,8 @@ import ./make-test.nix {
       services.xserver.displayManager.auto.enable = true;
       services.xserver.displayManager.auto.user = "alice";
       services.xserver.desktopManager.gnome3.enable = true;
+
+      virtualisation.memorySize = 512;
     };
 
   testScript =
diff --git a/nixos/tests/gnome3_12.nix b/nixos/tests/gnome3_12.nix
index 723d1bc45229..3b38d779b6f8 100644
--- a/nixos/tests/gnome3_12.nix
+++ b/nixos/tests/gnome3_12.nix
@@ -12,6 +12,8 @@ import ./make-test.nix {
       services.xserver.displayManager.auto.user = "alice";
       services.xserver.desktopManager.gnome3.enable = true;
       environment.gnome3.packageSet = pkgs.gnome3_12;
+
+      virtualisation.memorySize = 512;
     };
 
   testScript =
diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 138a81ad8075..4ee0e064c100 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -35,7 +35,7 @@ let
 
 
   # The configuration to install.
-  makeConfig = { testChannel, useEFI, grubVersion, grubDevice, grubIdentifier
+  makeConfig = { testChannel, grubVersion, grubDevice, grubIdentifier
     , readOnly ? true, forceGrubReinstallCount ? 0 }:
     pkgs.writeText "configuration.nix" ''
       { config, pkgs, modulesPath, ... }:
@@ -46,18 +46,13 @@ let
             <nixpkgs/nixos/modules/profiles/minimal.nix>
           ];
 
-        ${if useEFI then ''
-          boot.loader.efi.canTouchEfiVariables = true;
-          boot.loader.gummiboot.enable = true;
-        '' else ''
-          boot.loader.grub.version = ${toString grubVersion};
-          ${optionalString (grubVersion == 1) ''
-            boot.loader.grub.splashImage = null;
-          ''}
-          boot.loader.grub.device = "${grubDevice}";
-          boot.loader.grub.extraConfig = "serial; terminal_output.serial";
-          boot.loader.grub.fsIdentifier = "${grubIdentifier}";
+        boot.loader.grub.version = ${toString grubVersion};
+        ${optionalString (grubVersion == 1) ''
+          boot.loader.grub.splashImage = null;
         ''}
+        boot.loader.grub.device = "${grubDevice}";
+        boot.loader.grub.extraConfig = "serial; terminal_output.serial";
+        boot.loader.grub.fsIdentifier = "${grubIdentifier}";
 
         boot.loader.grub.configurationLimit = 100 + ${toString forceGrubReinstallCount};
 
@@ -100,16 +95,14 @@ let
   # disk, and then reboot from the hard disk.  It's parameterized with
   # a test script fragment `createPartitions', which must create
   # partitions and filesystems.
-  testScriptFun = { createPartitions, testChannel, useEFI, grubVersion, grubDevice, grubIdentifier }:
+  testScriptFun = { createPartitions, testChannel, grubVersion, grubDevice, grubIdentifier }:
     let
       # FIXME: OVMF doesn't boot from virtio http://www.mail-archive.com/edk2-devel@lists.sourceforge.net/msg01501.html
-      iface = if useEFI || grubVersion == 1 then "scsi" else "virtio";
+      iface = if grubVersion == 1 then "scsi" else "virtio";
       qemuFlags =
         (if iso.system == "x86_64-linux" then "-m 768 " else "-m 512 ") +
-        (optionalString (iso.system == "x86_64-linux") "-cpu kvm64 ") +
-        (optionalString useEFI ''-L ${efiBios} -hda ''${\(Cwd::abs_path('harddisk'))} '');
-      hdFlags = optionalString (!useEFI)
-        ''hda => "harddisk", hdaInterface => "${iface}", '';
+        (optionalString (iso.system == "x86_64-linux") "-cpu kvm64 ");
+      hdFlags =''hda => "harddisk", hdaInterface => "${iface}", '';
     in
     ''
       createDisk("harddisk", 4 * 1024);
@@ -168,7 +161,7 @@ let
       $machine->succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2");
 
       $machine->copyFileFromHost(
-          "${ makeConfig { inherit testChannel useEFI grubVersion grubDevice grubIdentifier; } }",
+          "${ makeConfig { inherit testChannel grubVersion grubDevice grubIdentifier; } }",
           "/mnt/etc/nixos/configuration.nix");
 
       # Perform the installation.
@@ -189,11 +182,7 @@ let
       # Did /boot get mounted?
       $machine->waitForUnit("local-fs.target");
 
-      ${if useEFI then ''
-        $machine->succeed("test -e /boot/efi");
-      '' else ''
-        $machine->succeed("test -e /boot/grub");
-      ''}
+      $machine->succeed("test -e /boot/grub");
 
       # Did the swap device get activated?
       $machine->waitForUnit("swap.target");
@@ -206,7 +195,7 @@ let
 
       # We need to a writable nix-store on next boot
       $machine->copyFileFromHost(
-          "${ makeConfig { inherit testChannel useEFI grubVersion grubDevice grubIdentifier; readOnly = false; forceGrubReinstallCount = 1; } }",
+          "${ makeConfig { inherit testChannel grubVersion grubDevice grubIdentifier; readOnly = false; forceGrubReinstallCount = 1; } }",
           "/etc/nixos/configuration.nix");
 
       # Check whether nixos-rebuild works.
@@ -223,7 +212,7 @@ let
       $machine = createMachine({ ${hdFlags} qemuFlags => "${qemuFlags}" });
       $machine->waitForUnit("multi-user.target");
       $machine->copyFileFromHost(
-          "${ makeConfig { inherit testChannel useEFI grubVersion grubDevice grubIdentifier; readOnly = false; forceGrubReinstallCount = 2; } }",
+          "${ makeConfig { inherit testChannel grubVersion grubDevice grubIdentifier; readOnly = false; forceGrubReinstallCount = 2; } }",
           "/etc/nixos/configuration.nix");
       $machine->succeed("nixos-rebuild boot >&2");
       $machine->shutdown;
@@ -237,13 +226,13 @@ let
 
 
   makeInstallerTest = name:
-    { createPartitions, testChannel ? false, useEFI ? false, grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid" }:
+    { createPartitions, testChannel ? false, grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid" }:
     makeTest {
       inherit iso;
       name = "installer-" + name;
       nodes = if testChannel then { inherit webserver; } else { };
       testScript = testScriptFun {
-        inherit createPartitions testChannel useEFI grubVersion grubDevice grubIdentifier;
+        inherit createPartitions testChannel grubVersion grubDevice grubIdentifier;
       };
     };
 
@@ -369,25 +358,6 @@ in {
       grubDevice = "/dev/sda";
     };
 
-  # Test an EFI install.
-  efi = makeInstallerTest "efi"
-    { createPartitions =
-        ''
-          $machine->succeed(
-              "sgdisk -Z /dev/sda",
-              "sgdisk -n 1:0:+256M -n 2:0:+1024M -N 3 -t 1:ef00 -t 2:8200 -t 3:8300 -c 1:boot -c 2:swap -c 3:root /dev/sda",
-              "mkfs.vfat -n BOOT /dev/sda1",
-              "mkswap /dev/sda2 -L swap",
-              "swapon -L swap",
-              "mkfs.ext3 -L nixos /dev/sda3",
-              "mount LABEL=nixos /mnt",
-              "mkdir /mnt/boot",
-              "mount LABEL=BOOT /mnt/boot",
-          );
-        '';
-      useEFI = true;
-    };
-
   # Rebuild the CD configuration with a little modification.
   rebuildCD = makeTest
     { inherit iso;
diff --git a/nixos/tests/jenkins.nix b/nixos/tests/jenkins.nix
index f0d3139d902c..3f4a197ebcc4 100644
--- a/nixos/tests/jenkins.nix
+++ b/nixos/tests/jenkins.nix
@@ -17,7 +17,7 @@ import ./make-test.nix {
 
         users.extraUsers.jenkins.extraGroups = [ "users" ];
 
-        systemd.services.jenkins.unitConfig.TimeoutSec = 240;
+        systemd.services.jenkins.serviceConfig.TimeoutStartSec = "3min";
       };
 
     slave =
diff --git a/nixos/tests/kde4.nix b/nixos/tests/kde4.nix
index 90c37397821e..fcc5101feb3d 100644
--- a/nixos/tests/kde4.nix
+++ b/nixos/tests/kde4.nix
@@ -32,7 +32,7 @@ import ./make-test.nix ({ pkgs, ... }: {
           pkgs.kde4.kdegraphics
           pkgs.kde4.kdeutils
           pkgs.kde4.kdegames
-          pkgs.kde4.kdeedu
+          #pkgs.kde4.kdeedu
           pkgs.kde4.kdeaccessibility
           pkgs.kde4.kdeadmin
           pkgs.kde4.kdenetwork
diff --git a/nixos/tests/munin.nix b/nixos/tests/munin.nix
index d18abd68ee0e..1e51453df83b 100644
--- a/nixos/tests/munin.nix
+++ b/nixos/tests/munin.nix
@@ -18,7 +18,7 @@ import ./make-test.nix {
              '';
            };
           };
-          systemd.services.munin-node.unitConfig.TimeoutSec = 240;
+          systemd.services.munin-node.serviceConfig.TimeoutStartSec = "3min";
         };
     };
 
diff --git a/nixos/tests/partition.nix b/nixos/tests/partition.nix
index 72fd37e041e5..5e94b263d5b8 100644
--- a/nixos/tests/partition.nix
+++ b/nixos/tests/partition.nix
@@ -67,7 +67,7 @@ in {
 
   machine = { config, pkgs, ... }: {
     environment.systemPackages = [
-      pkgs.pythonPackages.nixpart
+      pkgs.pythonPackages.nixpart0
       pkgs.file pkgs.btrfsProgs pkgs.xfsprogs pkgs.lvm2
     ];
     virtualisation.emptyDiskImages = [ 4096 4096 ];
@@ -209,7 +209,7 @@ in {
       ensurePartition("swap", "swap");
       ensurePartition("boot", "f2fs");
       ensurePartition("root", "f2fs");
-      remoteAndCheck;
+      remountAndCheck;
       ensureMountPoint("/mnt/boot", "f2fs");
     };
 
diff --git a/nixos/tests/proxy.nix b/nixos/tests/proxy.nix
index 01f0f3fe17a3..8350bc5c6a4b 100644
--- a/nixos/tests/proxy.nix
+++ b/nixos/tests/proxy.nix
@@ -22,20 +22,19 @@ in
 
         { services.httpd.enable = true;
           services.httpd.adminAddr = "bar@example.org";
-          services.httpd.extraModules = ["proxy_balancer"];
+          services.httpd.extraModules = [ "proxy_balancer" "lbmethod_byrequests" ];
 
           services.httpd.extraConfig =
             ''
               ExtendedStatus on
 
               <Location /server-status>
-                Order deny,allow
-                Allow from all
+                Require all granted
                 SetHandler server-status
               </Location>
 
               <Proxy balancer://cluster>
-                Allow from all
+                Require all granted
                 BalancerMember http://${nodes.backend1.config.networking.hostName} retry=0
                 BalancerMember http://${nodes.backend2.config.networking.hostName} retry=0
               </Proxy>
diff --git a/nixos/tests/run-in-machine.nix b/nixos/tests/run-in-machine.nix
index 7f6e6a6dc573..d1102f8d4073 100644
--- a/nixos/tests/run-in-machine.nix
+++ b/nixos/tests/run-in-machine.nix
@@ -2,9 +2,7 @@
 
 with import ../lib/testing.nix { inherit system; };
 
-{
-  test = runInMachine {
-    drv = pkgs.hello;
-    machine = { config, pkgs, ... }: { /* services.sshd.enable = true; */ };
-  };
+runInMachine {
+  drv = pkgs.hello;
+  machine = { config, pkgs, ... }: { /* services.sshd.enable = true; */ };
 }