about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/administration/cleaning-store.xml4
-rw-r--r--nixos/doc/manual/administration/container-networking.xml4
-rw-r--r--nixos/doc/manual/administration/imperative-containers.xml24
-rw-r--r--nixos/doc/manual/administration/maintenance-mode.xml4
-rw-r--r--nixos/doc/manual/administration/network-problems.xml4
-rw-r--r--nixos/doc/manual/administration/rebooting.xml8
-rw-r--r--nixos/doc/manual/administration/rollback.xml8
-rw-r--r--nixos/doc/manual/administration/service-mgmt.xml6
-rw-r--r--nixos/doc/manual/administration/store-corruption.xml6
-rw-r--r--nixos/doc/manual/administration/user-sessions.xml4
-rw-r--r--nixos/doc/manual/configuration/adding-custom-packages.xml2
-rw-r--r--nixos/doc/manual/configuration/linux-kernel.xml6
-rw-r--r--nixos/doc/manual/configuration/luks-file-systems.xml14
-rw-r--r--nixos/doc/manual/configuration/user-mgmt.xml8
-rw-r--r--nixos/doc/manual/configuration/wireless.xml4
-rw-r--r--nixos/doc/manual/configuration/x-windows.xml13
-rw-r--r--nixos/doc/manual/development/building-nixos.xml4
-rw-r--r--nixos/doc/manual/development/building-parts.xml6
-rw-r--r--nixos/doc/manual/development/option-declarations.xml6
-rw-r--r--nixos/doc/manual/development/sources.xml2
-rw-r--r--nixos/doc/manual/development/testing-installer.xml8
-rw-r--r--nixos/doc/manual/installation/changing-config.xml8
-rw-r--r--nixos/doc/manual/installation/installing-uefi.xml6
-rw-r--r--nixos/doc/manual/installation/installing.xml38
-rw-r--r--nixos/doc/manual/installation/upgrading.xml12
-rw-r--r--nixos/doc/manual/man-configuration.xml4
-rw-r--r--nixos/doc/manual/man-nixos-build-vms.xml8
-rw-r--r--nixos/doc/manual/man-nixos-generate-config.xml4
-rw-r--r--nixos/doc/manual/man-nixos-option.xml4
-rw-r--r--nixos/doc/manual/manual.xml5
-rw-r--r--nixos/doc/manual/options-to-docbook.xsl3
-rw-r--r--nixos/doc/manual/release-notes/rl-1603.xml2
-rw-r--r--nixos/doc/manual/release-notes/rl-1609.xml9
-rw-r--r--nixos/lib/test-driver/Logger.pm4
-rw-r--r--nixos/lib/test-driver/Machine.pm12
-rw-r--r--nixos/lib/testing.nix8
-rw-r--r--nixos/lib/utils.nix6
-rw-r--r--nixos/modules/config/fonts/fontdir.nix54
-rw-r--r--nixos/modules/config/ldap.nix2
-rw-r--r--nixos/modules/config/networking.nix20
-rw-r--r--nixos/modules/config/shells-environment.nix12
-rw-r--r--nixos/modules/config/users-groups.nix27
-rw-r--r--nixos/modules/hardware/video/ati.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix4
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl37
-rw-r--r--nixos/modules/misc/ids.nix10
-rw-r--r--nixos/modules/misc/version.nix8
-rw-r--r--nixos/modules/module-list.nix17
-rw-r--r--nixos/modules/programs/bash/bash.nix2
-rw-r--r--nixos/modules/programs/fish.nix12
-rw-r--r--nixos/modules/programs/man.nix2
-rw-r--r--nixos/modules/programs/shadow.nix18
-rw-r--r--nixos/modules/programs/tmux.nix7
-rw-r--r--nixos/modules/programs/unity3d.nix25
-rw-r--r--nixos/modules/rename.nix22
-rw-r--r--nixos/modules/security/acme.nix180
-rw-r--r--nixos/modules/security/acme.xml28
-rw-r--r--nixos/modules/security/grsecurity.nix376
-rw-r--r--nixos/modules/security/setuid-wrappers.nix2
-rw-r--r--nixos/modules/services/audio/squeezelite.nix67
-rw-r--r--nixos/modules/services/computing/slurm/slurm.nix4
-rw-r--r--nixos/modules/services/continuous-integration/buildkite-agent.nix100
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix418
-rw-r--r--nixos/modules/services/databases/openldap.nix23
-rw-r--r--nixos/modules/services/databases/redis.nix24
-rw-r--r--nixos/modules/services/desktops/gnome3/gnome-keyring.nix2
-rw-r--r--nixos/modules/services/hardware/pcscd.nix55
-rw-r--r--nixos/modules/services/mail/opendkim.nix2
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix11
-rw-r--r--nixos/modules/services/mail/postfix.nix32
-rw-r--r--nixos/modules/services/misc/confd.nix2
-rw-r--r--nixos/modules/services/misc/disnix.nix108
-rw-r--r--nixos/modules/services/misc/dysnomia.nix217
-rw-r--r--nixos/modules/services/misc/etcd.nix2
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix324
-rw-r--r--nixos/modules/services/misc/parsoid.nix2
-rw-r--r--nixos/modules/services/misc/taskserver/default.nix2
-rw-r--r--nixos/modules/services/monitoring/bosun.nix2
-rw-r--r--nixos/modules/services/monitoring/grafana.nix2
-rw-r--r--nixos/modules/services/monitoring/scollector.nix2
-rw-r--r--nixos/modules/services/network-filesystems/diod.nix2
-rw-r--r--nixos/modules/services/networking/chrony.nix6
-rw-r--r--nixos/modules/services/networking/consul.nix8
-rw-r--r--nixos/modules/services/networking/coturn.nix327
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix4
-rw-r--r--nixos/modules/services/networking/ejabberd.nix2
-rw-r--r--nixos/modules/services/networking/mosquitto.nix219
-rw-r--r--nixos/modules/services/networking/networkmanager.nix8
-rw-r--r--nixos/modules/services/networking/ntpd.nix2
-rw-r--r--nixos/modules/services/networking/openntpd.nix3
-rw-r--r--nixos/modules/services/networking/openvpn.nix22
-rw-r--r--nixos/modules/services/networking/pptpd.nix124
-rw-r--r--nixos/modules/services/networking/skydns.nix2
-rw-r--r--nixos/modules/services/networking/syncthing.nix4
-rw-r--r--nixos/modules/services/networking/toxvpn.nix54
-rw-r--r--nixos/modules/services/networking/unbound.nix2
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix2
-rw-r--r--nixos/modules/services/networking/xl2tpd.nix143
-rw-r--r--nixos/modules/services/security/fail2ban.nix2
-rw-r--r--nixos/modules/services/security/hologram.nix2
-rw-r--r--nixos/modules/services/security/oauth2_proxy.nix523
-rw-r--r--nixos/modules/services/torrent/transmission.nix32
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix8
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/mediawiki.nix2
-rw-r--r--nixos/modules/services/web-servers/lighttpd/inginious.nix262
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix8
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix5
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix10
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix20
-rw-r--r--nixos/modules/services/x11/display-managers/kdm.nix2
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix4
-rw-r--r--nixos/modules/services/x11/window-managers/i3.nix71
-rw-r--r--nixos/modules/services/x11/xbanish.nix30
-rw-r--r--nixos/modules/services/x11/xserver.nix17
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix4
-rw-r--r--nixos/modules/system/boot/loader/efi.nix7
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix13
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py (renamed from nixos/modules/system/boot/loader/gummiboot/gummiboot-builder.py)6
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix (renamed from nixos/modules/system/boot/loader/gummiboot/gummiboot.nix)35
-rw-r--r--nixos/modules/system/boot/luksroot.nix44
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh2
-rw-r--r--nixos/modules/system/boot/systemd.nix8
-rw-r--r--nixos/modules/tasks/cpu-freq.nix2
-rw-r--r--nixos/modules/tasks/filesystems.nix20
-rw-r--r--nixos/modules/testing/test-instrumentation.nix10
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix2
-rw-r--r--nixos/modules/virtualisation/azure-common.nix4
-rw-r--r--nixos/modules/virtualisation/brightbox-image.nix2
-rw-r--r--nixos/modules/virtualisation/containers.nix6
-rw-r--r--nixos/modules/virtualisation/docker.nix2
-rw-r--r--nixos/modules/virtualisation/google-compute-image.nix2
-rw-r--r--nixos/modules/virtualisation/lxd.nix2
-rw-r--r--nixos/modules/virtualisation/nova-image.nix2
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix2
-rw-r--r--nixos/modules/virtualisation/virtualbox-guest.nix2
-rw-r--r--nixos/release-combined.nix1
-rw-r--r--nixos/tests/boot.nix6
-rw-r--r--nixos/tests/gnome3_20-gdm.nix41
-rw-r--r--nixos/tests/gnome3_20.nix38
-rw-r--r--nixos/tests/grsecurity.nix40
-rw-r--r--nixos/tests/installer.nix23
-rw-r--r--nixos/tests/sddm-kde5.nix41
-rw-r--r--nixos/tests/virtualbox.nix13
143 files changed, 3930 insertions, 928 deletions
diff --git a/nixos/doc/manual/administration/cleaning-store.xml b/nixos/doc/manual/administration/cleaning-store.xml
index 41dc65795b68..4cf62947f528 100644
--- a/nixos/doc/manual/administration/cleaning-store.xml
+++ b/nixos/doc/manual/administration/cleaning-store.xml
@@ -21,7 +21,7 @@ Alternatively, you can use a systemd unit that does the same in the
 background:
 
 <screen>
-$ systemctl start nix-gc.service
+# systemctl start nix-gc.service
 </screen>
 
 You can tell NixOS in <filename>configuration.nix</filename> to run
@@ -59,4 +59,4 @@ $ nix-store --optimise
 Since this command needs to read the entire Nix store, it can take
 quite a while to finish.</para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/nixos/doc/manual/administration/container-networking.xml b/nixos/doc/manual/administration/container-networking.xml
index adea3e69840d..1b1576d3babe 100644
--- a/nixos/doc/manual/administration/container-networking.xml
+++ b/nixos/doc/manual/administration/container-networking.xml
@@ -13,7 +13,7 @@ create</literal>, it gets it own private IPv4 address in the range
 address as follows:
 
 <screen>
-$ nixos-container show-ip foo
+# nixos-container show-ip foo
 10.233.4.2
 
 $ ping -c1 10.233.4.2
@@ -47,4 +47,4 @@ where <literal>eth0</literal> should be replaced with the desired
 external interface. Note that <literal>ve-+</literal> is a wildcard
 that matches all container interfaces.</para>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/nixos/doc/manual/administration/imperative-containers.xml b/nixos/doc/manual/administration/imperative-containers.xml
index 6131d4e04ea8..3a52658436ac 100644
--- a/nixos/doc/manual/administration/imperative-containers.xml
+++ b/nixos/doc/manual/administration/imperative-containers.xml
@@ -11,7 +11,7 @@
 identifier <literal>foo</literal> as follows:
 
 <screen>
-$ nixos-container create foo
+# nixos-container create foo
 </screen>
 
 This creates the container’s root directory in
@@ -25,7 +25,7 @@ line. For instance, to create a container that has
 <literal>root</literal>:
 
 <screen>
-$ nixos-container create foo --config 'services.openssh.enable = true; \
+# nixos-container create foo --config 'services.openssh.enable = true; \
   users.extraUsers.root.openssh.authorizedKeys.keys = ["ssh-dss AAAAB3N…"];'
 </screen>
 
@@ -35,7 +35,7 @@ $ nixos-container create foo --config 'services.openssh.enable = true; \
 run:
 
 <screen>
-$ nixos-container start foo
+# nixos-container start foo
 </screen>
 
 This command will return as soon as the container has booted and has
@@ -46,7 +46,7 @@ Thus, if something went wrong, you can get status info using
 <command>systemctl</command>:
 
 <screen>
-$ systemctl status container@foo
+# systemctl status container@foo
 </screen>
 
 </para>
@@ -55,7 +55,7 @@ $ systemctl status container@foo
 root using the <command>root-login</command> operation:
 
 <screen>
-$ nixos-container root-login foo
+# nixos-container root-login foo
 [root@foo:~]#
 </screen>
 
@@ -65,7 +65,7 @@ authentication).  You can also get a regular login prompt using the
 the host:
 
 <screen>
-$ nixos-container login foo
+# nixos-container login foo
 foo login: alice
 Password: ***
 </screen>
@@ -74,7 +74,7 @@ With <command>nixos-container run</command>, you can execute arbitrary
 commands in the container:
 
 <screen>
-$ nixos-container run foo -- uname -a
+# nixos-container run foo -- uname -a
 Linux foo 3.4.82 #1-NixOS SMP Thu Mar 20 14:44:05 UTC 2014 x86_64 GNU/Linux
 </screen>
 
@@ -86,17 +86,17 @@ container. First, on the host, you can edit
 and run
 
 <screen>
-$ nixos-container update foo
+# nixos-container update foo
 </screen>
 
 This will build and activate the new configuration. You can also
 specify a new configuration on the command line:
 
 <screen>
-$ nixos-container update foo --config 'services.httpd.enable = true; \
+# nixos-container update foo --config 'services.httpd.enable = true; \
   services.httpd.adminAddr = "foo@example.org";'
 
-$ curl http://$(nixos-container show-ip foo)/
+# curl http://$(nixos-container show-ip foo)/
 &lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">…
 </screen>
 
@@ -116,9 +116,9 @@ start</literal>, respectively, or by using
 destroy a container, including its file system, do
 
 <screen>
-$ nixos-container destroy foo
+# nixos-container destroy foo
 </screen>
 
 </para>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/nixos/doc/manual/administration/maintenance-mode.xml b/nixos/doc/manual/administration/maintenance-mode.xml
index 15c1f902da79..17a1609e5579 100644
--- a/nixos/doc/manual/administration/maintenance-mode.xml
+++ b/nixos/doc/manual/administration/maintenance-mode.xml
@@ -9,10 +9,10 @@
 <para>You can enter rescue mode by running:
 
 <screen>
-$ systemctl rescue</screen>
+# systemctl rescue</screen>
 
 This will eventually give you a single-user root shell.  Systemd will
 stop (almost) all system services.  To get out of maintenance mode,
 just exit from the rescue shell.</para>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/nixos/doc/manual/administration/network-problems.xml b/nixos/doc/manual/administration/network-problems.xml
index 3af9cc59742f..91f9eb4e22c6 100644
--- a/nixos/doc/manual/administration/network-problems.xml
+++ b/nixos/doc/manual/administration/network-problems.xml
@@ -18,14 +18,14 @@ You can disable the use of the binary cache by adding <option>--option
 use-binary-caches false</option>, e.g.
 
 <screen>
-$ nixos-rebuild switch --option use-binary-caches false
+# nixos-rebuild switch --option use-binary-caches false
 </screen>
 
 If you have an alternative binary cache at your disposal, you can use
 it instead:
 
 <screen>
-$ nixos-rebuild switch --option binary-caches http://my-cache.example.org/
+# nixos-rebuild switch --option binary-caches http://my-cache.example.org/
 </screen>
 
 </para>
diff --git a/nixos/doc/manual/administration/rebooting.xml b/nixos/doc/manual/administration/rebooting.xml
index d1db7b141cf2..23f3a3219c6a 100644
--- a/nixos/doc/manual/administration/rebooting.xml
+++ b/nixos/doc/manual/administration/rebooting.xml
@@ -10,7 +10,7 @@
 doing:
 
 <screen>
-$ shutdown
+# shutdown
 </screen>
 
 This is equivalent to running <command>systemctl
@@ -19,7 +19,7 @@ poweroff</command>.</para>
 <para>To reboot the system, run
 
 <screen>
-$ reboot
+# reboot
 </screen>
 
 which is equivalent to <command>systemctl reboot</command>.
@@ -28,7 +28,7 @@ Alternatively, you can quickly reboot the system using
 the new kernel into memory:
 
 <screen>
-$ systemctl kexec
+# systemctl kexec
 </screen>
 
 </para>
@@ -41,4 +41,4 @@ $ systemctl kexec
 i.e. on a virtual console or in X11; otherwise, the user is asked for
 authentication.</para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/nixos/doc/manual/administration/rollback.xml b/nixos/doc/manual/administration/rollback.xml
index 23a3ece7c070..ae621f33de2c 100644
--- a/nixos/doc/manual/administration/rollback.xml
+++ b/nixos/doc/manual/administration/rollback.xml
@@ -19,7 +19,7 @@ fails to boot.  After the system has booted, you can make the selected
 configuration the default for subsequent boots:
 
 <screen>
-$ /run/current-system/bin/switch-to-configuration boot</screen>
+# /run/current-system/bin/switch-to-configuration boot</screen>
 
 </para>
 
@@ -27,12 +27,12 @@ $ /run/current-system/bin/switch-to-configuration boot</screen>
 system:
 
 <screen>
-$ nixos-rebuild switch --rollback</screen>
+# nixos-rebuild switch --rollback</screen>
 
 This is equivalent to running:
 
 <screen>
-$ /nix/var/nix/profiles/system-<replaceable>N</replaceable>-link/bin/switch-to-configuration switch</screen>
+# /nix/var/nix/profiles/system-<replaceable>N</replaceable>-link/bin/switch-to-configuration switch</screen>
 
 where <replaceable>N</replaceable> is the number of the NixOS system
 configuration.  To get a list of the available configurations, do:
@@ -45,4 +45,4 @@ lrwxrwxrwx 1 root root 78 Aug 12 13:54 /nix/var/nix/profiles/system-268-link ->
 
 </para>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/nixos/doc/manual/administration/service-mgmt.xml b/nixos/doc/manual/administration/service-mgmt.xml
index c0940a42f307..1627c7a2fdeb 100644
--- a/nixos/doc/manual/administration/service-mgmt.xml
+++ b/nixos/doc/manual/administration/service-mgmt.xml
@@ -66,9 +66,9 @@ messages from the service.
 <para>Units can be stopped, started or restarted:
 
 <screen>
-$ systemctl stop postgresql.service
-$ systemctl start postgresql.service
-$ systemctl restart postgresql.service
+# systemctl stop postgresql.service
+# systemctl start postgresql.service
+# systemctl restart postgresql.service
 </screen>
 
 These operations are synchronous: they wait until the service has
diff --git a/nixos/doc/manual/administration/store-corruption.xml b/nixos/doc/manual/administration/store-corruption.xml
index 0160cb45358b..9f567042b727 100644
--- a/nixos/doc/manual/administration/store-corruption.xml
+++ b/nixos/doc/manual/administration/store-corruption.xml
@@ -18,7 +18,7 @@ you may be able to fix it automatically.</para>
 system configuration, you can fix it by doing
 
 <screen>
-$ nixos-rebuild switch --repair
+# nixos-rebuild switch --repair
 </screen>
 
 This will cause Nix to check every path in the closure, and if its
@@ -28,10 +28,10 @@ the path is rebuilt or redownloaded.</para>
 <para>You can also scan the entire Nix store for corrupt paths:
 
 <screen>
-$ nix-store --verify --check-contents --repair
+# nix-store --verify --check-contents --repair
 </screen>
 
 Any corrupt paths will be redownloaded if they’re available in a
 binary cache; otherwise, they cannot be repaired.</para>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/nixos/doc/manual/administration/user-sessions.xml b/nixos/doc/manual/administration/user-sessions.xml
index 05e2c1a9b29f..0a7eb8cd123c 100644
--- a/nixos/doc/manual/administration/user-sessions.xml
+++ b/nixos/doc/manual/administration/user-sessions.xml
@@ -45,9 +45,9 @@ track of this, you can terminate a session in a way that ensures that
 all the session’s processes are gone:
 
 <screen>
-$ loginctl terminate-session c3
+# loginctl terminate-session c3
 </screen>
 
 </para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/nixos/doc/manual/configuration/adding-custom-packages.xml b/nixos/doc/manual/configuration/adding-custom-packages.xml
index c1789fcbc041..ab3665bae504 100644
--- a/nixos/doc/manual/configuration/adding-custom-packages.xml
+++ b/nixos/doc/manual/configuration/adding-custom-packages.xml
@@ -31,7 +31,7 @@ and you run <command>nixos-rebuild</command>, specifying your own
 Nixpkgs tree:
 
 <screen>
-$ nixos-rebuild switch -I nixpkgs=/path/to/my/nixpkgs</screen>
+# nixos-rebuild switch -I nixpkgs=/path/to/my/nixpkgs</screen>
 
 </para>
 
diff --git a/nixos/doc/manual/configuration/linux-kernel.xml b/nixos/doc/manual/configuration/linux-kernel.xml
index 0cdae4f64416..52be26d6024a 100644
--- a/nixos/doc/manual/configuration/linux-kernel.xml
+++ b/nixos/doc/manual/configuration/linux-kernel.xml
@@ -19,7 +19,7 @@ kernel.</para>
 
 <para>The default Linux kernel configuration should be fine for most users. You can see the configuration of your current kernel with the following command:
 <programlisting>
-cat /proc/config.gz | gunzip
+zcat /proc/config.gz
 </programlisting>
 If you want to change the kernel configuration, you can use the
 <option>packageOverrides</option> feature (see <xref
@@ -72,7 +72,7 @@ available parameters, run <command>sysctl -a</command>.</para>
   <para>When developing kernel modules it's often convenient to run
   edit-compile-run loop as quickly as possible.
 
-  See below snippet as an example of developing <literal>mellanix</literal>
+  See below snippet as an example of developing <literal>mellanox</literal>
   drivers.
   </para>
 
@@ -82,7 +82,7 @@ $ nix-shell '<nixpkgs>' -A linuxPackages.kernel
 $ unpackPhase
 $ cd linux-*
 $ make -C $dev/lib/modules/*/build M=$(pwd)/drivers/net/ethernet/mellanox modules
-$ sudo insmod ./drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko
+# insmod ./drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko
 ]]></screen>
 
 </section>
diff --git a/nixos/doc/manual/configuration/luks-file-systems.xml b/nixos/doc/manual/configuration/luks-file-systems.xml
index 45475dbcd446..2062456703f7 100644
--- a/nixos/doc/manual/configuration/luks-file-systems.xml
+++ b/nixos/doc/manual/configuration/luks-file-systems.xml
@@ -9,23 +9,23 @@
 <para>NixOS supports file systems that are encrypted using
 <emphasis>LUKS</emphasis> (Linux Unified Key Setup).  For example,
 here is how you create an encrypted Ext4 file system on the device
-<filename>/dev/sda2</filename>:
+<filename>/dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d</filename>:
 
 <screen>
-$ cryptsetup luksFormat /dev/sda2
+# cryptsetup luksFormat /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d
 
 WARNING!
 ========
-This will overwrite data on /dev/sda2 irrevocably.
+This will overwrite data on /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d irrevocably.
 
 Are you sure? (Type uppercase yes): YES
 Enter LUKS passphrase: ***
 Verify passphrase: ***
 
-$ cryptsetup luksOpen /dev/sda2 crypted
-Enter passphrase for /dev/sda2: ***
+# cryptsetup luksOpen /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d crypted
+Enter passphrase for /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d: ***
 
-$ mkfs.ext4 /dev/mapper/crypted
+# mkfs.ext4 /dev/mapper/crypted
 </screen>
 
 To ensure that this file system is automatically mounted at boot time
@@ -33,7 +33,7 @@ as <filename>/</filename>, add the following to
 <filename>configuration.nix</filename>:
 
 <programlisting>
-boot.initrd.luks.devices = [ { device = "/dev/sda2"; name = "crypted"; } ];
+boot.initrd.luks.devices.crypted.device = "/dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d";
 fileSystems."/".device = "/dev/mapper/crypted";
 </programlisting>
 
diff --git a/nixos/doc/manual/configuration/user-mgmt.xml b/nixos/doc/manual/configuration/user-mgmt.xml
index 631742059278..829e5b9ea842 100644
--- a/nixos/doc/manual/configuration/user-mgmt.xml
+++ b/nixos/doc/manual/configuration/user-mgmt.xml
@@ -63,14 +63,14 @@ commands such as <command>useradd</command>,
 account named <literal>alice</literal>:
 
 <screen>
-$ useradd -m alice</screen>
+# useradd -m alice</screen>
 
 To make all nix tools available to this new user use `su - USER` which 
 opens a login shell (==shell that loads the profile) for given user. 
 This will create the ~/.nix-defexpr symlink. So run:
 
 <screen>
-$ su - alice -c "true"</screen>
+# su - alice -c "true"</screen>
 
 
 The flag <option>-m</option> causes the creation of a home directory
@@ -79,7 +79,7 @@ have an initial password and therefore cannot log in.  A password can
 be set using the <command>passwd</command> utility:
 
 <screen>
-$ passwd alice
+# passwd alice
 Enter new UNIX password: ***
 Retype new UNIX password: ***
 </screen>
@@ -87,7 +87,7 @@ Retype new UNIX password: ***
 A user can be deleted using <command>userdel</command>:
 
 <screen>
-$ userdel -r alice</screen>
+# userdel -r alice</screen>
 
 The flag <option>-r</option> deletes the user’s home directory.
 Accounts can be modified using <command>usermod</command>.  Unix
diff --git a/nixos/doc/manual/configuration/wireless.xml b/nixos/doc/manual/configuration/wireless.xml
index e4560f2da36b..1868380dcbfa 100644
--- a/nixos/doc/manual/configuration/wireless.xml
+++ b/nixos/doc/manual/configuration/wireless.xml
@@ -41,13 +41,13 @@ If you are using WPA2 the <command>wpa_passphrase</command> tool might be useful
 to generate the <literal>wpa_supplicant.conf</literal>.
 
 <screen>
-$ wpa_passphrase ESSID PSK > /etc/wpa_supplicant.conf</screen>
+# wpa_passphrase ESSID PSK > /etc/wpa_supplicant.conf</screen>
 
 After you have edited the <literal>wpa_supplicant.conf</literal>,
 you need to restart the wpa_supplicant service.
 
 <screen>
-$ systemctl restart wpa_supplicant.service</screen>
+# systemctl restart wpa_supplicant.service</screen>
 </para>
 
 </section>
diff --git a/nixos/doc/manual/configuration/x-windows.xml b/nixos/doc/manual/configuration/x-windows.xml
index 7f43acab2c38..3040839861c1 100644
--- a/nixos/doc/manual/configuration/x-windows.xml
+++ b/nixos/doc/manual/configuration/x-windows.xml
@@ -5,7 +5,7 @@
          xml:id="sec-x11">
 
 <title>X Window System</title>
-    
+
 <para>The X Window System (X11) provides the basis of NixOS’ graphical
 user interface.  It can be enabled as follows:
 <programlisting>
@@ -48,7 +48,7 @@ services.xserver.autorun = false;
 </programlisting>
 The X server can then be started manually:
 <screen>
-$ systemctl start display-manager.service
+# systemctl start display-manager.service
 </screen>
 </para>
 
@@ -115,5 +115,14 @@ services.xserver.synaptics.twoFingerScroll = true;
 
 </simplesect>
 
+<simplesect><title>GTK/Qt themes</title>
+
+<para>GTK themes can be installed either to user profile or system-wide (via
+<literal>system.environmentPackages</literal>). To make Qt 5 applications look similar
+to GTK2 ones, you can install <literal>qt5.qtbase.gtk</literal> package into your
+system environment. It should work for all Qt 5 library versions.
+</para>
+
+</simplesect>
 
 </chapter>
diff --git a/nixos/doc/manual/development/building-nixos.xml b/nixos/doc/manual/development/building-nixos.xml
index 21c5bfe6a5b1..150fa1d7017e 100644
--- a/nixos/doc/manual/development/building-nixos.xml
+++ b/nixos/doc/manual/development/building-nixos.xml
@@ -25,8 +25,8 @@ $ nix-build -A config.system.build.isoImage -I nixos-config=modules/installer/cd
 suggested by the following command:
 
 <screen>
-$ mount -o loop -t iso9660 ./result/iso/cd.iso /mnt/iso</screen>
+# mount -o loop -t iso9660 ./result/iso/cd.iso /mnt/iso</screen>
 
 </para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/nixos/doc/manual/development/building-parts.xml b/nixos/doc/manual/development/building-parts.xml
index cb8dee039c8e..09a40114f02e 100644
--- a/nixos/doc/manual/development/building-parts.xml
+++ b/nixos/doc/manual/development/building-parts.xml
@@ -94,8 +94,8 @@ $ nix-build -A 'config.systemd.units."httpd.service".unit'
 <screen>
 $ cp $(nix-build -A 'config.systemd.units."httpd.service".unit')/httpd.service \
     /run/systemd/system/tmp-httpd.service
-$ systemctl daemon-reload
-$ systemctl start tmp-httpd.service
+# systemctl daemon-reload
+# systemctl start tmp-httpd.service
 </screen>
 
       Note that the unit must not have the same name as any unit in
@@ -110,4 +110,4 @@ $ systemctl start tmp-httpd.service
 
 </para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/nixos/doc/manual/development/option-declarations.xml b/nixos/doc/manual/development/option-declarations.xml
index ea5d1241876e..b0689aa1d97f 100644
--- a/nixos/doc/manual/development/option-declarations.xml
+++ b/nixos/doc/manual/development/option-declarations.xml
@@ -7,8 +7,8 @@
 <title>Option Declarations</title>
 
 <para>An option declaration specifies the name, type and description
-of a NixOS configuration option.  It is illegal to define an option
-that hasn’t been declared in any module.  A option declaration
+of a NixOS configuration option.  It is invalid to define an option
+that hasn’t been declared in any module.  An option declaration
 generally looks like this:
 
 <programlisting>
@@ -42,7 +42,7 @@ options = {
     <listitem>
       <para>The default value used if no value is defined by any
       module.  A default is not required; in that case, if the option
-      value is ever used, an error will be thrown.</para>
+      value is never used, an error will be thrown.</para>
     </listitem>
   </varlistentry>
 
diff --git a/nixos/doc/manual/development/sources.xml b/nixos/doc/manual/development/sources.xml
index fd0b0109b322..7cd5ce0002c2 100644
--- a/nixos/doc/manual/development/sources.xml
+++ b/nixos/doc/manual/development/sources.xml
@@ -70,7 +70,7 @@ sources, you need to tell <command>nixos-rebuild</command> about them
 using the <option>-I</option> flag:
 
 <screen>
-$ nixos-rebuild switch -I nixpkgs=<replaceable>/my/sources</replaceable>/nixpkgs
+# nixos-rebuild switch -I nixpkgs=<replaceable>/my/sources</replaceable>/nixpkgs
 </screen>
 
 </para>
diff --git a/nixos/doc/manual/development/testing-installer.xml b/nixos/doc/manual/development/testing-installer.xml
index 87e40e326171..20c8d51815ad 100644
--- a/nixos/doc/manual/development/testing-installer.xml
+++ b/nixos/doc/manual/development/testing-installer.xml
@@ -12,16 +12,16 @@ properly:
 
 <screen>
 $ nix-build -A config.system.build.nixos-install
-$ mount -t tmpfs none /mnt
-$ ./result/bin/nixos-install</screen>
+# mount -t tmpfs none /mnt
+# ./result/bin/nixos-install</screen>
 
 To start a login shell in the new NixOS installation in
 <filename>/mnt</filename>:
 
 <screen>
-$ ./result/bin/nixos-install --chroot
+# ./result/bin/nixos-install --chroot
 </screen>
 
 </para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/nixos/doc/manual/installation/changing-config.xml b/nixos/doc/manual/installation/changing-config.xml
index aa31742434e4..43b591a1cae9 100644
--- a/nixos/doc/manual/installation/changing-config.xml
+++ b/nixos/doc/manual/installation/changing-config.xml
@@ -10,7 +10,7 @@ contains the current configuration of your machine.  Whenever you’ve
 changed something to that file, you should do
 
 <screen>
-$ nixos-rebuild switch</screen>
+# nixos-rebuild switch</screen>
 
 to build the new configuration, make it the default configuration for
 booting, and try to realise the configuration in the running system
@@ -23,7 +23,7 @@ either run them from a root shell or by prefixing them with
 <para>You can also do
 
 <screen>
-$ nixos-rebuild test</screen>
+# nixos-rebuild test</screen>
 
 to build the configuration and switch the running system to it, but
 without making it the boot default.  So if (say) the configuration
@@ -33,7 +33,7 @@ configuration.</para>
 <para>There is also
 
 <screen>
-$ nixos-rebuild boot</screen>
+# nixos-rebuild boot</screen>
 
 to build the configuration and make it the boot default, but not
 switch to it now (so it will only take effect after the next
@@ -44,7 +44,7 @@ of the GRUB 2 boot screen by giving it a different <emphasis>profile
 name</emphasis>, e.g.
 
 <screen>
-$ nixos-rebuild switch -p test </screen>
+# nixos-rebuild switch -p test </screen>
 
 which causes the new configuration (and previous ones created using
 <literal>-p test</literal>) to show up in the GRUB submenu “NixOS -
diff --git a/nixos/doc/manual/installation/installing-uefi.xml b/nixos/doc/manual/installation/installing-uefi.xml
index 90d18695447c..927648febc50 100644
--- a/nixos/doc/manual/installation/installing-uefi.xml
+++ b/nixos/doc/manual/installation/installing-uefi.xml
@@ -5,7 +5,7 @@
          xml:id="sec-uefi-installation">
 
 <title>UEFI Installation</title>
-    
+
 <para>NixOS can also be installed on UEFI systems.  The procedure
 is by and large the same as a BIOS installation, with the following
 changes:
@@ -26,7 +26,7 @@ changes:
     <literal>vfat</literal> filesystem.</para>
   </listitem>
   <listitem>
-    <para>You must set <option>boot.loader.gummiboot.enable</option> to
+    <para>You must set <option>boot.loader.systemd-boot.enable</option> to
     <literal>true</literal>. <command>nixos-generate-config</command>
     should do this automatically for new configurations when booted in
     UEFI mode.</para>
@@ -38,7 +38,7 @@ changes:
   </listitem>
   <listitem>
     <para>You may want to look at the options starting with
-    <option>boot.loader.efi</option> and <option>boot.loader.gummiboot</option>
+    <option>boot.loader.efi</option> and <option>boot.loader.systemd-boot</option>
     as well.</para>
   </listitem>
 </itemizedlist>
diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml
index 3e53062c3e84..2f118d27b1a5 100644
--- a/nixos/doc/manual/installation/installing.xml
+++ b/nixos/doc/manual/installation/installing.xml
@@ -54,7 +54,7 @@
     changes.  For example:
 
 <screen>
-$ mkfs.ext4 -L nixos /dev/sda1</screen>
+# mkfs.ext4 -L nixos /dev/sda1</screen>
 
     </para></listitem>
 
@@ -66,10 +66,10 @@ $ mkfs.ext4 -L nixos /dev/sda1</screen>
     <listitem><para>For creating LVM volumes, the LVM commands, e.g.,
 
 <screen>
-$ pvcreate /dev/sda1 /dev/sdb1
-$ vgcreate MyVolGroup /dev/sda1 /dev/sdb1
-$ lvcreate --size 2G --name bigdisk MyVolGroup
-$ lvcreate --size 1G --name smalldisk MyVolGroup</screen>
+# pvcreate /dev/sda1 /dev/sdb1
+# vgcreate MyVolGroup /dev/sda1 /dev/sdb1
+# lvcreate --size 2G --name bigdisk MyVolGroup
+# lvcreate --size 1G --name smalldisk MyVolGroup</screen>
 
     </para></listitem>
 
@@ -84,7 +84,7 @@ $ lvcreate --size 1G --name smalldisk MyVolGroup</screen>
   be installed on <filename>/mnt</filename>, e.g.
 
 <screen>
-$ mount /dev/disk/by-label/nixos /mnt
+# mount /dev/disk/by-label/nixos /mnt
 </screen>
 
   </para></listitem>
@@ -113,14 +113,14 @@ $ mount /dev/disk/by-label/nixos /mnt
     generate an initial configuration file for you:
 
 <screen>
-$ nixos-generate-config --root /mnt</screen>
+# nixos-generate-config --root /mnt</screen>
 
     You should then edit
     <filename>/mnt/etc/nixos/configuration.nix</filename> to suit your
     needs:
 
 <screen>
-$ nano /mnt/etc/nixos/configuration.nix
+# nano /mnt/etc/nixos/configuration.nix
 </screen>
 
     If you’re using the graphical ISO image, other editors may be
@@ -162,7 +162,7 @@ $ nano /mnt/etc/nixos/configuration.nix
   <listitem><para>Do the installation:
 
 <screen>
-$ nixos-install</screen>
+# nixos-install</screen>
 
     Cross fingers.  If this fails due to a temporary problem (such as
     a network issue while downloading binaries from the NixOS binary
@@ -186,7 +186,7 @@ Retype new UNIX password: ***
   <listitem><para>If everything went well:
 
 <screen>
-$ reboot</screen>
+# reboot</screen>
 
   </para></listitem>
 
@@ -235,15 +235,15 @@ drive (here <filename>/dev/sda</filename>).  <xref linkend="ex-config"
 
 <example xml:id='ex-install-sequence'><title>Commands for Installing NixOS on <filename>/dev/sda</filename></title>
 <screen>
-$ fdisk /dev/sda # <lineannotation>(or whatever device you want to install on)</lineannotation>
-$ mkfs.ext4 -L nixos /dev/sda1
-$ mkswap -L swap /dev/sda2
-$ swapon /dev/sda2
-$ mount /dev/disk/by-label/nixos /mnt
-$ nixos-generate-config --root /mnt
-$ nano /mnt/etc/nixos/configuration.nix
-$ nixos-install
-$ reboot</screen>
+# fdisk /dev/sda # <lineannotation>(or whatever device you want to install on)</lineannotation>
+# mkfs.ext4 -L nixos /dev/sda1
+# mkswap -L swap /dev/sda2
+# swapon /dev/sda2
+# mount /dev/disk/by-label/nixos /mnt
+# nixos-generate-config --root /mnt
+# nano /mnt/etc/nixos/configuration.nix
+# nixos-install
+# reboot</screen>
 </example>
 
 <example xml:id='ex-config'><title>NixOS Configuration</title>
diff --git a/nixos/doc/manual/installation/upgrading.xml b/nixos/doc/manual/installation/upgrading.xml
index c4812cc637c3..65d395b0c88e 100644
--- a/nixos/doc/manual/installation/upgrading.xml
+++ b/nixos/doc/manual/installation/upgrading.xml
@@ -60,33 +60,33 @@ the <literal>nixos-14.12</literal> channel.  To see which NixOS
 channel you’re subscribed to, run the following as root:
 
 <screen>
-$ nix-channel --list | grep nixos
+# nix-channel --list | grep nixos
 nixos https://nixos.org/channels/nixos-unstable
 </screen>
 
 To switch to a different NixOS channel, do
 
 <screen>
-$ nix-channel --add https://nixos.org/channels/<replaceable>channel-name</replaceable> nixos
+# nix-channel --add https://nixos.org/channels/<replaceable>channel-name</replaceable> nixos
 </screen>
 
 (Be sure to include the <literal>nixos</literal> parameter at the
 end.)  For instance, to use the NixOS 14.12 stable channel:
 
 <screen>
-$ nix-channel --add https://nixos.org/channels/nixos-14.12 nixos
+# nix-channel --add https://nixos.org/channels/nixos-14.12 nixos
 </screen>
 
 If you have a server, you may want to use the “small” channel instead:
 
 <screen>
-$ nix-channel --add https://nixos.org/channels/nixos-14.12-small nixos
+# nix-channel --add https://nixos.org/channels/nixos-14.12-small nixos
 </screen>
 
 And if you want to live on the bleeding edge:
 
 <screen>
-$ nix-channel --add https://nixos.org/channels/nixos-unstable nixos
+# nix-channel --add https://nixos.org/channels/nixos-unstable nixos
 </screen>
 
 </para>
@@ -95,7 +95,7 @@ $ nix-channel --add https://nixos.org/channels/nixos-unstable nixos
 channel by running
 
 <screen>
-$ nixos-rebuild switch --upgrade
+# nixos-rebuild switch --upgrade
 </screen>
 
 which is equivalent to the more verbose <literal>nix-channel --update
diff --git a/nixos/doc/manual/man-configuration.xml b/nixos/doc/manual/man-configuration.xml
index d49369d2c584..05531b3909a3 100644
--- a/nixos/doc/manual/man-configuration.xml
+++ b/nixos/doc/manual/man-configuration.xml
@@ -1,7 +1,7 @@
 <refentry xmlns="http://docbook.org/ns/docbook"
           xmlns:xlink="http://www.w3.org/1999/xlink"
           xmlns:xi="http://www.w3.org/2001/XInclude">
-  
+
 <refmeta>
   <refentrytitle><filename>configuration.nix</filename></refentrytitle>
   <manvolnum>5</manvolnum>
@@ -34,5 +34,5 @@ therein.</para>
 <xi:include href="options-db.xml" />
 
 </refsection>
-  
+
 </refentry>
diff --git a/nixos/doc/manual/man-nixos-build-vms.xml b/nixos/doc/manual/man-nixos-build-vms.xml
index f37677629d0c..878ebee05273 100644
--- a/nixos/doc/manual/man-nixos-build-vms.xml
+++ b/nixos/doc/manual/man-nixos-build-vms.xml
@@ -1,7 +1,7 @@
 <refentry xmlns="http://docbook.org/ns/docbook"
           xmlns:xlink="http://www.w3.org/1999/xlink"
           xmlns:xi="http://www.w3.org/2001/XInclude">
-  
+
 <refmeta>
   <refentrytitle><command>nixos-build-vms</command></refentrytitle>
   <manvolnum>8</manvolnum>
@@ -42,10 +42,10 @@ points to the generated virtual network.
       services.openssh.enable = true;
       nixpkgs.system = "i686-linux";
       deployment.targetHost = "test1.example.net";
-      
+
       # Other NixOS options
     };
-    
+
   test2 = {pkgs, config, ...}:
     {
       services.openssh.enable = true;
@@ -53,7 +53,7 @@ points to the generated virtual network.
       environment.systemPackages = [ pkgs.lynx ];
       nixpkgs.system = "x86_64-linux";
       deployment.targetHost = "test2.example.net";
-      
+
       # Other NixOS options
     };
 }
diff --git a/nixos/doc/manual/man-nixos-generate-config.xml b/nixos/doc/manual/man-nixos-generate-config.xml
index 140642bc9c9c..993a932ddfbe 100644
--- a/nixos/doc/manual/man-nixos-generate-config.xml
+++ b/nixos/doc/manual/man-nixos-generate-config.xml
@@ -113,8 +113,8 @@
   <varlistentry>
     <term><option>--no-filesystems</option></term>
     <listitem>
-      <para>Omit everything concerning file system information
-      (which includes swap devices) from the hardware configuration.</para>
+      <para>Omit everything concerning file systems and swap devices
+      from the hardware configuration.</para>
     </listitem>
   </varlistentry>
 
diff --git a/nixos/doc/manual/man-nixos-option.xml b/nixos/doc/manual/man-nixos-option.xml
index 2875336c67e5..6be8bc780f13 100644
--- a/nixos/doc/manual/man-nixos-option.xml
+++ b/nixos/doc/manual/man-nixos-option.xml
@@ -1,7 +1,7 @@
 <refentry xmlns="http://docbook.org/ns/docbook"
           xmlns:xlink="http://www.w3.org/1999/xlink"
           xmlns:xi="http://www.w3.org/2001/XInclude">
-  
+
 <refmeta>
   <refentrytitle><command>nixos-option</command></refentrytitle>
   <manvolnum>8</manvolnum>
@@ -64,7 +64,7 @@ $ nixos-option boot.loader.grub.enable
 Value:
 true
 
-Default: 
+Default:
 true
 
 Description:
diff --git a/nixos/doc/manual/manual.xml b/nixos/doc/manual/manual.xml
index 736d1d4eff71..2c28dd448016 100644
--- a/nixos/doc/manual/manual.xml
+++ b/nixos/doc/manual/manual.xml
@@ -3,7 +3,7 @@
       xmlns:xi="http://www.w3.org/2001/XInclude"
       version="5.0"
       xml:id="book-nixos-manual">
-  
+
   <info>
     <title>NixOS Manual</title>
     <subtitle>Version <xi:include href="version" parse="text" /></subtitle>
@@ -26,6 +26,9 @@
     xlink:href="https://github.com/NixOS/nixpkgs/issues">NixOS’ GitHub
     issue tracker</link>.</para>
 
+    <note><para>Commands prefixed with <literal>#</literal> have to be run as
+    root, either requiring to login as root user or temporarily switching
+    to it using <literal>sudo</literal> for example.</para></note>
   </preface>
 
   <xi:include href="installation/installation.xml" />
diff --git a/nixos/doc/manual/options-to-docbook.xsl b/nixos/doc/manual/options-to-docbook.xsl
index cd30ae36ae59..5387546b5982 100644
--- a/nixos/doc/manual/options-to-docbook.xsl
+++ b/nixos/doc/manual/options-to-docbook.xsl
@@ -11,6 +11,7 @@
   <xsl:output method='xml' encoding="UTF-8" />
 
   <xsl:param name="revision" />
+  <xsl:param name="program" />
 
 
   <xsl:template match="/expr/list">
@@ -188,7 +189,7 @@
                 </xsl:otherwise>
               </xsl:choose>
             </xsl:when>
-            <xsl:when test="$revision != 'local' and contains(@value, 'nixops') and contains(@value, '/nix/')">
+            <xsl:when test="$revision != 'local' and $program = 'nixops' and contains(@value, '/nix/')">
               <xsl:attribute name="xlink:href">https://github.com/NixOS/nixops/blob/<xsl:value-of select="$revision"/>/nix/<xsl:value-of select="substring-after(@value, '/nix/')"/></xsl:attribute>
             </xsl:when>
             <xsl:otherwise>
diff --git a/nixos/doc/manual/release-notes/rl-1603.xml b/nixos/doc/manual/release-notes/rl-1603.xml
index 620c3e362a65..c51316bd2808 100644
--- a/nixos/doc/manual/release-notes/rl-1603.xml
+++ b/nixos/doc/manual/release-notes/rl-1603.xml
@@ -279,7 +279,7 @@ fileSystems."/example" = {
 
   <listitem>
     <para><literal>services.xserver.vaapiDrivers</literal> has been removed. Use
-    <literal>services.hardware.opengl.extraPackages{,32}</literal> instead. You can
+    <literal>hardware.opengl.extraPackages{,32}</literal> instead. You can
     also specify VDPAU drivers there.</para>
   </listitem>
 
diff --git a/nixos/doc/manual/release-notes/rl-1609.xml b/nixos/doc/manual/release-notes/rl-1609.xml
index 22dea8029242..be175a54c232 100644
--- a/nixos/doc/manual/release-notes/rl-1609.xml
+++ b/nixos/doc/manual/release-notes/rl-1609.xml
@@ -16,6 +16,10 @@ has the following highlights: </para>
     See <xref linkend="sec-booting-from-pxe" /> for documentation.</para>
   </listitem>
 
+  <listitem>
+    <para>Xorg-server-1.18.*. If you choose <literal>"ati_unfree"</literal> driver,
+    1.17.* is still used due to ABI incompatibility.</para>
+  </listitem>
 </itemizedlist>
 
 <para>The following new services were added since the last release:</para>
@@ -30,7 +34,10 @@ following incompatible changes:</para>
 
 <itemizedlist>
   <listitem>
-    <para>todo</para>
+    <para>Shell aliases for systemd sub-commands
+    <link xlink:href="https://github.com/NixOS/nixpkgs/pull/15598">were dropped</link>:
+    <command>start</command>, <command>stop</command>,
+    <command>restart</command>, <command>status</command>.</para>
   </listitem>
 </itemizedlist>
 
diff --git a/nixos/lib/test-driver/Logger.pm b/nixos/lib/test-driver/Logger.pm
index 6e62fdfd7708..3fe5ef67c144 100644
--- a/nixos/lib/test-driver/Logger.pm
+++ b/nixos/lib/test-driver/Logger.pm
@@ -3,6 +3,7 @@ package Logger;
 use strict;
 use Thread::Queue;
 use XML::Writer;
+use Encode qw(decode encode);
 
 sub new {
     my ($class) = @_;
@@ -56,7 +57,8 @@ sub nest {
 sub sanitise {
     my ($s) = @_;
     $s =~ s/[[:cntrl:]\xff]//g;
-    return $s;
+    $s = decode('UTF-8', $s, Encode::FB_DEFAULT);
+    return encode('UTF-8', $s, Encode::FB_CROAK);
 }
 
 sub log {
diff --git a/nixos/lib/test-driver/Machine.pm b/nixos/lib/test-driver/Machine.pm
index 37d6518fd8d7..1a243918c22f 100644
--- a/nixos/lib/test-driver/Machine.pm
+++ b/nixos/lib/test-driver/Machine.pm
@@ -382,9 +382,17 @@ sub waitForUnit {
             my $state = $info->{ActiveState};
             die "unit ‘$unit’ reached state ‘$state’\n" if $state eq "failed";
             if ($state eq "inactive") {
+                # If there are no pending jobs, then assume this unit
+                # will never reach active state.
                 my ($status, $jobs) = $self->execute("systemctl list-jobs --full 2>&1");
-                die "unit ‘$unit’ is inactive and there are no pending jobs\n"
-                    if $jobs =~ /No jobs/; # FIXME: fragile
+                if ($jobs =~ /No jobs/) {  # FIXME: fragile
+                    # Handle the case where the unit may have started
+                    # between the previous getUnitInfo() and
+                    # list-jobs.
+                    my $info2 = $self->getUnitInfo($unit);
+                    die "unit ‘$unit’ is inactive and there are no pending jobs\n"
+                        if $info2->{ActiveState} eq $state;
+                }
             }
             return 1 if $state eq "active";
         };
diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix
index f7159634e4f1..5f463c092846 100644
--- a/nixos/lib/testing.nix
+++ b/nixos/lib/testing.nix
@@ -113,14 +113,14 @@ rec {
             --add-flags "$vms" \
             ${lib.optionalString enableOCR "--prefix PATH : '${ocrProg}/bin'"} \
             --run "testScript=\"\$(cat $out/test-script)\"" \
-            --set testScript '"$testScript"' \
-            --set VLANS '"${toString vlans}"'
+            --set testScript '$testScript' \
+            --set VLANS '${toString vlans}'
           ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
           wrapProgram $out/bin/nixos-run-vms \
             --add-flags "$vms" \
             ${lib.optionalString enableOCR "--prefix PATH : '${ocrProg}/bin'"} \
-            --set tests '"startAll; joinAll;"' \
-            --set VLANS '"${toString vlans}"' \
+            --set tests 'startAll; joinAll;' \
+            --set VLANS '${toString vlans}' \
             ${lib.optionalString (builtins.length vms == 1) "--set USE_SERIAL 1"}
         ''; # "
 
diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix
index 7b8be2050c13..871fbb121d03 100644
--- a/nixos/lib/utils.nix
+++ b/nixos/lib/utils.nix
@@ -8,4 +8,10 @@ rec {
    replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"]
     (if hasPrefix "/" s then substring 1 (stringLength s) s else s);
 
+  # Returns a system path for a given shell package
+  toShellPath = shell:
+    if types.shellPackage.check shell then
+      "/run/current-system/sw${shell.shellPath}"
+    else
+      shell;
 }
diff --git a/nixos/modules/config/fonts/fontdir.nix b/nixos/modules/config/fonts/fontdir.nix
index c78b52fe29e1..180e38f81f4f 100644
--- a/nixos/modules/config/fonts/fontdir.nix
+++ b/nixos/modules/config/fonts/fontdir.nix
@@ -4,47 +4,17 @@ with lib;
 
 let
 
-  fontDirs = config.fonts.fonts;
-
-  localDefs = with pkgs.builderDefs; pkgs.builderDefs.passthru.function rec {
-    src = "";/* put a fetchurl here */
-    buildInputs = [pkgs.xorg.mkfontdir pkgs.xorg.mkfontscale];
-    inherit fontDirs;
-    installPhase = fullDepEntry ("
-    list='';
-    for i in ${toString fontDirs} ; do
-      if [ -d \$i/ ]; then
-        list=\"\$list \$i\";
-      fi;
-    done
-    list=\$(find \$list -name fonts.dir -o -name '*.ttf' -o -name '*.otf');
-    fontDirs='';
-    for i in \$list ; do
-      fontDirs=\"\$fontDirs \$(dirname \$i)\";
-    done;
-    mkdir -p \$out/share/X11-fonts/;
-    find \$fontDirs -type f -o -type l | while read i; do
-      j=\"\${i##*/}\"
-      if ! test -e \"\$out/share/X11-fonts/\${j}\"; then
-        ln -s \"\$i\" \"\$out/share/X11-fonts/\${j}\";
-      fi;
-    done;
-    cd \$out/share/X11-fonts/
-    rm fonts.dir
-    rm fonts.scale
-    rm fonts.alias
-    mkfontdir
-    mkfontscale
-    cat \$( find ${pkgs.xorg.fontalias}/ -name fonts.alias) >fonts.alias
-  ") ["minInit" "addInputs"];
-  };
-
-  x11Fonts = with localDefs; stdenv.mkDerivation rec {
-    name = "X11-fonts";
-    builder = writeScript (name + "-builder")
-      (textClosure localDefs
-        [installPhase doForceShare doPropagate]);
-  };
+  x11Fonts = pkgs.runCommand "X11-fonts" { } ''
+    mkdir -p "$out/share/X11-fonts"
+    find ${toString config.fonts.fonts} \
+      \( -name fonts.dir -o -name '*.ttf' -o -name '*.otf' \) \
+      -exec ln -sf -t "$out/share/X11-fonts" '{}' \;
+    cd "$out/share/X11-fonts"
+    rm -f fonts.dir fonts.scale fonts.alias
+    ${pkgs.xorg.mkfontdir}/bin/mkfontdir
+    ${pkgs.xorg.mkfontscale}/bin/mkfontscale
+    cat $(find ${pkgs.xorg.fontalias}/ -name fonts.alias) >fonts.alias
+  '';
 
 in
 
@@ -70,6 +40,8 @@ in
 
     environment.systemPackages = [ x11Fonts ];
 
+    environment.pathsToLink = [ "/share/X11-fonts" ];
+
   };
 
 }
diff --git a/nixos/modules/config/ldap.nix b/nixos/modules/config/ldap.nix
index a6657768e061..7064ef64b4c8 100644
--- a/nixos/modules/config/ldap.nix
+++ b/nixos/modules/config/ldap.nix
@@ -192,7 +192,7 @@ in
     system.activationScripts = mkIf insertLdapPassword {
       ldap = stringAfter [ "etc" "groups" "users" ] ''
         if test -f "${cfg.bind.password}" ; then
-          echo "bindpw "$(cat ${cfg.bind.password})"" | cat ${ldapConfig} - > /etc/ldap.conf.bindpw
+          echo "bindpw "$(cat ${cfg.bind.password})"" | cat ${ldapConfig.source} - > /etc/ldap.conf.bindpw
           mv -fT /etc/ldap.conf.bindpw /etc/ldap.conf
           chmod 600 /etc/ldap.conf
         fi
diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix
index 0c4f4cbfa5c6..8a2e630a917a 100644
--- a/nixos/modules/config/networking.nix
+++ b/nixos/modules/config/networking.nix
@@ -11,6 +11,9 @@ let
                    config.services.dnsmasq.resolveLocalQueries;
   hasLocalResolver = config.services.bind.enable || dnsmasqResolve;
 
+  resolvconfOptions = cfg.resolvconfOptions
+    ++ optional cfg.dnsSingleRequest "single-request"
+    ++ optional cfg.dnsExtensionMechanism "ends0";
 in
 
 {
@@ -59,6 +62,14 @@ in
       '';
     };
 
+    networking.resolvconfOptions = lib.mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = [ "ndots:1" "rotate" ];
+      description = ''
+        Set the options in <filename>/etc/resolv.conf</filename>.
+      '';
+    };
 
     networking.proxy = {
 
@@ -171,12 +182,9 @@ in
               # Invalidate the nscd cache whenever resolv.conf is
               # regenerated.
               libc_restart='${pkgs.systemd}/bin/systemctl try-restart --no-block nscd.service 2> /dev/null'
-            '' + optionalString cfg.dnsSingleRequest ''
-              # only send one DNS request at a time
-              resolv_conf_options+=' single-request'
-            '' + optionalString cfg.dnsExtensionMechanism ''
-              # enable extension mechanisms for DNS
-              resolv_conf_options+=' edns0'
+            '' + optionalString (length resolvconfOptions > 0) ''
+              # Options as described in resolv.conf(5)
+              resolv_conf_options='${concatStringsSep " " resolvconfOptions}'
             '' + optionalString hasLocalResolver ''
               # This hosts runs a full-blown DNS resolver.
               name_servers='127.0.0.1'
diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix
index 89b8a04b5e7c..f458bc39adaa 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -1,7 +1,7 @@
 # This module defines a global environment configuration and
 # a common configuration for all shells.
 
-{ config, lib, pkgs, ... }:
+{ config, lib, utils, pkgs, ... }:
 
 with lib;
 
@@ -135,13 +135,13 @@ in
 
     environment.shells = mkOption {
       default = [];
-      example = [ "/run/current-system/sw/bin/zsh" ];
+      example = literalExample "[ pkgs.bashInteractive pkgs.zsh ]";
       description = ''
         A list of permissible login shells for user accounts.
         No need to mention <literal>/bin/sh</literal>
         here, it is placed into this list implicitly.
       '';
-      type = types.listOf types.path;
+      type = types.listOf (types.either types.shellPackage types.path);
     };
 
   };
@@ -150,10 +150,6 @@ in
 
     system.build.binsh = pkgs.bashInteractive;
 
-    # Ensure TERMINFO is set appropriately *before* user shells are run,
-    # as they may depend on it
-    environment.sessionVariables.TERMINFO = "/run/current-system/sw/share/terminfo";
-
     # Set session variables in the shell as well. This is usually
     # unnecessary, but it allows changes to session variables to take
     # effect without restarting the session (e.g. by opening a new
@@ -162,7 +158,7 @@ in
 
     environment.etc."shells".text =
       ''
-        ${concatStringsSep "\n" cfg.shells}
+        ${concatStringsSep "\n" (map utils.toShellPath cfg.shells)}
         /bin/sh
       '';
 
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index e643b2d059b5..277a4264137b 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -1,9 +1,8 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, utils, pkgs, ... }:
 
 with lib;
 
 let
-
   ids = config.ids;
   cfg = config.users;
 
@@ -103,7 +102,7 @@ let
       };
 
       home = mkOption {
-        type = types.str;
+        type = types.path;
         default = "/var/empty";
         description = "The user's home directory.";
       };
@@ -118,8 +117,10 @@ let
       };
 
       shell = mkOption {
-        type = types.str;
-        default = "/run/current-system/sw/bin/nologin";
+        type = types.either types.shellPackage types.path;
+        default = pkgs.nologin;
+        defaultText = "pkgs.nologin";
+        example = literalExample "pkgs.bashInteractive";
         description = "The path to the user's shell.";
       };
 
@@ -359,11 +360,12 @@ let
 
   spec = pkgs.writeText "users-groups.json" (builtins.toJSON {
     inherit (cfg) mutableUsers;
-    users = mapAttrsToList (n: u:
+    users = mapAttrsToList (_: u:
       { inherit (u)
-          name uid group description home shell createHome isSystemUser
+          name uid group description home createHome isSystemUser
           password passwordFile hashedPassword
           initialPassword initialHashedPassword;
+        shell = utils.toShellPath u.shell;
       }) cfg.users;
     groups = mapAttrsToList (n: g:
       { inherit (g) name gid;
@@ -373,6 +375,12 @@ let
       }) cfg.groups;
   });
 
+  systemShells =
+    let
+      shells = mapAttrsToList (_: u: u.shell) cfg.users;
+    in
+      filter types.shellPackage.check shells;
+
 in {
 
   ###### interface
@@ -468,7 +476,6 @@ in {
         home = "/root";
         shell = mkDefault cfg.defaultUserShell;
         group = "root";
-        extraGroups = [ "grsecurity" ];
         initialHashedPassword = mkDefault config.security.initialRootPassword;
       };
       nobody = {
@@ -478,6 +485,9 @@ in {
       };
     };
 
+    # Install all the user shells
+    environment.systemPackages = systemShells;
+
     users.groups = {
       root.gid = ids.gids.root;
       wheel.gid = ids.gids.wheel;
@@ -497,7 +507,6 @@ in {
       nixbld.gid = ids.gids.nixbld;
       utmp.gid = ids.gids.utmp;
       adm.gid = ids.gids.adm;
-      grsecurity.gid = ids.gids.grsecurity;
       input.gid = ids.gids.input;
     };
 
diff --git a/nixos/modules/hardware/video/ati.nix b/nixos/modules/hardware/video/ati.nix
index 033e49d2233e..bf91bcf0776b 100644
--- a/nixos/modules/hardware/video/ati.nix
+++ b/nixos/modules/hardware/video/ati.nix
@@ -18,6 +18,8 @@ in
 
   config = mkIf enabled {
 
+    nixpkgs.config.xorg.fglrxCompat = true;
+
     services.xserver.drivers = singleton
       { name = "fglrx"; modules = [ ati_x11 ]; libPath = [ "${ati_x11}/lib" ]; };
 
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index c31ded977e68..4fc8bf5428f8 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -64,7 +64,7 @@ let
   # The EFI boot image.
   efiDir = pkgs.runCommand "efi-directory" {} ''
     mkdir -p $out/EFI/boot
-    cp -v ${pkgs.gummiboot}/lib/gummiboot/gummiboot${targetArch}.efi $out/EFI/boot/boot${targetArch}.efi
+    cp -v ${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${targetArch}.efi $out/EFI/boot/boot${targetArch}.efi
     mkdir -p $out/loader/entries
 
     echo "title NixOS Live CD" > $out/loader/entries/nixos-livecd.conf
@@ -79,7 +79,7 @@ let
     echo "options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset" >> $out/loader/entries/nixos-livecd-nomodeset.conf
 
     echo "default nixos-livecd" > $out/loader/loader.conf
-    echo "timeout ${builtins.toString config.boot.loader.gummiboot.timeout}" >> $out/loader/loader.conf
+    echo "timeout ${builtins.toString config.boot.loader.timeout}" >> $out/loader/loader.conf
   '';
 
   efiImg = pkgs.runCommand "efi-image_eltorito" { buildInputs = [ pkgs.mtools pkgs.libfaketime ]; }
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index 8e75f8d3c40a..5e576367eb2f 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -1,5 +1,6 @@
 #! @perl@
 
+use strict;
 use Cwd 'abs_path';
 use File::Spec;
 use File::Path;
@@ -69,6 +70,7 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
 my @attrs = ();
 my @kernelModules = ();
 my @initrdKernelModules = ();
+my @initrdAvailableKernelModules = ();
 my @modulePackages = ();
 my @imports;
 
@@ -379,7 +381,7 @@ EOF
     # Is this a btrfs filesystem?
     if ($fsType eq "btrfs") {
         my ($status, @id_info) = runCommand("btrfs subvol show $rootDir$mountPoint");
-        if ($status != 0 || join("", @msg) =~ /ERROR:/) {
+        if ($status != 0 || join("", @id_info) =~ /ERROR:/) {
             die "Failed to retrieve subvolume info for $mountPoint\n";
         }
         my @ids = join("", @id_info) =~ m/Subvolume ID:[ \t\n]*([^ \t\n]*)/;
@@ -408,7 +410,7 @@ EOF
 EOF
 
     if (scalar @extraOptions > 0) {
-      $fileSystems .= <<EOF;
+        $fileSystems .= <<EOF;
       options = \[ ${\join " ", map { "\"" . $_ . "\"" } uniq(@extraOptions)} \];
 EOF
     }
@@ -417,6 +419,25 @@ EOF
     };
 
 EOF
+
+    # If this filesystem is on a LUKS device, then add a
+    # boot.initrd.luks.devices entry.
+    if (-e $device) {
+        my $deviceName = basename(abs_path($device));
+        if (-e "/sys/class/block/$deviceName"
+            && read_file("/sys/class/block/$deviceName/dm/uuid",  err_mode => 'quiet') =~ /^CRYPT-LUKS/)
+        {
+            my @slaves = glob("/sys/class/block/$deviceName/slaves/*");
+            if (scalar @slaves == 1) {
+                my $slave = "/dev/" . basename($slaves[0]);
+                if (-e $slave) {
+                    my $dmName = read_file("/sys/class/block/$deviceName/dm/name");
+                    chomp $dmName;
+                    $fileSystems .= "  boot.initrd.luks.devices.\"$dmName\".device = \"${\(findStableDevPath $slave)}\";\n\n";
+                }
+            }
+        }
+    }
 }
 
 
@@ -440,7 +461,7 @@ sub toNixList {
 sub multiLineList {
     my $indent = shift;
     return " [ ]" if !@_;
-    $res = "\n${indent}[ ";
+    my $res = "\n${indent}[ ";
     my $first = 1;
     foreach my $s (@_) {
         $res .= "$indent  " if !$first;
@@ -457,7 +478,7 @@ my $modulePackages = toNixList(uniq @modulePackages);
 
 my $fsAndSwap = "";
 if (!$noFilesystems) {
-    $fsAndSwap = "\n${fileSystems}  ";
+    $fsAndSwap = "\n$fileSystems  ";
     $fsAndSwap .= "swapDevices =" . multiLineList("    ", @swapDevices) . ";\n";
 }
 
@@ -494,11 +515,11 @@ if ($showHardwareConfig) {
     if ($force || ! -e $fn) {
         print STDERR "writing $fn...\n";
 
-        my $bootloaderConfig = "";
+        my $bootLoaderConfig = "";
         if (-e "/sys/firmware/efi/efivars") {
             $bootLoaderConfig = <<EOF;
-  # Use the gummiboot efi boot loader.
-  boot.loader.gummiboot.enable = true;
+  # Use the systemd-boot EFI boot loader.
+  boot.loader.systemd-boot.enable = true;
   boot.loader.efi.canTouchEfiVariables = true;
 EOF
         } elsif ($virt ne "systemd-nspawn") {
@@ -568,7 +589,7 @@ $bootLoaderConfig
   # };
 
   # The NixOS release to be compatible with for stateful data such as databases.
-  system.stateVersion = "@nixosRelease@";
+  system.stateVersion = "${\(qw(@nixosRelease@))}";
 
 }
 EOF
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index b2cb121d1d63..8da421447624 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -147,7 +147,6 @@
       foundationdb = 118;
       newrelic = 119;
       starbound = 120;
-      #grsecurity = 121; # unused
       hydra = 122;
       spiped = 123;
       teamspeak = 124;
@@ -267,6 +266,10 @@
       graylog = 243;
       sniproxy = 244;
       nzbget = 245;
+      mosquitto = 246;
+      toxvpn = 247;
+      squeezelite = 248;
+      turnserver = 249;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -394,7 +397,6 @@
       foundationdb = 118;
       newrelic = 119;
       starbound = 120;
-      grsecurity = 121;
       hydra = 122;
       spiped = 123;
       teamspeak = 124;
@@ -504,6 +506,10 @@
       emby = 242;
       sniproxy = 244;
       nzbget = 245;
+      mosquitto = 246;
+      #toxvpn = 247; # unused
+      #squeezelite = 248; #unused
+      turnserver = 249;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix
index f12ecc1b88ec..9a37f5950930 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -5,9 +5,11 @@ with lib;
 let
   cfg = config.system;
 
-  releaseFile = "${toString pkgs.path}/.version";
-  suffixFile = "${toString pkgs.path}/.version-suffix";
+  releaseFile  = "${toString pkgs.path}/.version";
+  suffixFile   = "${toString pkgs.path}/.version-suffix";
   revisionFile = "${toString pkgs.path}/.git-revision";
+  gitRepo      = "${toString pkgs.path}/.git";
+  gitCommitId  = lib.substring 0 7 (commitIdFromGitRepo gitRepo);
 in
 
 {
@@ -102,6 +104,8 @@ in
       # changing them would not rebuild the manual
       nixosLabel   = mkDefault (maybeEnv "NIXOS_LABEL" cfg.nixosVersion);
       nixosVersion = mkDefault (maybeEnv "NIXOS_VERSION" (cfg.nixosRelease + cfg.nixosVersionSuffix));
+      nixosRevision      = mkIf (pathIsDirectory gitRepo) (mkDefault            gitCommitId);
+      nixosVersionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId));
 
       # Note: code names must only increase in alphabetical order.
       nixosCodeName = "Flounder";
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 370220d253a5..be72c0ef29c0 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -79,6 +79,7 @@
   ./programs/ssh.nix
   ./programs/ssmtp.nix
   ./programs/tmux.nix
+  ./programs/unity3d.nix
   ./programs/venus.nix
   ./programs/wvdial.nix
   ./programs/xfs_quota.nix
@@ -109,6 +110,7 @@
   ./services/audio/liquidsoap.nix
   ./services/audio/mpd.nix
   ./services/audio/mopidy.nix
+  ./services/audio/squeezelite.nix
   ./services/backup/almir.nix
   ./services/backup/bacula.nix
   ./services/backup/crashplan.nix
@@ -124,9 +126,11 @@
   ./services/computing/torque/server.nix
   ./services/computing/torque/mom.nix
   ./services/computing/slurm/slurm.nix
+  ./services/continuous-integration/buildkite-agent.nix
+  ./services/continuous-integration/hydra/default.nix
   ./services/continuous-integration/jenkins/default.nix
-  ./services/continuous-integration/jenkins/slave.nix
   ./services/continuous-integration/jenkins/job-builder.nix
+  ./services/continuous-integration/jenkins/slave.nix
   ./services/databases/4store-endpoint.nix
   ./services/databases/4store.nix
   ./services/databases/couchdb.nix
@@ -216,6 +220,7 @@
   ./services/misc/confd.nix
   ./services/misc/devmon.nix
   ./services/misc/dictd.nix
+  ./services/misc/dysnomia.nix
   ./services/misc/disnix.nix
   ./services/misc/docker-registry.nix
   ./services/misc/emby.nix
@@ -312,6 +317,7 @@
   ./services/networking/cntlm.nix
   ./services/networking/connman.nix
   ./services/networking/consul.nix
+  ./services/networking/coturn.nix
   ./services/networking/ddclient.nix
   ./services/networking/dhcpcd.nix
   ./services/networking/dhcpd.nix
@@ -347,6 +353,7 @@
   ./services/networking/mjpg-streamer.nix
   ./services/networking/minidlna.nix
   ./services/networking/miniupnpd.nix
+  ./services/networking/mosquitto.nix
   ./services/networking/mstpd.nix
   ./services/networking/murmur.nix
   ./services/networking/namecoind.nix
@@ -366,6 +373,7 @@
   ./services/networking/ostinato.nix
   ./services/networking/pdnsd.nix
   ./services/networking/polipo.nix
+  ./services/networking/pptpd.nix
   ./services/networking/prayer.nix
   ./services/networking/privoxy.nix
   ./services/networking/prosody.nix
@@ -397,6 +405,7 @@
   ./services/networking/tftpd.nix
   ./services/networking/tlsdated.nix
   ./services/networking/tox-bootstrapd.nix
+  ./services/networking/toxvpn.nix
   ./services/networking/tvheadend.nix
   ./services/networking/unbound.nix
   ./services/networking/unifi.nix
@@ -406,6 +415,7 @@
   ./services/networking/wicd.nix
   ./services/networking/wpa_supplicant.nix
   ./services/networking/xinetd.nix
+  ./services/networking/xl2tpd.nix
   ./services/networking/zerobin.nix
   ./services/networking/zerotierone.nix
   ./services/networking/znc.nix
@@ -427,6 +437,7 @@
   ./services/security/haveged.nix
   ./services/security/hologram.nix
   ./services/security/munge.nix
+  ./services/security/oauth2_proxy.nix
   ./services/security/physlock.nix
   ./services/security/torify.nix
   ./services/security/tor.nix
@@ -451,6 +462,7 @@
   ./services/web-servers/lighttpd/cgit.nix
   ./services/web-servers/lighttpd/default.nix
   ./services/web-servers/lighttpd/gitweb.nix
+  ./services/web-servers/lighttpd/inginious.nix
   ./services/web-servers/nginx/default.nix
   ./services/web-servers/phpfpm.nix
   ./services/web-servers/shellinabox.nix
@@ -486,6 +498,7 @@
   ./services/x11/window-managers/windowlab.nix
   ./services/x11/window-managers/wmii.nix
   ./services/x11/window-managers/xmonad.nix
+  ./services/x11/xbanish.nix
   ./services/x11/xfs.nix
   ./services/x11/xserver.nix
   ./system/activation/activation-script.nix
@@ -502,10 +515,10 @@
   ./system/boot/loader/grub/grub.nix
   ./system/boot/loader/grub/ipxe.nix
   ./system/boot/loader/grub/memtest.nix
-  ./system/boot/loader/gummiboot/gummiboot.nix
   ./system/boot/loader/init-script/init-script.nix
   ./system/boot/loader/loader.nix
   ./system/boot/loader/raspberrypi/raspberrypi.nix
+  ./system/boot/loader/systemd-boot/systemd-boot.nix
   ./system/boot/luksroot.nix
   ./system/boot/modprobe.nix
   ./system/boot/networkd.nix
diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix
index e4e264ec0036..c09bcfb70e24 100644
--- a/nixos/modules/programs/bash/bash.nix
+++ b/nixos/modules/programs/bash/bash.nix
@@ -200,7 +200,7 @@ in
     # Configuration for readline in bash.
     environment.etc."inputrc".source = ./inputrc;
 
-    users.defaultUserShell = mkDefault "/run/current-system/sw/bin/bash";
+    users.defaultUserShell = mkDefault pkgs.bashInteractive;
 
     environment.pathsToLink = optionals cfg.enableCompletion [
       "/etc/bash_completion.d"
diff --git a/nixos/modules/programs/fish.nix b/nixos/modules/programs/fish.nix
index 7a4b78118ce6..a99c98e166dc 100644
--- a/nixos/modules/programs/fish.nix
+++ b/nixos/modules/programs/fish.nix
@@ -84,19 +84,19 @@ in
 
       set fish_function_path $fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions
 
-      fenv source ${config.system.build.setEnvironment} 1> /dev/null
-      fenv source /etc/fish/foreign-env/shellInit 1> /dev/null
+      fenv source ${config.system.build.setEnvironment} > /dev/null ^&1
+      fenv source /etc/fish/foreign-env/shellInit > /dev/null
 
       ${cfg.shellInit}
 
-      if builtin status --is-login
-        fenv source /etc/fish/foreign-env/loginShellInit 1> /dev/null
+      if status --is-login
+        fenv source /etc/fish/foreign-env/loginShellInit > /dev/null
         ${cfg.loginShellInit}
       end
 
-      if builtin status --is-interactive
+      if status --is-interactive
         ${fishAliases}
-        fenv source /etc/fish/foreign-env/interactiveShellInit 1> /dev/null
+        fenv source /etc/fish/foreign-env/interactiveShellInit > /dev/null
         ${cfg.interactiveShellInit}
       end
     '';
diff --git a/nixos/modules/programs/man.nix b/nixos/modules/programs/man.nix
index 201144ccb451..e59ffd6f936d 100644
--- a/nixos/modules/programs/man.nix
+++ b/nixos/modules/programs/man.nix
@@ -19,7 +19,7 @@ with lib;
 
   config = mkIf config.programs.man.enable {
 
-    environment.systemPackages = [ pkgs.man ];
+    environment.systemPackages = [ pkgs.man-db ];
 
     environment.pathsToLink = [ "/share/man" ];
 
diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix
index 566398d839fd..6398509357a6 100644
--- a/nixos/modules/programs/shadow.nix
+++ b/nixos/modules/programs/shadow.nix
@@ -1,6 +1,6 @@
 # Configuration for the pwdutils suite of tools: passwd, useradd, etc.
 
-{ config, lib, pkgs, ... }:
+{ config, lib, utils, pkgs, ... }:
 
 with lib;
 
@@ -43,13 +43,13 @@ in
     users.defaultUserShell = lib.mkOption {
       description = ''
         This option defines the default shell assigned to user
-        accounts.  This must not be a store path, since the path is
+        accounts. This can be either a full system path or a shell package.
+
+        This must not be a store path, since the path is
         used outside the store (in particular in /etc/passwd).
-        Rather, it should be the path of a symlink that points to the
-        actual shell in the Nix store.
       '';
-      example = "/run/current-system/sw/bin/zsh";
-      type = types.path;
+      example = literalExample "pkgs.zsh";
+      type = types.either types.path types.shellPackage;
     };
 
   };
@@ -60,7 +60,9 @@ in
   config = {
 
     environment.systemPackages =
-      lib.optional config.users.mutableUsers pkgs.shadow;
+      lib.optional config.users.mutableUsers pkgs.shadow ++
+      lib.optional (types.shellPackage.check config.users.defaultUserShell)
+        config.users.defaultUserShell;
 
     environment.etc =
       [ { # /etc/login.defs: global configuration for pwdutils.  You
@@ -74,7 +76,7 @@ in
             ''
               GROUP=100
               HOME=/home
-              SHELL=${config.users.defaultUserShell}
+              SHELL=${utils.toShellPath config.users.defaultUserShell}
             '';
           target = "default/useradd";
         }
diff --git a/nixos/modules/programs/tmux.nix b/nixos/modules/programs/tmux.nix
index 2fc1ed63cb36..cadf8d4ae105 100644
--- a/nixos/modules/programs/tmux.nix
+++ b/nixos/modules/programs/tmux.nix
@@ -156,8 +156,13 @@ in {
 
   config = mkIf cfg.enable {
     environment = {
-      systemPackages = [ pkgs.tmux ];
       etc."tmux.conf".text = tmuxConf;
+
+      systemPackages = [ pkgs.tmux ];
+
+      variables = {
+        TMUX_TMPDIR = ''''${XDG_RUNTIME_DIR:-"/run/user/\$(id -u)"}'';
+      };
     };
   };
 }
diff --git a/nixos/modules/programs/unity3d.nix b/nixos/modules/programs/unity3d.nix
new file mode 100644
index 000000000000..3c0ea26d9d56
--- /dev/null
+++ b/nixos/modules/programs/unity3d.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.programs.unity3d;
+in {
+
+  options = {
+    programs.unity3d.enable = mkEnableOption "Unity3D, a game development tool";
+  };
+
+  config = mkIf cfg.enable {
+    security.setuidOwners = [{
+      program = "unity-chrome-sandbox";
+      source = "${pkgs.unity3d.sandbox}/bin/unity-chrome-sandbox";
+      owner = "root";
+      #group = "root";
+      setuid = true;
+      #setgid = true;
+    }];
+
+    environment.systemPackages = [ pkgs.unity3d ];
+  };
+
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 2f37f180c7ec..634f91a275d3 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -34,6 +34,8 @@ with lib;
     # Old Grub-related options.
     (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ])
     (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ])
+    (mkRenamedOptionModule [ "boot" "loader" "grub" "timeout" ] [ "boot" "loader" "timeout" ])
+    (mkRenamedOptionModule [ "boot" "loader" "gummiboot" "timeout" ] [ "boot" "loader" "timeout" ])
 
     # smartd
     (mkRenamedOptionModule [ "services" "smartd" "deviceOpts" ] [ "services" "smartd" "defaults" "monitored" ])
@@ -112,6 +114,26 @@ with lib;
     (mkRenamedOptionModule [ "services" "iodined" "extraConfig" ] [ "services" "iodine" "server" "extraConfig" ])
     (mkRemovedOptionModule [ "services" "iodined" "client" ])
 
+    # Grsecurity
+    (mkRemovedOptionModule [ "security" "grsecurity" "kernelPatch" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "mode" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "priority" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "system" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationConfig" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "hardwareVirtualisation" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationSoftware" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "sysctl" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootChmod" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootCaps" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyUSB" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProc" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProcWithGroup" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "unrestrictProcGid" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableRBAC" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableSimultConnect" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "verboseVersion" ])
+    (mkRemovedOptionModule [ "security" "grsecurity" "config" "kernelExtraConfig" ])
+
     # Options that are obsolete and have no replacement.
     (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ])
     (mkRemovedOptionModule [ "programs" "bash" "enable" ])
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index cb5410a5f15d..f646602221a4 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -114,6 +114,19 @@ in
         '';
       };
 
+      preliminarySelfsigned = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether a preliminary self-signed certificate should be generated before
+          doing ACME requests. This can be useful when certificates are required in
+          a webserver, but ACME needs the webserver to make its requests.
+
+          With preliminary self-signed certificate the webserver can be started and
+          can later reload the correct ACME certificates.
+        '';
+      };
+
       certs = mkOption {
         default = { };
         type = types.loaOf types.optionSet;
@@ -140,54 +153,126 @@ in
   config = mkMerge [
     (mkIf (cfg.certs != { }) {
 
-      systemd.services = flip mapAttrs' cfg.certs (cert: data:
-        let
-          cpath = "${cfg.directory}/${cert}";
-          rights = if data.allowKeysForGroup then "750" else "700";
-          cmdline = [ "-v" "-d" cert "--default_root" data.webroot "--valid_min" cfg.validMin ]
-                    ++ optionals (data.email != null) [ "--email" data.email ]
-                    ++ concatMap (p: [ "-f" p ]) data.plugins
-                    ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains);
+      systemd.services = let
+          services = concatLists servicesLists;
+          servicesLists = mapAttrsToList certToServices cfg.certs;
+          certToServices = cert: data:
+              let
+                cpath = "${cfg.directory}/${cert}";
+                rights = if data.allowKeysForGroup then "750" else "700";
+                cmdline = [ "-v" "-d" cert "--default_root" data.webroot "--valid_min" cfg.validMin ]
+                          ++ optionals (data.email != null) [ "--email" data.email ]
+                          ++ concatMap (p: [ "-f" p ]) data.plugins
+                          ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains);
+                acmeService = {
+                  description = "Renew ACME Certificate for ${cert}";
+                  after = [ "network.target" ];
+                  serviceConfig = {
+                    Type = "oneshot";
+                    SuccessExitStatus = [ "0" "1" ];
+                    PermissionsStartOnly = true;
+                    User = data.user;
+                    Group = data.group;
+                    PrivateTmp = true;
+                  };
+                  path = [ pkgs.simp_le ];
+                  preStart = ''
+                    mkdir -p '${cfg.directory}'
+                    if [ ! -d '${cpath}' ]; then
+                      mkdir '${cpath}'
+                    fi
+                    chmod ${rights} '${cpath}'
+                    chown -R '${data.user}:${data.group}' '${cpath}'
+                  '';
+                  script = ''
+                    cd '${cpath}'
+                    set +e
+                    simp_le ${escapeShellArgs cmdline}
+                    EXITCODE=$?
+                    set -e
+                    echo "$EXITCODE" > /tmp/lastExitCode
+                    exit "$EXITCODE"
+                  '';
+                  postStop = ''
+                    if [ -e /tmp/lastExitCode ] && [ "$(cat /tmp/lastExitCode)" = "0" ]; then
+                      echo "Executing postRun hook..."
+                      ${data.postRun}
+                    fi
+                  '';
 
-        in nameValuePair
-        ("acme-${cert}")
-        ({
-          description = "Renew ACME Certificate for ${cert}";
-          after = [ "network.target" ];
-          serviceConfig = {
-            Type = "oneshot";
-            SuccessExitStatus = [ "0" "1" ];
-            PermissionsStartOnly = true;
-            User = data.user;
-            Group = data.group;
-            PrivateTmp = true;
+                  before = [ "acme-certificates.target" ];
+                  wantedBy = [ "acme-certificates.target" ];
+                };
+                selfsignedService = {
+                  description = "Create preliminary self-signed certificate for ${cert}";
+                  preStart = ''
+                      if [ ! -d '${cpath}' ]
+                      then
+                        mkdir -p '${cpath}'
+                        chmod ${rights} '${cpath}'
+                        chown '${data.user}:${data.group}' '${cpath}'
+                      fi
+                  '';
+                  script = 
+                    ''
+                      # Create self-signed key
+                      workdir="/run/acme-selfsigned-${cert}"
+                      ${pkgs.openssl.bin}/bin/openssl genrsa -des3 -passout pass:x -out $workdir/server.pass.key 2048
+                      ${pkgs.openssl.bin}/bin/openssl rsa -passin pass:x -in $workdir/server.pass.key -out $workdir/server.key
+                      ${pkgs.openssl.bin}/bin/openssl req -new -key $workdir/server.key -out $workdir/server.csr \
+                        -subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=IT Department/CN=example.com"
+                      ${pkgs.openssl.bin}/bin/openssl x509 -req -days 1 -in $workdir/server.csr -signkey $workdir/server.key -out $workdir/server.crt
+
+                      # Move key to destination
+                      mv $workdir/server.key ${cpath}/key.pem
+                      mv $workdir/server.crt ${cpath}/fullchain.pem
+
+                      # Clean up working directory
+                      rm $workdir/server.csr
+                      rm $workdir/server.pass.key
+
+                      # Give key acme permissions
+                      chmod ${rights} '${cpath}/key.pem'
+                      chown '${data.user}:${data.group}' '${cpath}/key.pem'
+                      chmod ${rights} '${cpath}/fullchain.pem'
+                      chown '${data.user}:${data.group}' '${cpath}/fullchain.pem'
+                    '';
+                  serviceConfig = {
+                    Type = "oneshot";
+                    RuntimeDirectory = "acme-selfsigned-${cert}";
+                    PermissionsStartOnly = true;
+                    User = data.user;
+                    Group = data.group;
+                  };
+                  unitConfig = {
+                    # Do not create self-signed key when key already exists
+                    ConditionPathExists = "!${cpath}/key.pem";
+                  };
+                  before = [
+                    "acme-selfsigned-certificates.target"
+                  ];
+                  wantedBy = [
+                    "acme-selfsigned-certificates.target"
+                  ];
+                };
+              in (
+                [ { name = "acme-${cert}"; value = acmeService; } ]
+                ++
+                (if cfg.preliminarySelfsigned
+                  then [ { name = "acme-selfsigned-${cert}"; value = selfsignedService; } ]
+                  else []
+                )
+              );
+          servicesAttr = listToAttrs services;
+          nginxAttr = {
+            nginx = {
+              after = [ "acme-selfsigned-certificates.target" ];
+              wants = [ "acme-selfsigned-certificates.target" "acme-certificates.target" ];
+            };
           };
-          path = [ pkgs.simp_le ];
-          preStart = ''
-            mkdir -p '${cfg.directory}'
-            if [ ! -d '${cpath}' ]; then
-              mkdir '${cpath}'
-            fi
-            chmod ${rights} '${cpath}'
-            chown -R '${data.user}:${data.group}' '${cpath}'
-          '';
-          script = ''
-            cd '${cpath}'
-            set +e
-            simp_le ${concatMapStringsSep " " (arg: escapeShellArg (toString arg)) cmdline}
-            EXITCODE=$?
-            set -e
-            echo "$EXITCODE" > /tmp/lastExitCode
-            exit "$EXITCODE"
-          '';
-          postStop = ''
-            if [ -e /tmp/lastExitCode ] && [ "$(cat /tmp/lastExitCode)" = "0" ]; then
-              echo "Executing postRun hook..."
-              ${data.postRun}
-            fi
-          '';
-        })
-      );
+        in
+          servicesAttr //
+          (if config.services.nginx.enable then nginxAttr else {});
 
       systemd.timers = flip mapAttrs' cfg.certs (cert: data: nameValuePair
         ("acme-${cert}")
@@ -200,6 +285,9 @@ in
           };
         })
       );
+
+      systemd.targets."acme-selfsigned-certificates" = mkIf cfg.preliminarySelfsigned {};
+      systemd.targets."acme-certificates" = {};
     })
 
     { meta.maintainers = with lib.maintainers; [ abbradar fpletz globin ];
diff --git a/nixos/modules/security/acme.xml b/nixos/modules/security/acme.xml
index e32fa72c9393..15ed4c04a23d 100644
--- a/nixos/modules/security/acme.xml
+++ b/nixos/modules/security/acme.xml
@@ -66,4 +66,32 @@ options for the <literal>security.acme</literal> module.</para>
 
 </section>
 
+<section><title>Using ACME certificates in Nginx</title>
+<para>In practice ACME is mostly used for retrieval and renewal of
+  certificates that will be used in a webserver like Nginx. A configuration for
+  Nginx that uses the certificates from ACME for
+  <literal>foo.example.com</literal> will look similar to:
+</para>
+
+<programlisting>
+services.nginx.httpConfig = ''
+  server {
+    server_name foo.example.com;
+    listen 443 ssl;
+    ssl_certificate     ${config.security.acme.directory}/foo.example.com/fullchain.pem;
+    ssl_certificate_key ${config.security.acme.directory}/foo.example.com/key.pem;
+    root /var/www/foo.example.com/;
+  }
+'';
+</programlisting>
+
+<para>Now Nginx will try to use the certificates that will be retrieved by ACME.
+  ACME needs Nginx (or any other webserver) to function and Nginx needs
+  the certificates to actually start. For this reason the ACME module
+  automatically generates self-signed certificates that will be used by Nginx to
+  start. After that Nginx is used by ACME to retrieve the actual ACME
+  certificates. <literal>security.acme.preliminarySelfsigned</literal> can be
+  used to control whether to generate the self-signed certificates.
+</para>
+</section>
 </chapter>
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index 3f24118ea1cb..9d0249820d5d 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -1,312 +1,122 @@
-{ config, lib, pkgs, ... }:
+{ config, pkgs, lib, ... }:
 
 with lib;
 
 let
   cfg = config.security.grsecurity;
-
-  customGrsecPkg =
-    (import ../../../pkgs/build-support/grsecurity {
-      grsecOptions = cfg;
-      inherit pkgs lib;
-    }).grsecPackage;
+  grsecLockPath = "/proc/sys/kernel/grsecurity/grsec_lock";
+
+  # Ascertain whether ZFS is required for booting the system; grsecurity is
+  # currently incompatible with ZFS, rendering the system unbootable.
+  zfsNeededForBoot = filter
+    (fs: (fs.neededForBoot
+          || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ])
+          && fs.fsType == "zfs")
+    (attrValues config.fileSystems) != [];
 in
-{
-  options = {
-    security.grsecurity = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Enable grsecurity support. This enables advanced exploit
-          hardening for the Linux kernel, and adds support for
-          administrative Role-Based Acess Control (RBAC) via
-          <literal>gradm</literal>. It also includes traditional
-          utilities for PaX.
-        '';
-      };
-
-      kernelPatch = mkOption {
-        type = types.attrs;
-        example = lib.literalExample "pkgs.kernelPatches.grsecurity_4_1";
-        description = ''
-          Grsecurity patch to use.
-        '';
-      };
-
-      config = {
-        mode = mkOption {
-          type = types.enum [ "auto" "custom" ];
-          default = "auto";
-          description = ''
-            grsecurity configuration mode. This specifies whether
-            grsecurity is auto-configured or otherwise completely
-            manually configured.
-          '';
-        };
-
-        priority = mkOption {
-          type = types.enum [ "security" "performance" ];
-          default = "security";
-          description = ''
-            grsecurity configuration priority. This specifies whether
-            the kernel configuration should emphasize speed or
-            security.
-          '';
-        };
-
-        system = mkOption {
-          type = types.enum [ "desktop" "server" ];
-          default = "desktop";
-          description = ''
-            grsecurity system configuration.
-          '';
-        };
 
-        virtualisationConfig = mkOption {
-          type = types.nullOr (types.enum [ "host" "guest" ]);
-          default = null;
-          description = ''
-            grsecurity virtualisation configuration. This specifies
-            the virtualisation role of the machine - that is, whether
-            it will be a virtual machine guest, a virtual machine
-            host, or neither.
-          '';
-        };
-
-        hardwareVirtualisation = mkOption {
-          type = types.nullOr types.bool;
-          default = null;
-          example = true;
-          description = ''
-            grsecurity hardware virtualisation configuration. Set to
-            <literal>true</literal> if your machine supports hardware
-            accelerated virtualisation.
-          '';
-        };
-
-        virtualisationSoftware = mkOption {
-          type = types.nullOr (types.enum [ "kvm" "xen" "vmware" "virtualbox" ]);
-          default = null;
-          description = ''
-            Configure grsecurity for use with this virtualisation software.
-          '';
-        };
-
-        sysctl = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            If true, then set <literal>GRKERN_SYSCTL y</literal>. If
-            enabled then grsecurity can be controlled using sysctl
-            (and turned off). You are advised to *never* enable this,
-            but if you do, make sure to always set the sysctl
-            <literal>kernel.grsecurity.grsec_lock</literal> to
-            non-zero as soon as all sysctl options are set. *THIS IS
-            EXTREMELY IMPORTANT*!
-          '';
-        };
-
-        denyChrootChmod = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            If true, then set <literal>GRKERN_CHROOT_CHMOD
-            y</literal>. If enabled, this denies processes inside a
-            chroot from setting the suid or sgid bits using
-            <literal>chmod</literal> or <literal>fchmod</literal>.
-
-            By default this protection is disabled - it makes it
-            impossible to use Nix to build software on your system,
-            which is what most users want.
+{
+  options.security.grsecurity = {
+
+    enable = mkEnableOption "Grsecurity/PaX";
+
+    lockTunables = mkOption {
+      type = types.bool;
+      example = false;
+      default = true;
+      description = ''
+        Whether to automatically lock grsecurity tunables
+        (<option>boot.kernel.sysctl."kernel.grsecurity.*"</option>).  Disable
+        this to allow configuration of grsecurity features while the system is
+        running.  The lock can be manually engaged by activating the
+        <literal>grsec-lock</literal> service unit.
+      '';
+    };
 
-            If you are using NixOps to deploy your software to a
-            remote machine, you're encouraged to enable this as you
-            won't need to compile code.
-          '';
-        };
+  };
 
-        denyChrootCaps = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            Whether to lower capabilities of all processes within a chroot,
-            preventing commands that require <literal>CAP_SYS_ADMIN</literal>.
+  config = mkIf cfg.enable {
 
-            This protection is disabled by default because it breaks
-            <literal>nixos-rebuild</literal>. Whenever possible, it is
-            highly recommended to enable this protection.
-          '';
-        };
+    # Allow the user to select a different package set, subject to the stated
+    # required kernel config
+    boot.kernelPackages = mkDefault pkgs.linuxPackages_grsec_nixos;
 
-        denyUSB = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            If true, then set <literal>GRKERNSEC_DENYUSB y</literal>.
+    system.requiredKernelConfig = with config.lib.kernelConfig;
+      [ (isEnabled "GRKERNSEC")
+        (isEnabled "PAX")
+        (isYES "GRKERNSEC_SYSCTL")
+        (isYES "GRKERNSEC_SYSCTL_DISTRO")
+      ];
 
-            This enables a sysctl with name
-            <literal>kernel.grsecurity.deny_new_usb</literal>. Setting
-            its value to <literal>1</literal> will prevent any new USB
-            devices from being recognized by the OS.  Any attempted
-            USB device insertion will be logged.
+    # Crashing on an overflow in kernel land is user unfriendly and may prevent
+    # the system from booting, which is too severe for our use case.
+    boot.kernelParams = [ "pax_size_overflow_report_only" ];
 
-            This option is intended to be used against custom USB
-            devices designed to exploit vulnerabilities in various USB
-            device drivers.
-          '';
-        };
+    # Install PaX related utillities into the system profile.  Eventually, we
+    # also want to include gradm here.
+    environment.systemPackages = with pkgs; [ paxctl pax-utils ];
 
-        restrictProc = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            If true, then set <literal>GRKERN_PROC_USER
-            y</literal>. This restricts non-root users to only viewing
-            their own processes and restricts network-related
-            information, kernel symbols, and module information.
-          '';
-        };
+    # Install rules for the grsec device node
+    services.udev.packages = [ pkgs.gradm ];
 
-        restrictProcWithGroup = mkOption {
-          type = types.bool;
-          default = true;
-          description = ''
-            If true, then set <literal>GRKERN_PROC_USERGROUP
-            y</literal>. This is similar to
-            <literal>restrictProc</literal> except it allows a special
-            group (specified by <literal>unrestrictProcGid</literal>)
-            to still access otherwise classified information in
-            <literal>/proc</literal>.
-          '';
-        };
+    # This service unit is responsible for locking the Grsecurity tunables.  The
+    # unit is always defined, but only activated on bootup if lockTunables is
+    # toggled.  When lockTunables is toggled, failure to activate the unit will
+    # enter emergency mode.  The intent is to make it difficult to silently
+    # enter multi-user mode without having locked the tunables.  Some effort is
+    # made to ensure that starting the unit is an idempotent operation.
+    systemd.services.grsec-lock = {
+      description = "Lock grsecurity tunables";
 
-        unrestrictProcGid = mkOption {
-          type = types.int;
-          default = config.ids.gids.grsecurity;
-          description = ''
-            If set, specifies a GID which is exempt from
-            <literal>/proc</literal> restrictions (set by
-            <literal>GRKERN_PROC_USERGROUP</literal>). By default,
-            this is set to the GID for <literal>grsecurity</literal>,
-            a predefined NixOS group, which the
-            <literal>root</literal> account is a member of. You may
-            conveniently add other users to this group if you need
-            access to <literal>/proc</literal>
-          '';
-        };
+      wantedBy = optional cfg.lockTunables "multi-user.target";
 
-        disableRBAC = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            If true, then set <literal>GRKERN_NO_RBAC
-            y</literal>. This disables the
-            <literal>/dev/grsec</literal> device, which in turn
-            disables the RBAC system (and <literal>gradm</literal>).
-          '';
-        };
+      wants = [ "local-fs.target" "systemd-sysctl.service" ];
+      after = [ "local-fs.target" "systemd-sysctl.service" ];
+      conflicts = [ "shutdown.target" ];
 
-        disableSimultConnect = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            Disable TCP simultaneous connect.  The TCP simultaneous connect
-            feature allows two clients to connect without either of them
-            entering the listening state.  This feature of the TCP specification
-            is claimed to enable an attacker to deny the target access to a given
-            server by guessing the source port the target would use to make the
-            connection.
+      restartIfChanged = false;
 
-            This option is OFF by default because TCP simultaneous connect has
-            some legitimate uses.  Enable this option if you know what this TCP
-            feature is for and know that you do not need it.
-          '';
-        };
+      script = ''
+        if ${pkgs.gnugrep}/bin/grep -Fq 0 ${grsecLockPath} ; then
+          echo -n 1 > ${grsecLockPath}
+        fi
+      '';
 
-        verboseVersion = mkOption {
-          type = types.bool;
-          default = false;
-          description = "Use verbose version in kernel localversion.";
-        };
+      unitConfig = {
+        ConditionPathIsReadWrite = grsecLockPath;
+        DefaultDependencies = false;
+      } // optionalAttrs cfg.lockTunables {
+        OnFailure = "emergency.target";
+      };
 
-        kernelExtraConfig = mkOption {
-          type = types.str;
-          default = "";
-          description = "Extra kernel configuration parameters.";
-        };
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
       };
     };
-  };
 
-  config = mkIf cfg.enable {
-    assertions =
-      [
-        { assertion = (cfg.config.restrictProc -> !cfg.config.restrictProcWithGroup) ||
-                      (cfg.config.restrictProcWithGroup -> !cfg.config.restrictProc);
-          message   = "You cannot enable both restrictProc and restrictProcWithGroup";
-        }
-        { assertion = config.boot.kernelPackages.kernel.features ? grsecurity
-                   && config.boot.kernelPackages.kernel.features.grsecurity;
-          message = "grsecurity enabled, but kernel doesn't have grsec support";
-        }
-        { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) ->
-              cfg.config.hardwareVirtualisation != null;
-          message   = "when using auto grsec mode with virtualisation, you must specify if your hardware has virtualisation extensions";
-        }
-        { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) ->
-              cfg.config.virtualisationSoftware != null;
-         message   = "grsecurity configured for virtualisation but no virtualisation software specified";
-        }
-      ];
-
-    security.grsecurity.kernelPatch = lib.mkDefault pkgs.kernelPatches.grsecurity_latest;
-
-    systemd.services.grsec-lock = mkIf cfg.config.sysctl {
-      description     = "grsecurity sysctl-lock Service";
-      wants           = [ "systemd-sysctl.service" ];
-      after           = [ "systemd-sysctl.service" ];
-      wantedBy        = [ "multi-user.target" ];
-      serviceConfig.Type = "oneshot";
-      serviceConfig.RemainAfterExit = "yes";
-      unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock";
-      script = ''
-        locked=`cat /proc/sys/kernel/grsecurity/grsec_lock`
-        if [ "$locked" == "0" ]; then
-            echo 1 > /proc/sys/kernel/grsecurity/grsec_lock
-            echo grsecurity sysctl lock - enabled
-        else
-            echo grsecurity sysctl lock already enabled - doing nothing
-        fi
-      '';
+    # Configure system tunables
+    boot.kernel.sysctl = {
+      # Removed under grsecurity
+      "kernel.kptr_restrict" = mkForce null;
+    } // optionalAttrs config.nix.useSandbox {
+      # chroot(2) restrictions that conflict with sandboxed Nix builds
+      "kernel.grsecurity.chroot_caps" = mkForce 0;
+      "kernel.grsecurity.chroot_deny_chroot" = mkForce 0;
+      "kernel.grsecurity.chroot_deny_mount" = mkForce 0;
+      "kernel.grsecurity.chroot_deny_pivot" = mkForce 0;
+    } // optionalAttrs config.boot.enableContainers {
+      # chroot(2) restrictions that conflict with NixOS lightweight containers
+      "kernel.grsecurity.chroot_deny_chmod" = mkForce 0;
+      "kernel.grsecurity.chroot_deny_mount" = mkForce 0;
+      "kernel.grsecurity.chroot_restrict_nice" = mkForce 0;
     };
 
-#   systemd.services.grsec-learn = {
-#     description     = "grsecurity learning Service";
-#     wantedBy        = [ "local-fs.target" ];
-#     serviceConfig   = {
-#       Type = "oneshot";
-#       RemainAfterExit = "yes";
-#       ExecStart = "${pkgs.gradm}/sbin/gradm -VFL /etc/grsec/learning.logs";
-#       ExecStop  = "${pkgs.gradm}/sbin/gradm -D";
-#     };
-#   };
-
-    system.activationScripts = lib.optionalAttrs (!cfg.config.disableRBAC) { grsec = ''
-      mkdir -p /etc/grsec
-      if [ ! -f /etc/grsec/learn_config ]; then
-        cp ${pkgs.gradm}/etc/grsec/learn_config /etc/grsec
-      fi
-      if [ ! -f /etc/grsec/policy ]; then
-        cp ${pkgs.gradm}/etc/grsec/policy /etc/grsec
-      fi
-      chmod -R 0600 /etc/grsec
-    ''; };
+    assertions = [
+      { assertion = !zfsNeededForBoot;
+        message = "grsecurity is currently incompatible with ZFS";
+      }
+    ];
 
-    # Enable AppArmor, gradm udev rules, and utilities
-    security.apparmor.enable   = true;
-    boot.kernelPackages        = customGrsecPkg;
-    services.udev.packages     = lib.optional (!cfg.config.disableRBAC) pkgs.gradm;
-    environment.systemPackages = [ pkgs.paxctl pkgs.pax-utils ] ++ lib.optional (!cfg.config.disableRBAC) pkgs.gradm;
   };
 }
diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix
index 7d69f9b1183d..99dd514feea3 100644
--- a/nixos/modules/security/setuid-wrappers.nix
+++ b/nixos/modules/security/setuid-wrappers.nix
@@ -96,7 +96,7 @@ in
           }:
 
           ''
-            if ! source=${if source != "" then source else "$(PATH=$SETUID_PATH type -tP ${program})"}; then
+            if ! source=${if source != "" then source else "$(readlink -f $(PATH=$SETUID_PATH type -tP ${program}))"}; then
                 # If we can't find the program, fall back to the
                 # system profile.
                 source=/nix/var/nix/profiles/default/bin/${program}
diff --git a/nixos/modules/services/audio/squeezelite.nix b/nixos/modules/services/audio/squeezelite.nix
new file mode 100644
index 000000000000..f1a60be992d8
--- /dev/null
+++ b/nixos/modules/services/audio/squeezelite.nix
@@ -0,0 +1,67 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  uid = config.ids.uids.squeezelite;
+  cfg = config.services.squeezelite;
+
+in {
+
+  ###### interface
+
+  options = {
+
+    services.squeezelite= {
+
+      enable = mkEnableOption "Squeezelite, a software Squeezebox emulator";
+
+      dataDir = mkOption {
+        default = "/var/lib/squeezelite";
+        type = types.str;
+        description = ''
+          The directory where Squeezelite stores its name file.
+        '';
+      };
+
+      extraArguments = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Additional command line arguments to pass to Squeezelite.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.squeezelite= {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "sound.target" ];
+      description = "Software Squeezebox emulator";
+      preStart = "mkdir -p ${cfg.dataDir} && chown -R squeezelite ${cfg.dataDir}";
+      serviceConfig = {
+        ExecStart = "${pkgs.squeezelite}/bin/squeezelite -N ${cfg.dataDir}/player-name ${cfg.extraArguments}";
+        User = "squeezelite";
+        PermissionsStartOnly = true;
+      };
+    };
+
+    users.extraUsers.squeezelite= {
+      inherit uid;
+      group = "nogroup";
+      extraGroups = [ "audio" ];
+      description = "Squeezelite user";
+      home = "${cfg.dataDir}";
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix
index ad8836f40094..ee38a42199ee 100644
--- a/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixos/modules/services/computing/slurm/slurm.nix
@@ -40,7 +40,7 @@ in
         defaultText = "pkgs.slurm-llnl";
         example = literalExample "pkgs.slurm-llnl-full";
         description = ''
-          The packge to use for slurm binaries.
+          The package to use for slurm binaries.
         '';
       };
 
@@ -111,7 +111,7 @@ in
         builder = pkgs.writeText "builder.sh" ''
           source $stdenv/setup
           mkdir -p $out/bin
-          find  ${cfg.package}/bin -type f -executable | while read EXE
+          find  ${getBin cfg.package}/bin -type f -executable | while read EXE
           do
             exename="$(basename $EXE)"
             wrappername="$out/bin/$exename"
diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix
new file mode 100644
index 000000000000..b1449882b04f
--- /dev/null
+++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix
@@ -0,0 +1,100 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.buildkite-agent;
+  configFile = pkgs.writeText "buildkite-agent.cfg"
+    ''
+      token="${cfg.token}"
+      name="${cfg.name}"
+      meta-data="${cfg.meta-data}"
+      hooks-path="${pkgs.buildkite-agent}/share/hooks"
+      build-path="/var/lib/buildkite-agent/builds"
+      bootstrap-script="${pkgs.buildkite-agent}/share/bootstrap.sh"
+    '';
+in
+
+{
+  options = {
+    services.buildkite-agent = {
+      enable = mkEnableOption "buildkite-agent";
+
+      token = mkOption {
+        type = types.str;
+        description = ''
+          The token from your Buildkite "Agents" page.
+        '';
+      };
+
+      name = mkOption {
+        type = types.str;
+        description = ''
+          The name of the agent.
+        '';
+      };
+
+      meta-data = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Meta data for the agent.
+        '';
+      };
+
+      openssh =
+        { privateKey = mkOption {
+            type = types.str;
+            description = ''
+              Private agent key.
+            '';
+          };
+          publicKey = mkOption {
+            type = types.str;
+            description = ''
+              Public agent key.
+            '';
+          };
+        };
+    };
+  };
+
+  config = mkIf config.services.buildkite-agent.enable {
+    users.extraUsers.buildkite-agent =
+      { name = "buildkite-agent";
+        home = "/var/lib/buildkite-agent";
+        createHome = true;
+        description = "Buildkite agent user";
+      };
+
+    environment.systemPackages = [ pkgs.buildkite-agent ];
+
+    systemd.services.buildkite-agent =
+      { description = "Buildkite Agent";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+        environment.HOME = "/var/lib/buildkite-agent";
+        preStart = ''
+            ${pkgs.coreutils}/bin/mkdir -m 0700 -p /var/lib/buildkite-agent/.ssh
+
+            if ! [ -f /var/lib/buildkite-agent/.ssh/id_rsa ]; then
+              echo "${cfg.openssh.privateKey}" > /var/lib/buildkite-agent/.ssh/id_rsa
+              ${pkgs.coreutils}/bin/chmod 600 /var/lib/buildkite-agent/.ssh/id_rsa
+            fi
+
+            if ! [ -f /var/lib/buildkite-agent/.ssh/id_rsa.pub ]; then
+              echo "${cfg.openssh.publicKey}" > /var/lib/buildkite-agent/.ssh/id_rsa.pub
+              ${pkgs.coreutils}/bin/chmod 600 /var/lib/buildkite-agent/.ssh/id_rsa.pub
+            fi
+          '';
+
+        serviceConfig =
+          { ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config ${configFile}";
+            User = "buildkite-agent";
+            RestartSec = 5;
+            Restart = "on-failure";
+            TimeoutSec = 10;
+          };
+      };
+  };
+}
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
new file mode 100644
index 000000000000..c8edfaf18537
--- /dev/null
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -0,0 +1,418 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.hydra;
+
+  baseDir = "/var/lib/hydra";
+
+  hydraConf = pkgs.writeScript "hydra.conf" cfg.extraConfig;
+
+  hydraEnv =
+    { HYDRA_DBI = cfg.dbi;
+      HYDRA_CONFIG = "${baseDir}/hydra.conf";
+      HYDRA_DATA = "${baseDir}";
+    };
+
+  env =
+    { NIX_REMOTE = "daemon";
+      SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; # Remove in 16.03
+      PGPASSFILE = "${baseDir}/pgpass";
+      NIX_REMOTE_SYSTEMS = concatStringsSep ":" cfg.buildMachinesFiles;
+    } // optionalAttrs (cfg.smtpHost != null) {
+      EMAIL_SENDER_TRANSPORT = "SMTP";
+      EMAIL_SENDER_TRANSPORT_host = cfg.smtpHost;
+    } // hydraEnv // cfg.extraEnv;
+
+  serverEnv = env //
+    { HYDRA_TRACKER = cfg.tracker;
+      COLUMNS = "80";
+      PGPASSFILE = "${baseDir}/pgpass-www"; # grrr
+    } // (optionalAttrs cfg.debugServer { DBIC_TRACE = "1"; });
+
+  localDB = "dbi:Pg:dbname=hydra;user=hydra;";
+
+  haveLocalDB = cfg.dbi == localDB;
+
+in
+
+{
+  ###### interface
+  options = {
+
+    services.hydra = rec {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to run Hydra services.
+        '';
+      };
+
+      dbi = mkOption {
+        type = types.str;
+        default = localDB;
+        example = "dbi:Pg:dbname=hydra;host=postgres.example.org;user=foo;";
+        description = ''
+          The DBI string for Hydra database connection.
+        '';
+      };
+
+      package = mkOption {
+        type = types.path;
+        default = pkgs.hydra;
+        defaultText = "pkgs.hydra";
+        description = "The Hydra package.";
+      };
+
+      hydraURL = mkOption {
+        type = types.str;
+        description = ''
+          The base URL for the Hydra webserver instance. Used for links in emails.
+        '';
+      };
+
+      listenHost = mkOption {
+        type = types.str;
+        default = "*";
+        example = "localhost";
+        description = ''
+          The hostname or address to listen on or <literal>*</literal> to listen
+          on all interfaces.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 3000;
+        description = ''
+          TCP port the web server should listen to.
+        '';
+      };
+
+      minimumDiskFree = mkOption {
+        type = types.int;
+        default = 0;
+        description = ''
+          Threshold of minimum disk space (GiB) to determine if the queue runner should run or not.
+        '';
+      };
+
+      minimumDiskFreeEvaluator = mkOption {
+        type = types.int;
+        default = 0;
+        description = ''
+          Threshold of minimum disk space (GiB) to determine if the evaluator should run or not.
+        '';
+      };
+
+      notificationSender = mkOption {
+        type = types.str;
+        description = ''
+          Sender email address used for email notifications.
+        '';
+      };
+
+      smtpHost = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = ["localhost"];
+        description = ''
+          Hostname of the SMTP server to use to send email.
+        '';
+      };
+
+      tracker = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Piece of HTML that is included on all pages.
+        '';
+      };
+
+      logo = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          Path to a file containing the logo of your Hydra instance.
+        '';
+      };
+
+      debugServer = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to run the server in debug mode.";
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        description = "Extra lines for the Hydra configuration.";
+      };
+
+      extraEnv = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        description = "Extra environment variables for Hydra.";
+      };
+
+      gcRootsDir = mkOption {
+        type = types.path;
+        default = "/nix/var/nix/gcroots/hydra";
+        description = "Directory that holds Hydra garbage collector roots.";
+      };
+
+      buildMachinesFiles = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        example = [ "/etc/nix/machines" "/var/lib/hydra/provisioner/machines" ];
+        description = "List of files containing build machines.";
+      };
+
+      useSubstitutes = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to use binary caches for downloading store paths. Note that
+          binary substitutions trigger (a potentially large number of) additional
+          HTTP requests that slow down the queue monitor thread significantly.
+          Also, this Hydra instance will serve those downloaded store paths to
+          its users with its own signature attached as if it had built them
+          itself, so don't enable this feature unless your active binary caches
+          are absolute trustworthy.
+        '';
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraGroups.hydra = { };
+
+    users.extraUsers.hydra =
+      { description = "Hydra";
+        group = "hydra";
+        createHome = true;
+        home = baseDir;
+        useDefaultShell = true;
+      };
+
+    users.extraUsers.hydra-queue-runner =
+      { description = "Hydra queue runner";
+        group = "hydra";
+        useDefaultShell = true;
+        home = "${baseDir}/queue-runner"; # really only to keep SSH happy
+      };
+
+    users.extraUsers.hydra-www =
+      { description = "Hydra web server";
+        group = "hydra";
+        useDefaultShell = true;
+      };
+
+    nix.trustedUsers = [ "hydra-queue-runner" ];
+
+    services.hydra.extraConfig =
+      ''
+        using_frontend_proxy 1
+        base_uri ${cfg.hydraURL}
+        notification_sender ${cfg.notificationSender}
+        max_servers 25
+        ${optionalString (cfg.logo != null) ''
+          hydra_logo ${cfg.logo}
+        ''}
+        gc_roots_dir ${cfg.gcRootsDir}
+      '';
+
+    environment.systemPackages = [ cfg.package ];
+
+    environment.variables = hydraEnv;
+
+    nix.extraOptions = ''
+      gc-keep-outputs = true
+      gc-keep-derivations = true
+
+      # The default (`true') slows Nix down a lot since the build farm
+      # has so many GC roots.
+      gc-check-reachability = false
+    '';
+
+    systemd.services.hydra-init =
+      { wantedBy = [ "multi-user.target" ];
+        requires = optional haveLocalDB "postgresql.service";
+        after = optional haveLocalDB "postgresql.service";
+        environment = env;
+        preStart = ''
+          mkdir -p ${baseDir}
+          chown hydra.hydra ${baseDir}
+          chmod 0750 ${baseDir}
+
+          ln -sf ${hydraConf} ${baseDir}/hydra.conf
+
+          mkdir -m 0700 -p ${baseDir}/www
+          chown hydra-www.hydra ${baseDir}/www
+
+          mkdir -m 0700 -p ${baseDir}/queue-runner
+          mkdir -m 0750 -p ${baseDir}/build-logs
+          chown hydra-queue-runner.hydra ${baseDir}/queue-runner ${baseDir}/build-logs
+
+          ${optionalString haveLocalDB ''
+            if ! [ -e ${baseDir}/.db-created ]; then
+              ${config.services.postgresql.package}/bin/createuser hydra
+              ${config.services.postgresql.package}/bin/createdb -O hydra hydra
+              touch ${baseDir}/.db-created
+            fi
+          ''}
+
+          if [ ! -e ${cfg.gcRootsDir} ]; then
+
+            # Move legacy roots directory.
+            if [ -e /nix/var/nix/gcroots/per-user/hydra/hydra-roots ]; then
+              mv /nix/var/nix/gcroots/per-user/hydra/hydra-roots ${cfg.gcRootsDir}
+            fi
+
+            mkdir -p ${cfg.gcRootsDir}
+          fi
+
+          # Move legacy hydra-www roots.
+          if [ -e /nix/var/nix/gcroots/per-user/hydra-www/hydra-roots ]; then
+            find /nix/var/nix/gcroots/per-user/hydra-www/hydra-roots/ -type f \
+              | xargs -r mv -f -t ${cfg.gcRootsDir}/
+            rmdir /nix/var/nix/gcroots/per-user/hydra-www/hydra-roots
+          fi
+
+          chown hydra.hydra ${cfg.gcRootsDir}
+          chmod 2775 ${cfg.gcRootsDir}
+        '';
+        serviceConfig.ExecStart = "${cfg.package}/bin/hydra-init";
+        serviceConfig.PermissionsStartOnly = true;
+        serviceConfig.User = "hydra";
+        serviceConfig.Type = "oneshot";
+        serviceConfig.RemainAfterExit = true;
+      };
+
+    systemd.services.hydra-server =
+      { wantedBy = [ "multi-user.target" ];
+        requires = [ "hydra-init.service" ];
+        after = [ "hydra-init.service" ];
+        environment = serverEnv;
+        serviceConfig =
+          { ExecStart =
+              "@${cfg.package}/bin/hydra-server hydra-server -f -h '${cfg.listenHost}' "
+              + "-p ${toString cfg.port} --max_spare_servers 5 --max_servers 25 "
+              + "--max_requests 100 ${optionalString cfg.debugServer "-d"}";
+            User = "hydra-www";
+            PermissionsStartOnly = true;
+            Restart = "always";
+          };
+      };
+
+    systemd.services.hydra-queue-runner =
+      { wantedBy = [ "multi-user.target" ];
+        requires = [ "hydra-init.service" ];
+        after = [ "hydra-init.service" "network.target" ];
+        path = [ cfg.package pkgs.nettools pkgs.openssh pkgs.bzip2 config.nix.package ];
+        environment = env // {
+          PGPASSFILE = "${baseDir}/pgpass-queue-runner"; # grrr
+          IN_SYSTEMD = "1"; # to get log severity levels
+        };
+        serviceConfig =
+          { ExecStart = "@${cfg.package}/bin/hydra-queue-runner hydra-queue-runner -v --option build-use-substitutes ${if cfg.useSubstitutes then "true" else "false"}";
+            ExecStopPost = "${cfg.package}/bin/hydra-queue-runner --unlock";
+            User = "hydra-queue-runner";
+            Restart = "always";
+
+            # Ensure we can get core dumps.
+            LimitCORE = "infinity";
+            WorkingDirectory = "${baseDir}/queue-runner";
+          };
+      };
+
+    systemd.services.hydra-evaluator =
+      { wantedBy = [ "multi-user.target" ];
+        requires = [ "hydra-init.service" ];
+        after = [ "hydra-init.service" "network.target" ];
+        path = [ pkgs.nettools ];
+        environment = env;
+        serviceConfig =
+          { ExecStart = "@${cfg.package}/bin/hydra-evaluator hydra-evaluator";
+            User = "hydra";
+            Restart = "always";
+            WorkingDirectory = baseDir;
+          };
+      };
+
+    systemd.services.hydra-update-gc-roots =
+      { requires = [ "hydra-init.service" ];
+        after = [ "hydra-init.service" ];
+        environment = env;
+        serviceConfig =
+          { ExecStart = "@${cfg.package}/bin/hydra-update-gc-roots hydra-update-gc-roots";
+            User = "hydra";
+          };
+        startAt = "2,14:15";
+      };
+
+    systemd.services.hydra-send-stats =
+      { wantedBy = [ "multi-user.target" ];
+        after = [ "hydra-init.service" ];
+        environment = env;
+        serviceConfig =
+          { ExecStart = "@${cfg.package}/bin/hydra-send-stats hydra-send-stats";
+            User = "hydra";
+          };
+      };
+
+    # If there is less than a certain amount of free disk space, stop
+    # the queue/evaluator to prevent builds from failing or aborting.
+    systemd.services.hydra-check-space =
+      { script =
+          ''
+            if [ $(($(stat -f -c '%a' /nix/store) * $(stat -f -c '%S' /nix/store))) -lt $((${toString cfg.minimumDiskFree} * 1024**3)) ]; then
+                echo "stopping Hydra queue runner due to lack of free space..."
+                systemctl stop hydra-queue-runner
+            fi
+            if [ $(($(stat -f -c '%a' /nix/store) * $(stat -f -c '%S' /nix/store))) -lt $((${toString cfg.minimumDiskFreeEvaluator} * 1024**3)) ]; then
+                echo "stopping Hydra evaluator due to lack of free space..."
+                systemctl stop hydra-evaluator
+            fi
+          '';
+        startAt = "*:0/5";
+      };
+
+    # Periodically compress build logs. The queue runner compresses
+    # logs automatically after a step finishes, but this doesn't work
+    # if the queue runner is stopped prematurely.
+    systemd.services.hydra-compress-logs =
+      { path = [ pkgs.bzip2 ];
+        script =
+          ''
+            find /var/lib/hydra/build-logs -type f -name "*.drv" -mtime +3 -size +0c | xargs -r bzip2 -v -f
+          '';
+        startAt = "Sun 01:45";
+      };
+
+    services.postgresql.enable = mkIf haveLocalDB true;
+
+    services.postgresql.identMap = optionalString haveLocalDB
+      ''
+        hydra-users hydra hydra
+        hydra-users hydra-queue-runner hydra
+        hydra-users hydra-www hydra
+        hydra-users root hydra
+      '';
+
+    services.postgresql.authentication = optionalString haveLocalDB
+      ''
+        local hydra all ident map=hydra-users
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix
index 9e86559dda04..9f22aa7c92b2 100644
--- a/nixos/modules/services/databases/openldap.nix
+++ b/nixos/modules/services/databases/openldap.nix
@@ -40,6 +40,13 @@ in
         description = "Group account under which slapd runs.";
       };
 
+      urlList = mkOption {
+        type = types.listOf types.string;
+        default = [ "ldap:///" ];
+        description = "URL list slapd should listen on.";
+        example = [ "ldaps:///" ];
+      };
+
       dataDir = mkOption {
         type = types.string;
         default = "/var/db/openldap";
@@ -50,13 +57,14 @@ in
         type = types.lines;
         default = "";
         description = "
-          sldapd.conf configuration
+          slapd.conf configuration
         ";
-        example = ''
-            include ''${pkgs.openldap}/etc/openldap/schema/core.schema
-            include ''${pkgs.openldap}/etc/openldap/schema/cosine.schema
-            include ''${pkgs.openldap}/etc/openldap/schema/inetorgperson.schema
-            include ''${pkgs.openldap}/etc/openldap/schema/nis.schema
+        example = literalExample ''
+            '''
+            include ${pkgs.openldap.out}/etc/openldap/schema/core.schema
+            include ${pkgs.openldap.out}/etc/openldap/schema/cosine.schema
+            include ${pkgs.openldap.out}/etc/openldap/schema/inetorgperson.schema
+            include ${pkgs.openldap.out}/etc/openldap/schema/nis.schema
 
             database bdb 
             suffix dc=example,dc=org 
@@ -64,6 +72,7 @@ in
             # NOTE: change after first start
             rootpw secret
             directory /var/db/openldap
+            '''
           '';
       };
     };
@@ -87,7 +96,7 @@ in
         mkdir -p ${cfg.dataDir}
         chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}
       '';
-      serviceConfig.ExecStart = "${openldap.out}/libexec/slapd -u ${cfg.user} -g ${cfg.group} -d 0 -f ${configFile}";
+      serviceConfig.ExecStart = "${openldap.out}/libexec/slapd -u ${cfg.user} -g ${cfg.group} -d 0 -h \"${concatStringsSep " " cfg.urlList}\" -f ${configFile}";
     };
 
     users.extraUsers.openldap =
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index 6323d2c8ce4e..480e1184ffa3 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -68,6 +68,22 @@ in
         description = "The port for Redis to listen to.";
       };
 
+      vmOverCommit = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Set vm.overcommit_memory to 1 (Suggested for Background Saving: http://redis.io/topics/faq)
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to open ports in the firewall for the server.
+        '';
+      };
+
       bind = mkOption {
         type = with types; nullOr str;
         default = null; # All interfaces
@@ -193,6 +209,14 @@ in
 
   config = mkIf config.services.redis.enable {
 
+    boot.kernel.sysctl = mkIf cfg.vmOverCommit {
+      "vm.overcommit_memory" = "1";
+    };
+
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ cfg.port ];
+    };
+
     users.extraUsers.redis =
       { name = cfg.user;
         uid = config.ids.uids.redis;
diff --git a/nixos/modules/services/desktops/gnome3/gnome-keyring.nix b/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
index a8f1bcc28fbe..a36643a1cfb3 100644
--- a/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
+++ b/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
@@ -36,7 +36,7 @@ in
 
     environment.systemPackages = [ gnome3.gnome_keyring ];
 
-    services.dbus.packages = [ gnome3.gnome_keyring ];
+    services.dbus.packages = [ gnome3.gnome_keyring gnome3.gcr ];
 
   };
 
diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix
index 6e30dfb752d2..fa97e8bf746b 100644
--- a/nixos/modules/services/hardware/pcscd.nix
+++ b/nixos/modules/services/hardware/pcscd.nix
@@ -1,29 +1,51 @@
 { config, lib, pkgs, ... }:
 
+with lib;
+
 let
-  cfgFile = pkgs.writeText "reader.conf" "";
-in
+  cfgFile = pkgs.writeText "reader.conf" config.services.pcscd.readerConfig;
 
-with lib;
+  pluginEnv = pkgs.buildEnv {
+    name = "pcscd-plugins";
+    paths = map (p: "${p}/pcsc/drivers") config.services.pcscd.plugins;
+  };
 
-{
+in {
 
   ###### interface
 
   options = {
 
     services.pcscd = {
-
-      enable = mkOption {
-        default = false;
-        description = "Whether to enable the PCSC-Lite daemon.";
+      enable = mkEnableOption "PCSC-Lite daemon";
+
+      plugins = mkOption {
+        type = types.listOf types.package;
+        default = [ pkgs.ccid ];
+        defaultText = "[ pkgs.ccid ]";
+        example = literalExample "[ pkgs.pcsc-cyberjack ]";
+        description = "Plugin packages to be used for PCSC-Lite.";
       };
 
+      readerConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = ''
+          FRIENDLYNAME      "Some serial reader"
+          DEVICENAME        /dev/ttyS0
+          LIBPATH           /path/to/serial_reader.so
+          CHANNELID         1
+        '';
+        description = ''
+          Configuration for devices that aren't hotpluggable.
+
+          See <citerefentry><refentrytitle>reader.conf</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry> for valid options.
+        '';
+      };
     };
-
   };
 
-
   ###### implementation
 
   config = mkIf config.services.pcscd.enable {
@@ -37,18 +59,11 @@ with lib;
 
     systemd.services.pcscd = {
       description = "PCSC-Lite daemon";
-      preStart = ''
-          mkdir -p /var/lib/pcsc
-          rm -Rf /var/lib/pcsc/drivers
-          ln -s ${pkgs.ccid}/pcsc/drivers /var/lib/pcsc/
-      '';
+      environment.PCSCLITE_HP_DROPDIR = pluginEnv;
       serviceConfig = {
-        Type = "forking";
-        ExecStart = "${pkgs.pcsclite}/sbin/pcscd --auto-exit -c ${cfgFile}";
-        ExecReload = "${pkgs.pcsclite}/sbin/pcscd --hotplug";
+        ExecStart = "${pkgs.pcsclite}/sbin/pcscd -f -x -c ${cfgFile}";
+        ExecReload = "${pkgs.pcsclite}/sbin/pcscd -H";
       };
     };
-
   };
-
 }
diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix
index af996758f41f..f065208ddfc1 100644
--- a/nixos/modules/services/mail/opendkim.nix
+++ b/nixos/modules/services/mail/opendkim.nix
@@ -101,7 +101,7 @@ in {
       wantedBy = [ "multi-user.target" ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.opendkim}/bin/opendkim ${concatMapStringsSep " " escapeShellArg args}";
+        ExecStart = "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}";
         User = cfg.user;
         Group = cfg.group;
         RuntimeDirectory = optional (cfg.socket == defaultSock) "opendkim";
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index 42a1244cde57..e773cdedaea2 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -107,7 +107,16 @@ in {
       wantedBy = [ "multi-user.target" ];
       wants = [ "network.target" ];
       after = [ "network.target" ];
-      preStart = "mkdir -p /var/spool";
+      preStart = ''
+        mkdir -p /var/spool/smtpd
+
+        mkdir -p /var/spool/smtpd/offline
+        chown root.smtpq /var/spool/smtpd/offline
+        chmod 770 /var/spool/smtpd/offline
+
+        mkdir -p /var/spool/smtpd/purge
+        chmod 700 /var/spool/smtpd/purge
+      '';
       serviceConfig.ExecStart = "${opensmtpd}/sbin/smtpd -d -f ${conf} ${args}";
       environment.OPENSMTPD_PROC_PATH = "${procEnv}/libexec/opensmtpd";
     };
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index bad9d527f9a1..cdde41446224 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -127,11 +127,11 @@ let
     #               (yes)   (yes)   (no)    (never) (100)
     # ==========================================================================
     smtp      inet  n       -       n       -       -       smtpd
-    #submission inet n       -       n       -       -       smtpd
-    #  -o smtpd_tls_security_level=encrypt
-    #  -o smtpd_sasl_auth_enable=yes
-    #  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-    #  -o milter_macro_daemon_name=ORIGINATING
+  '' + optionalString cfg.enableSubmission ''
+    submission inet n       -       n       -       -       smtpd
+      ${concatStringsSep "\n  " (mapAttrsToList (x: y: "-o " + x + "=" + y) cfg.submissionOptions)}
+  ''
+  + ''
     pickup    unix  n       -       n       60      1       pickup
     cleanup   unix  n       -       n       -       0       cleanup
     qmgr      unix  n       -       n       300     1       qmgr
@@ -201,6 +201,28 @@ in
         default = true;
         description = "Whether to enable smtp in master.cf.";
       };
+      
+      enableSubmission = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable smtp submission";
+      };
+
+      submissionOptions = mkOption {
+        type = types.attrs;
+        default = { "smtpd_tls_security_level" = "encrypt";
+                    "smtpd_sasl_auth_enable" = "yes";
+                    "smtpd_client_restrictions" = "permit_sasl_authenticated,reject";
+                    "milter_macro_daemon_name" = "ORIGINATING";
+                  };
+        description = "Options for the submission config in master.cf";
+        example = { "smtpd_tls_security_level" = "encrypt";
+                    "smtpd_sasl_auth_enable" = "yes";
+                    "smtpd_sasl_type" = "dovecot";
+                    "smtpd_client_restrictions" = "permit_sasl_authenticated,reject";
+                    "milter_macro_daemon_name" = "ORIGINATING";
+                  };
+      };
 
       setSendmail = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix
index c0fbf06e6c4c..72ec68dee6b3 100644
--- a/nixos/modules/services/misc/confd.nix
+++ b/nixos/modules/services/misc/confd.nix
@@ -75,7 +75,7 @@ in {
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       serviceConfig = {
-        ExecStart = "${cfg.package}/bin/confd";
+        ExecStart = "${cfg.package.bin}/bin/confd";
       };
     };
 
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index 218802e0cf00..e5a125ad3245 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -36,49 +36,32 @@ in
         default = false;
         description = "Whether to enable the DisnixWebService interface running on Apache Tomcat";
       };
-
-      publishInfrastructure = {
-        enable = mkOption {
-          default = false;
-          description = "Whether to publish capabilities/properties of this machine in as attributes in the infrastructure option";
-        };
-
-        enableAuthentication = mkOption {
-          default = false;
-          description = "Whether to publish authentication credentials through the infrastructure attribute (not recommended in combination with Avahi)";
-        };
-      };
-
-      infrastructure = mkOption {
-        default = {};
-        description = "List of name value pairs containing properties for the infrastructure model";
-      };
-
-      publishAvahi = mkOption {
-        default = false;
-        description = "Whether to publish capabilities/properties as a Disnix service through Avahi";
+      
+      package = mkOption {
+        type = types.path;
+        description = "The Disnix package";
+        default = pkgs.disnix;
       };
 
     };
 
   };
 
-
   ###### implementation
 
   config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.disnix pkgs.dysnomia ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService;
+    dysnomia.enable = true;
+    
+    environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService;
 
     services.dbus.enable = true;
     services.dbus.packages = [ pkgs.disnix ];
 
-    services.avahi.enable = cfg.publishAvahi;
-
     services.tomcat.enable = cfg.useWebServiceInterface;
     services.tomcat.extraGroups = [ "disnix" ];
     services.tomcat.javaOpts = "${optionalString cfg.useWebServiceInterface "-Djava.library.path=${pkgs.libmatthew_java}/lib/jni"} ";
     services.tomcat.sharedLibs = optional cfg.useWebServiceInterface "${pkgs.DisnixWebService}/share/java/DisnixConnection.jar"
-                                 ++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar";
+      ++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar";
     services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService;
 
     users.extraGroups = singleton
@@ -86,38 +69,6 @@ in
         gid = config.ids.gids.disnix;
       };
 
-    services.disnix.infrastructure =
-      optionalAttrs (cfg.publishInfrastructure.enable)
-      ( { hostname = config.networking.hostName;
-          #targetHost = config.deployment.targetHost;
-          system = if config.nixpkgs.system == "" then builtins.currentSystem else config.nixpkgs.system;
-
-          supportedTypes = (import "${pkgs.stdenv.mkDerivation {
-            name = "supportedtypes";
-            buildCommand = ''
-              ( echo -n "[ "
-                cd ${dysnomia}/libexec/dysnomia
-                for i in *
-                do
-                    echo -n "\"$i\" "
-                done
-                echo -n " ]") > $out
-            '';
-          }}");
-        }
-        #// optionalAttrs (cfg.useWebServiceInterface) { targetEPR = "http://${config.deployment.targetHost}:8080/DisnixWebService/services/DisnixWebService"; }
-        // optionalAttrs (config.services.httpd.enable) { documentRoot = config.services.httpd.documentRoot; }
-        // optionalAttrs (config.services.mysql.enable) { mysqlPort = config.services.mysql.port; }
-        // optionalAttrs (config.services.tomcat.enable) { tomcatPort = 8080; }
-        // optionalAttrs (config.services.svnserve.enable) { svnBaseDir = config.services.svnserve.svnBaseDir; }
-        // optionalAttrs (config.services.ejabberd.enable) { ejabberdUser = config.services.ejabberd.user; }
-        // optionalAttrs (cfg.publishInfrastructure.enableAuthentication) (
-          optionalAttrs (config.services.mysql.enable) { mysqlUsername = "root"; mysqlPassword = readFile config.services.mysql.rootPassword; })
-        )
-    ;
-
-    services.disnix.publishInfrastructure.enable = cfg.publishAvahi;
-
     systemd.services = {
       disnix = {
         description = "Disnix server";
@@ -133,46 +84,17 @@ in
 
         restartIfChanged = false;
 
-        path = [ pkgs.nix pkgs.disnix dysnomia "/run/current-system/sw" ];
+        path = [ config.nix.package cfg.package config.dysnomia.package "/run/current-system/sw" ];
 
         environment = {
           HOME = "/root";
-        };
-
-        preStart = ''
-          mkdir -p /etc/systemd-mutable/system
-          if [ ! -f /etc/systemd-mutable/system/dysnomia.target ]
-          then
-              ( echo "[Unit]"
-                echo "Description=Services that are activated and deactivated by Dysnomia"
-                echo "After=final.target"
-              ) > /etc/systemd-mutable/system/dysnomia.target
-          fi
-        '';
-
-        script = "disnix-service";
+        }
+        // (if config.environment.variables ? DYSNOMIA_CONTAINERS_PATH then { inherit (config.environment.variables) DYSNOMIA_CONTAINERS_PATH; } else {})
+        // (if config.environment.variables ? DYSNOMIA_MODULES_PATH then { inherit (config.environment.variables) DYSNOMIA_MODULES_PATH; } else {});
+        
+        serviceConfig.ExecStart = "${cfg.package}/bin/disnix-service";
       };
-    } // optionalAttrs cfg.publishAvahi {
-      disnixAvahi = {
-        description = "Disnix Avahi publisher";
-        wants = [ "avahi-daemon.service" ];
-        wantedBy = [ "multi-user.target" ];
 
-        script = ''
-          ${pkgs.avahi}/bin/avahi-publish-service disnix-${config.networking.hostName} _disnix._tcp 22 \
-            "mem=$(grep 'MemTotal:' /proc/meminfo | sed -e 's/kB//' -e 's/MemTotal://' -e 's/ //g')" \
-            ${concatMapStrings (infrastructureAttrName:
-              let infrastructureAttrValue = getAttr infrastructureAttrName (cfg.infrastructure);
-              in
-              if isInt infrastructureAttrValue then
-              ''${infrastructureAttrName}=${toString infrastructureAttrValue} \
-              ''
-              else
-              ''${infrastructureAttrName}=\"${infrastructureAttrValue}\" \
-              ''
-              ) (attrNames (cfg.infrastructure))}
-        '';
-      };
     };
   };
 }
diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix
new file mode 100644
index 000000000000..df44d0a54866
--- /dev/null
+++ b/nixos/modules/services/misc/dysnomia.nix
@@ -0,0 +1,217 @@
+{pkgs, lib, config, ...}:
+
+with lib;
+
+let
+  cfg = config.dysnomia;
+  
+  printProperties = properties:
+    concatMapStrings (propertyName:
+      let
+        property = properties."${propertyName}";
+      in
+      if isList property then "${propertyName}=(${lib.concatMapStrings (elem: "\"${toString elem}\" ") (properties."${propertyName}")})\n"
+      else "${propertyName}=\"${toString property}\"\n"
+    ) (builtins.attrNames properties);
+  
+  properties = pkgs.stdenv.mkDerivation {
+    name = "dysnomia-properties";
+    buildCommand = ''
+      cat > $out << "EOF"
+      ${printProperties cfg.properties}
+      EOF
+    '';
+  };
+  
+  containersDir = pkgs.stdenv.mkDerivation {
+    name = "dysnomia-containers";
+    buildCommand = ''
+      mkdir -p $out
+      cd $out
+      
+      ${concatMapStrings (containerName:
+        let
+          containerProperties = cfg.containers."${containerName}";
+        in
+        ''
+          cat > ${containerName} <<EOF
+          ${printProperties containerProperties}
+          type=${containerName}
+          EOF
+        ''
+      ) (builtins.attrNames cfg.containers)}
+    '';
+  };
+  
+  linkMutableComponents = {containerName}:
+    ''
+      mkdir ${containerName}
+      
+      ${concatMapStrings (componentName:
+        let
+          component = cfg.components."${containerName}"."${componentName}";
+        in
+        "ln -s ${component} ${containerName}/${componentName}\n"
+      ) (builtins.attrNames (cfg.components."${containerName}" or {}))}
+    '';
+  
+  componentsDir = pkgs.stdenv.mkDerivation {
+    name = "dysnomia-components";
+    buildCommand = ''
+      mkdir -p $out
+      cd $out
+      
+      ${concatMapStrings (containerName:
+        let
+          components = cfg.components."${containerName}";
+        in
+        linkMutableComponents { inherit containerName; }
+      ) (builtins.attrNames cfg.components)}
+    '';
+  };
+in
+{
+  options = {
+    dysnomia = {
+      
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable Dysnomia";
+      };
+      
+      enableAuthentication = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to publish privacy-sensitive authentication credentials";
+      };
+      
+      package = mkOption {
+        type = types.path;
+        description = "The Dysnomia package";
+      };
+      
+      properties = mkOption {
+        description = "An attribute set in which each attribute represents a machine property. Optionally, these values can be shell substitutions.";
+        default = {};
+      };
+      
+      containers = mkOption {
+        description = "An attribute set in which each key represents a container and each value an attribute set providing its configuration properties";
+        default = {};
+      };
+      
+      components = mkOption {
+        description = "An atttribute set in which each key represents a container and each value an attribute set in which each key represents a component and each value a derivation constructing its initial state";
+        default = {};
+      };
+      
+      extraContainerProperties = mkOption {
+        description = "An attribute set providing additional container settings in addition to the default properties";
+        default = {};
+      };
+      
+      extraContainerPaths = mkOption {
+        description = "A list of paths containing additional container configurations that are added to the search folders";
+        default = [];
+      };
+      
+      extraModulePaths = mkOption {
+        description = "A list of paths containing additional modules that are added to the search folders";
+        default = [];
+      };
+    };
+  };
+  
+  config = mkIf cfg.enable {
+  
+    environment.etc = {
+      "dysnomia/containers" = {
+        source = containersDir;
+      };
+      "dysnomia/components" = {
+        source = componentsDir;
+      };
+      "dysnomia/properties" = {
+        source = properties;
+      };
+    };
+    
+    environment.variables = {
+      DYSNOMIA_STATEDIR = "/var/state/dysnomia-nixos";
+      DYSNOMIA_CONTAINERS_PATH = "${lib.concatMapStrings (containerPath: "${containerPath}:") cfg.extraContainerPaths}/etc/dysnomia/containers";
+      DYSNOMIA_MODULES_PATH = "${lib.concatMapStrings (modulePath: "${modulePath}:") cfg.extraModulePaths}/etc/dysnomia/modules";
+    };
+    
+    environment.systemPackages = [ cfg.package ];
+    
+    dysnomia.package = pkgs.dysnomia.override (origArgs: {
+      enableApacheWebApplication = config.services.httpd.enable;
+      enableAxis2WebService = config.services.tomcat.axis2.enable;
+      enableEjabberdDump = config.services.ejabberd.enable;
+      enableMySQLDatabase = config.services.mysql.enable;
+      enablePostgreSQLDatabase = config.services.postgresql.enable;
+      enableSubversionRepository = config.services.svnserve.enable;
+      enableTomcatWebApplication = config.services.tomcat.enable;
+      enableMongoDatabase = config.services.mongodb.enable;
+    });
+    
+    dysnomia.properties = {
+      hostname = config.networking.hostName;
+      system = if config.nixpkgs.system == "" then builtins.currentSystem else config.nixpkgs.system;
+
+      supportedTypes = (import "${pkgs.stdenv.mkDerivation {
+        name = "supportedtypes";
+        buildCommand = ''
+          ( echo -n "[ "
+            cd ${cfg.package}/libexec/dysnomia
+            for i in *
+            do
+                echo -n "\"$i\" "
+            done
+            echo -n " ]") > $out
+        '';
+      }}");
+    };
+    
+    dysnomia.containers = lib.recursiveUpdate ({
+      process = {};
+      wrapper = {};
+    }
+    // lib.optionalAttrs (config.services.httpd.enable) { apache-webapplication = {
+      documentRoot = config.services.httpd.documentRoot;
+    }; }
+    // lib.optionalAttrs (config.services.tomcat.axis2.enable) { axis2-webservice = {}; }
+    // lib.optionalAttrs (config.services.ejabberd.enable) { ejabberd-dump = {
+      ejabberdUser = config.services.ejabberd.user;
+    }; }
+    // lib.optionalAttrs (config.services.mysql.enable) { mysql-database = {
+        mysqlPort = config.services.mysql.port;
+      } // lib.optionalAttrs cfg.enableAuthentication {
+        mysqlUsername = "root";
+        mysqlPassword = builtins.readFile (config.services.mysql.rootPassword);
+      };
+    }
+    // lib.optionalAttrs (config.services.postgresql.enable && cfg.enableAuthentication) { postgresql-database = {
+      postgresqlUsername = "root";
+    }; }
+    // lib.optionalAttrs (config.services.tomcat.enable) { tomcat-webapplication = {
+      tomcatPort = 8080;
+    }; }
+    // lib.optionalAttrs (config.services.mongodb.enable) { mongo-database = {}; }
+    // lib.optionalAttrs (config.services.svnserve.enable) { subversion-repository = {
+      svnBaseDir = config.services.svnserve.svnBaseDir;
+    }; }) cfg.extraContainerProperties;
+
+    system.activationScripts.dysnomia = ''
+      mkdir -p /etc/systemd-mutable/system
+      if [ ! -f /etc/systemd-mutable/system/dysnomia.target ]
+      then
+          ( echo "[Unit]"
+            echo "Description=Services that are activated and deactivated by Dysnomia"
+            echo "After=final.target"
+          ) > /etc/systemd-mutable/system/dysnomia.target
+      fi
+    '';
+  };
+}
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix
index bc8064e3c879..0d6ed8eb9043 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -115,7 +115,7 @@ in {
 
       serviceConfig = {
         Type = "notify";
-        ExecStart = "${pkgs.etcd}/bin/etcd";
+        ExecStart = "${pkgs.etcd.bin}/bin/etcd";
         User = "etcd";
         PermissionsStartOnly = true;
       };
diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
index 0ae0516769c0..1a95e2d9367d 100644
--- a/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixos/modules/services/misc/matrix-synapse.nix
@@ -5,17 +5,31 @@ with lib;
 let
   cfg = config.services.matrix-synapse;
   logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig;
+  mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${if r.compress then "true" else "false"}}'';
+  mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${if l.tls then "true" else "false"}, x_forwarded: ${if l.x_forwarded then "true" else "false"}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}'';
   configFile = pkgs.writeText "homeserver.yaml" ''
 tls_certificate_path: "${cfg.tls_certificate_path}"
+${optionalString (cfg.tls_private_key_path != null) ''
 tls_private_key_path: "${cfg.tls_private_key_path}"
+''}
 tls_dh_params_path: "${cfg.tls_dh_params_path}"
 no_tls: ${if cfg.no_tls then "true" else "false"}
+${optionalString (cfg.bind_port != null) ''
 bind_port: ${toString cfg.bind_port}
+''}
+${optionalString (cfg.unsecure_port != null) ''
 unsecure_port: ${toString cfg.unsecure_port}
+''}
+${optionalString (cfg.bind_host != null) ''
 bind_host: "${cfg.bind_host}"
+''}
 server_name: "${cfg.server_name}"
 pid_file: "/var/run/matrix-synapse.pid"
 web_client: ${if cfg.web_client then "true" else "false"}
+${optionalString (cfg.public_baseurl != null) ''
+public_baseurl: "${cfg.public_baseurl}"
+''}
+listeners: [${concatStringsSep "," (map mkListener cfg.listeners)}]
 database: {
   name: "${cfg.database_type}",
   args: {
@@ -24,21 +38,41 @@ database: {
     )}
   }
 }
+event_cache_size: "${cfg.event_cache_size}"
+verbose: ${cfg.verbose}
 log_file: "/var/log/matrix-synapse/homeserver.log"
 log_config: "${logConfigFile}"
+rc_messages_per_second: ${cfg.rc_messages_per_second}
+rc_message_burst_count: ${cfg.rc_message_burst_count}
+federation_rc_window_size: ${cfg.federation_rc_window_size}
+federation_rc_sleep_limit: ${cfg.federation_rc_sleep_limit}
+federation_rc_sleep_delay: ${cfg.federation_rc_sleep_delay}
+federation_rc_reject_limit: ${cfg.federation_rc_reject_limit}
+federation_rc_concurrent: ${cfg.federation_rc_concurrent}
 media_store_path: "/var/lib/matrix-synapse/media"
+uploads_path: "/var/lib/matrix-synapse/uploads"
+max_upload_size: "${cfg.max_upload_size}"
+max_image_pixels: "${cfg.max_image_pixels}"
+dynamic_thumbnails: ${if cfg.dynamic_thumbnails then "true" else "false"}
+url_preview_enabled: False
 recaptcha_private_key: "${cfg.recaptcha_private_key}"
 recaptcha_public_key: "${cfg.recaptcha_public_key}"
 enable_registration_captcha: ${if cfg.enable_registration_captcha then "true" else "false"}
-turn_uris: ${if (length cfg.turn_uris) == 0 then "[]" else ("\n" + (concatStringsSep "\n" (map (s: "- " + s) cfg.turn_uris)))}
+turn_uris: ${builtins.toJSON cfg.turn_uris}
 turn_shared_secret: "${cfg.turn_shared_secret}"
 enable_registration: ${if cfg.enable_registration then "true" else "false"}
-${optionalString (cfg.registration_shared_secret != "") ''
+${optionalString (cfg.registration_shared_secret != null) ''
 registration_shared_secret: "${cfg.registration_shared_secret}"
 ''}
+recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify"
+turn_user_lifetime: "${cfg.turn_user_lifetime}"
+user_creation_max_duration: ${cfg.user_creation_max_duration}
+bcrypt_rounds: ${cfg.bcrypt_rounds}
+allow_guest_access: {if cfg.allow_guest_access then "true" else "false"}
 enable_metrics: ${if cfg.enable_metrics then "true" else "false"}
 report_stats: ${if cfg.report_stats then "true" else "false"}
 signing_key_path: "/var/lib/matrix-synapse/homeserver.signing.key"
+key_refresh_interval: "${cfg.key_refresh_interval}"
 perspectives:
   servers: {
     ${concatStringsSep "},\n" (mapAttrsToList (n: v: ''
@@ -52,6 +86,8 @@ perspectives:
     '') cfg.servers)}
     }
   }
+app_service_config_files: ${builtins.toJSON cfg.app_service_config_files}
+
 ${cfg.extraConfig}
 '';
 in {
@@ -73,53 +109,65 @@ in {
           Don't bind to the https port
         '';
       };
-      tls_certificate_path = mkOption {
-        type = types.path;
-        default = "/var/lib/matrix-synapse/homeserver.tls.crt";
+      bind_port = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 8448;
         description = ''
-          PEM encoded X509 certificate for TLS
+          DEPRECATED: Use listeners instead.
+          The port to listen for HTTPS requests on.
+          For when matrix traffic is sent directly to synapse.
         '';
       };
-      tls_private_key_path = mkOption {
-        type = types.path;
-        default = "/var/lib/matrix-synapse/homeserver.tls.key";
+      unsecure_port = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 8008;
         description = ''
-          PEM encoded private key for TLS
+          DEPRECATED: Use listeners instead.
+          The port to listen for HTTP requests on.
+          For when matrix traffic passes through loadbalancer that unwraps TLS.
         '';
       };
-      tls_dh_params_path = mkOption {
-        type = types.path;
-        default = "/var/lib/matrix-synapse/homeserver.tls.dh";
+      bind_host = mkOption {
+        type = types.nullOr types.str;
+        default = null;
         description = ''
-          PEM dh parameters for ephemeral keys
+          DEPRECATED: Use listeners instead.
+          Local interface to listen on.
+          The empty string will cause synapse to listen on all interfaces.
         '';
       };
-      bind_port = mkOption {
-        type = types.int;
-        default = 8448;
+      tls_certificate_path = mkOption {
+        type = types.str;
+        default = "/var/lib/matrix-synapse/homeserver.tls.crt";
         description = ''
-          The port to listen for HTTPS requests on.
-          For when matrix traffic is sent directly to synapse.
+          PEM encoded X509 certificate for TLS.
+          You can replace the self-signed certificate that synapse
+          autogenerates on launch with your own SSL certificate + key pair
+          if you like.  Any required intermediary certificates can be
+          appended after the primary certificate in hierarchical order.
         '';
       };
-      unsecure_port = mkOption {
-        type = types.int;
-        default = 8008;
+      tls_private_key_path = mkOption {
+        type = types.nullOr types.str;
+        default = "/var/lib/matrix-synapse/homeserver.tls.key";
+        example = null;
         description = ''
-          The port to listen for HTTP requests on.
-          For when matrix traffic passes through loadbalancer that unwraps TLS.
+          PEM encoded private key for TLS. Specify null if synapse is not
+          speaking TLS directly.
         '';
       };
-      bind_host = mkOption {
+      tls_dh_params_path = mkOption {
         type = types.str;
-        default = "";
+        default = "/var/lib/matrix-synapse/homeserver.tls.dh";
         description = ''
-          Local interface to listen on.
-          The empty string will cause synapse to listen on all interfaces.
+          PEM dh parameters for ephemeral keys
         '';
       };
       server_name = mkOption {
         type = types.str;
+        example = "example.com";
         description = ''
           The domain name of the server, with optional explicit port.
           This is used by remote servers to connect to this server,
@@ -134,6 +182,145 @@ in {
           Whether to serve a web client from the HTTP/HTTPS root resource.
         '';
       };
+      public_baseurl = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "https://example.com:8448/";
+        description = ''
+          The public-facing base URL for the client API (not including _matrix/...)
+        '';
+      };
+      listeners = mkOption {
+        type = types.listOf (types.submodule {
+          options = {
+            port = mkOption {
+              type = types.int;
+              example = 8448;
+              description = ''
+                The port to listen for HTTP(S) requests on.
+              '';
+            };
+            bind_address = mkOption {
+              type = types.str;
+              default = "";
+              example = "203.0.113.42";
+              description = ''
+                Local interface to listen on.
+                The empty string will cause synapse to listen on all interfaces.
+              '';
+            };
+            type = mkOption {
+              type = types.str;
+              default = "http";
+              description = ''
+                Type of listener.
+              '';
+            };
+            tls = mkOption {
+              type = types.bool;
+              default = true;
+              description = ''
+                Whether to listen for HTTPS connections rather than HTTP.
+              '';
+            };
+            x_forwarded = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Use the X-Forwarded-For (XFF) header as the client IP and not the
+                actual client IP.
+              '';
+            };
+            resources = mkOption {
+              type = types.listOf (types.submodule {
+                options = {
+                  names = mkOption {
+                    type = types.listOf types.str;
+                    description = ''
+                      List of resources to host on this listener.
+                    '';
+                    example = ["client" "webclient" "federation"];
+                  };
+                  compress = mkOption {
+                    type = types.bool;
+                    description = ''
+                      Should synapse compress HTTP responses to clients that support it?
+                      This should be disabled if running synapse behind a load balancer
+                      that can do automatic compression.
+                    '';
+                  };
+                };
+              });
+              description = ''
+                List of HTTP resources to serve on this listener.
+              '';
+            };
+          };
+        });
+        default = [{
+          port = 8448;
+          bind_address = "";
+          type = "http";
+          tls = true;
+          x_forwarded = false;
+          resources = [
+            { names = ["client" "webclient"]; compress = true; }
+            { names = ["federation"]; compress = false; }
+          ];
+        }];
+        description = ''
+          List of ports that Synapse should listen on, their purpose and their configuration.
+        '';
+      };
+      verbose = mkOption {
+        type = types.str;
+        default = "0";
+        description = "Logging verbosity level.";
+      };
+      rc_messages_per_second = mkOption {
+        type = types.str;
+        default = "0.2";
+        description = "Number of messages a client can send per second";
+      };
+      rc_message_burst_count = mkOption {
+        type = types.str;
+        default = "10.0";
+        description = "Number of message a client can send before being throttled";
+      };
+      federation_rc_window_size = mkOption {
+        type = types.str;
+        default = "1000";
+        description = "The federation window size in milliseconds";
+      };
+      federation_rc_sleep_limit = mkOption {
+        type = types.str;
+        default = "10";
+        description = ''
+          The number of federation requests from a single server in a window
+          before the server will delay processing the request.
+        '';
+      };
+      federation_rc_sleep_delay = mkOption {
+        type = types.str;
+        default = "500";
+        description = ''
+          The duration in milliseconds to delay processing events from
+          remote servers by if they go over the sleep limit.
+        '';
+      };
+      federation_rc_reject_limit = mkOption {
+        type = types.str;
+        default = "50";
+        description = ''
+          The maximum number of concurrent federation requests allowed
+          from a single server
+        '';
+      };
+      federation_rc_concurrent = mkOption {
+        type = types.str;
+        default = "3";
+        description = "The number of federation requests to concurrently process from a single server";
+      };
       database_type = mkOption {
         type = types.enum [ "sqlite3" "psycopg2" ];
         default = "sqlite3";
@@ -150,6 +337,11 @@ in {
           Arguments to pass to the engine.
         '';
       };
+      event_cache_size = mkOption {
+        type = types.str;
+        default = "10K";
+        description = "Number of events to cache in memory.";
+      };
       recaptcha_private_key = mkOption {
         type = types.str;
         default = "";
@@ -187,6 +379,11 @@ in {
           The shared secret used to compute passwords for the TURN server
         '';
       };
+      turn_user_lifetime = mkOption {
+        type = types.str;
+        default = "1h";
+        description = "How long generated TURN credentials last";
+      };
       enable_registration = mkOption {
         type = types.bool;
         default = false;
@@ -195,8 +392,8 @@ in {
         '';
       };
       registration_shared_secret = mkOption {
-        type = types.str;
-        default = "";
+        type = types.nullOr types.str;
+        default = null;
         description = ''
           If set, allows registration by anyone who also has the shared
           secret, even if registration is otherwise disabled.
@@ -216,7 +413,7 @@ in {
         '';
       };
       servers = mkOption {
-        type = types.attrs;
+        type = types.attrsOf (types.attrsOf types.str);
         default = {
           "matrix.org" = {
             "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
@@ -226,6 +423,69 @@ in {
           The trusted servers to download signing keys from.
         '';
       };
+      max_upload_size = mkOption {
+        type = types.str;
+        default = "10M";
+        description = "The largest allowed upload size in bytes";
+      };
+      max_image_pixels = mkOption {
+        type = types.str;
+        default = "32M";
+        description = "Maximum number of pixels that will be thumbnailed";
+      };
+      dynamic_thumbnails = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to generate new thumbnails on the fly to precisely match
+          the resolution requested by the client. If true then whenever
+          a new resolution is requested by the client the server will
+          generate a new thumbnail. If false the server will pick a thumbnail
+          from a precalculated list.
+        '';
+      };
+      user_creation_max_duration = mkOption {
+        type = types.str;
+        default = "1209600000";
+        description = ''
+          Sets the expiry for the short term user creation in
+          milliseconds. The default value is two weeks.
+        '';
+      };
+      bcrypt_rounds = mkOption {
+        type = types.str;
+        default = "12";
+        description = ''
+          Set the number of bcrypt rounds used to generate password hash.
+          Larger numbers increase the work factor needed to generate the hash.
+        '';
+      };
+      allow_guest_access = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Allows users to register as guests without a password/email/etc, and
+          participate in rooms hosted on this server which have been made
+          accessible to anonymous users.
+        '';
+      };
+      key_refresh_interval = mkOption {
+        type = types.str;
+        default = "1d";
+        description = ''
+          How long key response published by this server is valid for.
+          Used to set the valid_until_ts in /key/v2 APIs.
+          Determines how quickly servers will query to check which keys
+          are still valid.
+        '';
+      };
+      app_service_config_files = mkOption {
+        type = types.listOf types.path;
+        default = [ ];
+        description = ''
+          A list of application service config file to use
+        '';
+      };
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -265,7 +525,7 @@ in {
         mkdir -p /var/lib/matrix-synapse
         chmod 700 /var/lib/matrix-synapse
         chown -R matrix-synapse:matrix-synapse /var/lib/matrix-synapse
-        ${cfg.package}/bin/homeserver --config-path ${configFile} --generate-keys
+        ${cfg.package}/bin/homeserver --config-path ${configFile} --keys-directory /var/lib/matrix-synapse/ --generate-keys
       '';
       serviceConfig = {
         Type = "simple";
diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix
index ea97d6e30e83..0844190a5490 100644
--- a/nixos/modules/services/misc/parsoid.nix
+++ b/nixos/modules/services/misc/parsoid.nix
@@ -91,7 +91,7 @@ in
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       serviceConfig = {
-        ExecStart = "${pkgs.nodePackages_0_10.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}";
+        ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}";
       };
     };
 
diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix
index b7d14e90a2b7..c846ffd04551 100644
--- a/nixos/modules/services/misc/taskserver/default.nix
+++ b/nixos/modules/services/misc/taskserver/default.nix
@@ -152,8 +152,6 @@ let
     };
   };
 
-  mkShellStr = val: "'${replaceStrings ["'"] ["'\\''"] val}'";
-
   certtool = "${pkgs.gnutls.bin}/bin/certtool";
 
   nixos-taskserver = pkgs.buildPythonPackage {
diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix
index 51d38e8db4de..9a1e790d3ab6 100644
--- a/nixos/modules/services/monitoring/bosun.nix
+++ b/nixos/modules/services/monitoring/bosun.nix
@@ -148,7 +148,7 @@ in {
         User = cfg.user;
         Group = cfg.group;
         ExecStart = ''
-          ${cfg.package}/bin/bosun -c ${configFile}
+          ${cfg.package.bin}/bin/bosun -c ${configFile}
         '';
       };
     };
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index defbd9289dcd..0b7f3ce0a29b 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -228,7 +228,7 @@ in {
       after = ["networking.target"];
       environment = mapAttrs' (n: v: nameValuePair "GF_${n}" (toString v)) envOptions;
       serviceConfig = {
-        ExecStart = "${cfg.package}/bin/grafana-server -homepath ${cfg.dataDir}";
+        ExecStart = "${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir}";
         WorkingDirectory = cfg.dataDir;
         User = "grafana";
       };
diff --git a/nixos/modules/services/monitoring/scollector.nix b/nixos/modules/services/monitoring/scollector.nix
index 1e397435e600..2684482c6184 100644
--- a/nixos/modules/services/monitoring/scollector.nix
+++ b/nixos/modules/services/monitoring/scollector.nix
@@ -119,7 +119,7 @@ in {
         PermissionsStartOnly = true;
         User = cfg.user;
         Group = cfg.group;
-        ExecStart = "${cfg.package}/bin/scollector -conf=${conf} ${lib.concatStringsSep " " cfg.extraOpts}";
+        ExecStart = "${cfg.package.bin}/bin/scollector -conf=${conf} ${lib.concatStringsSep " " cfg.extraOpts}";
       };
     };
 
diff --git a/nixos/modules/services/network-filesystems/diod.nix b/nixos/modules/services/network-filesystems/diod.nix
index 7de7acaa4a08..556fad4d8ab4 100644
--- a/nixos/modules/services/network-filesystems/diod.nix
+++ b/nixos/modules/services/network-filesystems/diod.nix
@@ -153,7 +153,7 @@ in
       after = [ "network.target" ];
       serviceConfig = {
         ExecStart = "${pkgs.diod}/sbin/diod -f -c ${diodConfig}";
-        Capabilities = "cap_net_bind_service+=ep";
+        CapabilityBoundingSet = "cap_net_bind_service+=ep";
       };
     };
   };
diff --git a/nixos/modules/services/networking/chrony.nix b/nixos/modules/services/networking/chrony.nix
index 1cd678e7c621..a38142b4a08f 100644
--- a/nixos/modules/services/networking/chrony.nix
+++ b/nixos/modules/services/networking/chrony.nix
@@ -64,7 +64,7 @@ in
 
   ###### implementation
 
-  config = mkIf config.services.chrony.enable {
+  config = mkIf cfg.enable {
 
     # Make chronyc available in the system path
     environment.systemPackages = [ pkgs.chrony ];
@@ -101,12 +101,14 @@ in
         home = stateDir;
       };
 
-    systemd.services.ntpd.enable = false;
+    systemd.services.ntpd.enable = mkForce false;
 
     systemd.services.chronyd =
       { description = "chrony NTP daemon";
 
         wantedBy = [ "multi-user.target" ];
+        wants = [ "time-sync.target" ];
+        before = [ "time-sync.target" ];
         after = [ "network.target" ];
         conflicts = [ "ntpd.service" "systemd-timesyncd.service" ];
 
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 2aa101f980da..166ee7732375 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -178,14 +178,14 @@ in
             (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc);
 
         serviceConfig = {
-          ExecStart = "@${cfg.package}/bin/consul consul agent -config-dir /etc/consul.d"
+          ExecStart = "@${cfg.package.bin}/bin/consul consul agent -config-dir /etc/consul.d"
             + concatMapStrings (n: " -config-file ${n}") configFiles;
-          ExecReload = "${cfg.package}/bin/consul reload";
+          ExecReload = "${cfg.package.bin}/bin/consul reload";
           PermissionsStartOnly = true;
           User = if cfg.dropPrivileges then "consul" else null;
           TimeoutStartSec = "0";
         } // (optionalAttrs (cfg.leaveOnStop) {
-          ExecStop = "${cfg.package}/bin/consul leave";
+          ExecStop = "${cfg.package.bin}/bin/consul leave";
         });
 
         path = with pkgs; [ iproute gnugrep gawk consul ];
@@ -236,7 +236,7 @@ in
 
         serviceConfig = {
           ExecStart = ''
-            ${cfg.alerts.package}/bin/consul-alerts start \
+            ${cfg.alerts.package.bin}/bin/consul-alerts start \
               --alert-addr=${cfg.alerts.listenAddr} \
               --consul-addr=${cfg.alerts.consulAddr} \
               ${optionalString cfg.alerts.watchChecks "--watch-checks"} \
diff --git a/nixos/modules/services/networking/coturn.nix b/nixos/modules/services/networking/coturn.nix
new file mode 100644
index 000000000000..14e6932d868b
--- /dev/null
+++ b/nixos/modules/services/networking/coturn.nix
@@ -0,0 +1,327 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.coturn;
+  pidfile = "/run/turnserver/turnserver.pid";
+  configFile = pkgs.writeText "turnserver.conf" ''
+listening-port=${toString cfg.listening-port}
+tls-listening-port=${toString cfg.tls-listening-port}
+alt-listening-port=${toString cfg.alt-listening-port}
+alt-tls-listening-port=${toString cfg.alt-tls-listening-port}
+${concatStringsSep "\n" (map (x: "listening-ip=${x}") cfg.listening-ips)}
+${concatStringsSep "\n" (map (x: "relay-ip=${x}") cfg.relay-ips)}
+min-port=${toString cfg.min-port}
+max-port=${toString cfg.max-port}
+${lib.optionalString cfg.lt-cred-mech "lt-cred-mech"}
+${lib.optionalString cfg.no-auth "no-auth"}
+${lib.optionalString cfg.use-auth-secret "use-auth-secret"}
+${lib.optionalString (cfg.static-auth-secret != null) ("static-auth-secret=${cfg.static-auth-secret}")}
+realm=${cfg.realm}
+${lib.optionalString cfg.no-udp "no-udp"}
+${lib.optionalString cfg.no-tcp "no-tcp"}
+${lib.optionalString cfg.no-tls "no-tls"}
+${lib.optionalString cfg.no-dtls "no-dtls"}
+${lib.optionalString cfg.no-udp-relay "no-udp-relay"}
+${lib.optionalString cfg.no-tcp-relay "no-tcp-relay"}
+${lib.optionalString (cfg.cert != null) "cert=${cfg.cert}"}
+${lib.optionalString (cfg.pkey != null) "pkey=${cfg.pkey}"}
+${lib.optionalString (cfg.dh-file != null) ("dh-file=${cfg.dh-file}")}
+no-stdout-log
+syslog
+pidfile=${pidfile}
+${lib.optionalString cfg.secure-stun "secure-stun"}
+${lib.optionalString cfg.no-cli "no-cli"}
+cli-ip=${cfg.cli-ip}
+cli-port=${toString cfg.cli-port}
+${lib.optionalString (cfg.cli-password != null) ("cli-password=${cfg.cli-password}")}
+${cfg.extraConfig}
+'';
+in {
+  options = {
+    services.coturn = {
+      enable = mkEnableOption "coturn TURN server";
+      listening-port = mkOption {
+        type = types.int;
+        default = 3478;
+        description = ''
+          TURN listener port for UDP and TCP.
+          Note: actually, TLS and DTLS sessions can connect to the
+          "plain" TCP and UDP port(s), too - if allowed by configuration.
+        '';
+      };
+      tls-listening-port = mkOption {
+        type = types.int;
+        default = 5349;
+        description = ''
+          TURN listener port for TLS.
+          Note: actually, "plain" TCP and UDP sessions can connect to the TLS and
+          DTLS port(s), too - if allowed by configuration. The TURN server
+          "automatically" recognizes the type of traffic. Actually, two listening
+          endpoints (the "plain" one and the "tls" one) are equivalent in terms of
+          functionality; but we keep both endpoints to satisfy the RFC 5766 specs.
+          For secure TCP connections, we currently support SSL version 3 and
+          TLS version 1.0, 1.1 and 1.2.
+          For secure UDP connections, we support DTLS version 1.
+        '';
+      };
+      alt-listening-port = mkOption {
+        type = types.int;
+        default = cfg.listening-port + 1;
+        defaultText = "listening-port + 1";
+        description = ''
+          Alternative listening port for UDP and TCP listeners;
+          default (or zero) value means "listening port plus one".
+          This is needed for RFC 5780 support
+          (STUN extension specs, NAT behavior discovery). The TURN Server
+          supports RFC 5780 only if it is started with more than one
+          listening IP address of the same family (IPv4 or IPv6).
+          RFC 5780 is supported only by UDP protocol, other protocols
+          are listening to that endpoint only for "symmetry".
+        '';
+      };
+      alt-tls-listening-port = mkOption {
+        type = types.int;
+        default = cfg.tls-listening-port + 1;
+        defaultText = "tls-listening-port + 1";
+        description = ''
+          Alternative listening port for TLS and DTLS protocols.
+        '';
+      };
+      listening-ips = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "203.0.113.42" "2001:DB8::42" ];
+        description = ''
+          Listener IP addresses of relay server.
+          If no IP(s) specified in the config file or in the command line options,
+          then all IPv4 and IPv6 system IPs will be used for listening.
+        '';
+      };
+      relay-ips = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "203.0.113.42" "2001:DB8::42" ];
+        description = ''
+          Relay address (the local IP address that will be used to relay the
+          packets to the peer).
+          Multiple relay addresses may be used.
+          The same IP(s) can be used as both listening IP(s) and relay IP(s).
+
+          If no relay IP(s) specified, then the turnserver will apply the default
+          policy: it will decide itself which relay addresses to be used, and it
+          will always be using the client socket IP address as the relay IP address
+          of the TURN session (if the requested relay address family is the same
+          as the family of the client socket).
+        '';
+      };
+      min-port = mkOption {
+        type = types.int;
+        default = 49152;
+        description = ''
+          Lower bound of UDP relay endpoints
+        '';
+      };
+      max-port = mkOption {
+        type = types.int;
+        default = 65535;
+        description = ''
+          Upper bound of UDP relay endpoints
+        '';
+      };
+      lt-cred-mech = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Use long-term credential mechanism.
+        '';
+      };
+      no-auth = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          This option is opposite to lt-cred-mech.
+          (TURN Server with no-auth option allows anonymous access).
+          If neither option is defined, and no users are defined,
+          then no-auth is default. If at least one user is defined,
+          in this file or in command line or in usersdb file, then
+          lt-cred-mech is default.
+        '';
+      };
+      use-auth-secret = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          TURN REST API flag.
+          Flag that sets a special authorization option that is based upon authentication secret.
+          This feature can be used with the long-term authentication mechanism, only.
+          This feature purpose is to support "TURN Server REST API", see
+          "TURN REST API" link in the project's page
+          https://github.com/coturn/coturn/
+
+          This option is used with timestamp:
+
+          usercombo -> "timestamp:userid"
+          turn user -> usercombo
+          turn password -> base64(hmac(secret key, usercombo))
+
+          This allows TURN credentials to be accounted for a specific user id.
+          If you don't have a suitable id, the timestamp alone can be used.
+          This option is just turning on secret-based authentication.
+          The actual value of the secret is defined either by option static-auth-secret,
+          or can be found in the turn_secret table in the database.
+        '';
+      };
+      static-auth-secret = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          'Static' authentication secret value (a string) for TURN REST API only.
+          If not set, then the turn server
+          will try to use the 'dynamic' value in turn_secret table
+          in user database (if present). The database-stored  value can be changed on-the-fly
+          by a separate program, so this is why that other mode is 'dynamic'.
+        '';
+      };
+      realm = mkOption {
+        type = types.str;
+        default = config.networking.hostName;
+        example = "example.com";
+        description = ''
+          The default realm to be used for the users when no explicit
+          origin/realm relationship was found in the database, or if the TURN
+          server is not using any database (just the commands-line settings
+          and the userdb file). Must be used with long-term credentials
+          mechanism or with TURN REST API.
+        '';
+      };
+      cert = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "/var/lib/acme/example.com/fullchain.pem";
+        description = ''
+          Certificate file in PEM format.
+        '';
+      };
+      pkey = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "/var/lib/acme/example.com/key.pem";
+        description = ''
+          Private key file in PEM format.
+        '';
+      };
+      dh-file = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Use custom DH TLS key, stored in PEM format in the file.
+        '';
+      };
+      secure-stun = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Require authentication of the STUN Binding request.
+          By default, the clients are allowed anonymous access to the STUN Binding functionality.
+        '';
+      };
+      no-cli = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Turn OFF the CLI support.
+        '';
+      };
+      cli-ip = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = ''
+          Local system IP address to be used for CLI server endpoint.
+        '';
+      };
+      cli-port = mkOption {
+        type = types.int;
+        default = 5766;
+        description = ''
+          CLI server port.
+        '';
+      };
+      cli-password = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          CLI access password.
+          For the security reasons, it is recommended to use the encrypted
+          for of the password (see the -P command in the turnadmin utility).
+        '';
+      };
+      no-udp = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Disable UDP client listener";
+      };
+      no-tcp = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Disable TCP client listener";
+      };
+      no-tls = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Disable TLS client listener";
+      };
+      no-dtls = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Disable DTLS client listener";
+      };
+      no-udp-relay = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Disable UDP relay endpoints";
+      };
+      no-tcp-relay = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Disable TCP relay endpoints";
+      };
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Additional configuration options";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers = [
+      { name = "turnserver";
+        uid = config.ids.uids.turnserver;
+        description = "coturn TURN server user";
+      } ];
+    users.extraGroups = [
+      { name = "turnserver";
+        gid = config.ids.gids.turnserver;
+        members = [ "turnserver" ];
+      } ];
+
+    systemd.services.coturn = {
+      description = "coturn TURN server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      unitConfig = {
+        Documentation = "man:coturn(1) man:turnadmin(1) man:turnserver(1)";
+      };
+
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${pkgs.coturn}/bin/turnserver -c ${configFile}";
+        RuntimeDirectory = "turnserver";
+        User = "turnserver";
+        Group = "turnserver";
+        Restart = "on-abort";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index bb0dc756ba47..227e38acc4a6 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -89,8 +89,8 @@ in
         '';
         example = literalExample "${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv";
         default = pkgs.fetchurl {
-          url = "https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv";
-          sha256 = "07kbbisrvrqdxif3061hxj3whin3llg4nh50ln7prisi2vbd76xd";
+          url = https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv;
+          sha256 = "171zvdqcqqvcw3zr7wl9h1wmdmk6m3h55xr4gq2z1j7a0x0ba2in";
         };
         defaultText = "pkgs.fetchurl { url = ...; sha256 = ...; }";
       };
diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix
index 9868f303ab2b..8ecc16257db8 100644
--- a/nixos/modules/services/networking/ejabberd.nix
+++ b/nixos/modules/services/networking/ejabberd.nix
@@ -13,7 +13,7 @@ let
 
   ectl = ''${cfg.package}/bin/ejabberdctl ${if cfg.configFile == null then "" else "--config ${cfg.configFile}"} --ctl-config "${ctlcfg}" --spool "${cfg.spoolDir}" --logs "${cfg.logsDir}"'';
 
-  dumps = lib.concatMapStringsSep " " lib.escapeShellArg cfg.loadDumps;
+  dumps = lib.escapeShellArgs cfg.loadDumps;
 
 in {
 
diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix
new file mode 100644
index 000000000000..f926cd710c8d
--- /dev/null
+++ b/nixos/modules/services/networking/mosquitto.nix
@@ -0,0 +1,219 @@
+{ config, lib, pkgs, ...}:
+
+with lib;
+
+let
+  cfg = config.services.mosquitto;
+
+  listenerConf = optionalString cfg.ssl.enable ''
+    listener ${toString cfg.ssl.port} ${cfg.ssl.host}
+    cafile ${cfg.ssl.cafile}
+    certfile ${cfg.ssl.certfile}
+    keyfile ${cfg.ssl.keyfile}
+  '';
+
+  mosquittoConf = pkgs.writeText "mosquitto.conf" ''
+    pid_file /run/mosquitto/pid
+    acl_file ${aclFile}
+    persistence true
+    allow_anonymous ${if cfg.allowAnonymous then "true" else "false"}
+    bind_address ${cfg.host}
+    port ${toString cfg.port}
+    ${listenerConf}
+    ${cfg.extraConf}
+  '';
+
+  userAcl = (concatStringsSep "\n\n" (mapAttrsToList (n: c:
+    "user ${n}\n" + (concatStringsSep "\n" c.acl)) cfg.users
+  ));
+
+  aclFile = pkgs.writeText "mosquitto.acl" ''
+    ${cfg.aclExtraConf}
+    ${userAcl}
+  '';
+
+in
+
+{
+
+  ###### Interface
+
+  options = {
+    services.mosquitto = {
+      enable = mkEnableOption "Enable the MQTT Mosquitto broker.";
+
+      host = mkOption {
+        default = "127.0.0.1";
+        example = "0.0.0.0";
+        type = types.string;
+        description = ''
+          Host to listen on without SSL.
+        '';
+      };
+
+      port = mkOption {
+        default = 1883;
+        example = 1883;
+        type = types.int;
+        description = ''
+          Port on which to listen without SSL.
+        '';
+      };
+
+      ssl = {
+        enable = mkEnableOption "Enable SSL listener.";
+
+        cafile = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          description = "Path to PEM encoded CA certificates.";
+        };
+
+        certfile = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          description = "Path to PEM encoded server certificate.";
+        };
+
+        keyfile = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          description = "Path to PEM encoded server key.";
+        };
+
+        host = mkOption {
+          default = "0.0.0.0";
+          example = "localhost";
+          type = types.string;
+          description = ''
+            Host to listen on with SSL.
+          '';
+        };
+
+        port = mkOption {
+          default = 8883;
+          example = 8883;
+          type = types.int;
+          description = ''
+            Port on which to listen with SSL.
+          '';
+        };
+      };
+
+      dataDir = mkOption {
+        default = "/var/lib/mosquitto";
+        type = types.path;
+        description = ''
+          The data directory.
+        '';
+      };
+
+      users = mkOption {
+        type = types.attrsOf (types.submodule {
+          options = {
+            password = mkOption {
+              type = with types; uniq (nullOr str);
+              default = null;
+              description = ''
+                Specifies the (clear text) password for the MQTT User.
+              '';
+            };
+
+            hashedPassword = mkOption {
+              type = with types; uniq (nullOr str);
+              default = null;
+              description = ''
+                Specifies the hashed password for the MQTT User.
+                <option>hashedPassword</option> overrides <option>password</option>.
+                To generate hashed password install <literal>mkpasswd</literal>
+                package and run <literal>mkpasswd -m sha-512</literal>.
+              '';
+            };
+
+            acl = mkOption {
+              type = types.listOf types.string;
+              example = [ "topic read A/B" "topic A/#" ];
+              description = ''
+                Control client access to topics on the broker.
+              '';
+            };
+          };
+        });
+        example = { john = { password = "123456"; acl = [ "topic readwrite john/#" ]; }; };
+        description = ''
+          A set of users and their passwords and ACLs.
+        '';
+      };
+
+      allowAnonymous = mkOption {
+        default = false;
+        example = true;
+        type = types.bool;
+        description = ''
+          Allow clients to connect without authentication.
+        '';
+      };
+
+      extraConf = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Extra config to append to `mosquitto.conf` file.
+        '';
+      };
+
+      aclExtraConf = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Extra config to prepend to the ACL file.
+        '';
+      };
+
+    };
+  };
+
+
+  ###### Implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.mosquitto = {
+      description = "Mosquitto MQTT Broker Daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        Type = "forking";
+        User = "mosquitto";
+        Group = "mosquitto";
+        RuntimeDirectory = "mosquitto";
+        WorkingDirectory = cfg.dataDir;
+        Restart = "on-failure";
+        ExecStart = "${pkgs.mosquitto}/bin/mosquitto -c ${mosquittoConf} -d";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        PIDFile = "/run/mosquitto/pid";
+      };
+      preStart = ''
+        rm -f ${cfg.dataDir}/passwd
+        touch ${cfg.dataDir}/passwd
+      '' + concatStringsSep "\n" (
+        mapAttrsToList (n: c:
+          if c.hashedPassword != null then
+            "echo '${n}:${c.hashedPassword}' > ${cfg.dataDir}/passwd"
+          else optionalString (c.password != null)
+            "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} ${c.password}"
+        ) cfg.users);
+    };
+
+    users.extraUsers.mosquitto = {
+      description = "Mosquitto MQTT Broker Daemon owner";
+      group = "mosquitto";
+      uid = config.ids.uids.mosquitto;
+      home = cfg.dataDir;
+      createHome = true;
+    };
+
+    users.extraGroups.mosquitto.gid = config.ids.gids.mosquitto;
+
+  };
+}
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index e9eea6a2cae1..9912ad9ae3fc 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -114,12 +114,10 @@ in {
       # Ugly hack for using the correct gnome3 packageSet
       basePackages = mkOption {
         type = types.attrsOf types.package;
-        default = { inherit modemmanager wpa_supplicant
+        default = { inherit networkmanager modemmanager wpa_supplicant
                             networkmanager_openvpn networkmanager_vpnc
                             networkmanager_openconnect
-                            networkmanager_pptp networkmanager_l2tp;
-                    networkmanager = networkmanager.out;
-                  };
+                            networkmanager_pptp networkmanager_l2tp; };
         internal = true;
       };
 
@@ -189,7 +187,7 @@ in {
 
     boot.kernelModules = [ "ppp_mppe" ]; # Needed for most (all?) PPTP VPN connections.
 
-    environment.etc = with mapAttrs (name: getBin) cfg.basePackages; [
+    environment.etc = with cfg.basePackages; [
       { source = ipUpScript;
         target = "NetworkManager/dispatcher.d/01nixos-ip-up";
       }
diff --git a/nixos/modules/services/networking/ntpd.nix b/nixos/modules/services/networking/ntpd.nix
index 5256fc9bc071..c8a085679280 100644
--- a/nixos/modules/services/networking/ntpd.nix
+++ b/nixos/modules/services/networking/ntpd.nix
@@ -82,6 +82,8 @@ in
       { description = "NTP Daemon";
 
         wantedBy = [ "multi-user.target" ];
+        wants = [ "time-sync.target" ];
+        before = [ "time-sync.target" ];
 
         preStart =
           ''
diff --git a/nixos/modules/services/networking/openntpd.nix b/nixos/modules/services/networking/openntpd.nix
index e53fc574fbea..a8625fa2fa91 100644
--- a/nixos/modules/services/networking/openntpd.nix
+++ b/nixos/modules/services/networking/openntpd.nix
@@ -64,7 +64,8 @@ in
     systemd.services.openntpd = {
       description = "OpenNTP Server";
       wantedBy = [ "multi-user.target" ];
-      wants = [ "network-online.target" ];
+      wants = [ "network-online.target" "time-sync.target" ];
+      before = [ "time-sync.target" ];
       after = [ "dnsmasq.service" "bind.service" "network-online.target" ];
       serviceConfig.ExecStart = "${package}/sbin/ntpd -d -f ${cfgFile} ${cfg.extraOptions}";
     };
diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix
index a96888dec864..82173a841a3f 100644
--- a/nixos/modules/services/networking/openvpn.nix
+++ b/nixos/modules/services/networking/openvpn.nix
@@ -29,21 +29,27 @@ let
         done
 
         ${cfg.up}
+        ${optionalString cfg.updateResolvConf
+           "${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
       '';
 
       downScript = ''
         #! /bin/sh
         export PATH=${path}
+        ${optionalString cfg.updateResolvConf
+           "${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
         ${cfg.down}
       '';
 
       configFile = pkgs.writeText "openvpn-config-${name}"
         ''
           errors-to-stderr
-          ${optionalString (cfg.up != "" || cfg.down != "") "script-security 2"}
+          ${optionalString (cfg.up != "" || cfg.down != "" || cfg.updateResolvConf) "script-security 2"}
           ${cfg.config}
-          ${optionalString (cfg.up != "") "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"}
-          ${optionalString (cfg.down != "") "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"}
+          ${optionalString (cfg.up != "" || cfg.updateResolvConf)
+              "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"}
+          ${optionalString (cfg.down != "" || cfg.updateResolvConf)
+              "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"}
         '';
 
     in {
@@ -145,6 +151,16 @@ in
           description = "Whether this OpenVPN instance should be started automatically.";
         };
 
+        updateResolvConf = mkOption {
+          default = false;
+          type = types.bool;
+          description = ''
+            Use the script from the update-resolv-conf package to automatically
+            update resolv.conf with the DNS information provided by openvpn. The
+            script will be run after the "up" commands and before the "down" commands.
+          '';
+        };
+
       };
 
     };
diff --git a/nixos/modules/services/networking/pptpd.nix b/nixos/modules/services/networking/pptpd.nix
new file mode 100644
index 000000000000..513e6174752c
--- /dev/null
+++ b/nixos/modules/services/networking/pptpd.nix
@@ -0,0 +1,124 @@
+{ config, stdenv, pkgs, lib, ... }:
+
+with lib;
+
+{
+  options = {
+    services.pptpd = {
+      enable = mkEnableOption "Whether pptpd should be run on startup.";
+
+      serverIp = mkOption {
+        type        = types.string;
+        description = "The server-side IP address.";
+        default     = "10.124.124.1";
+      };
+
+      clientIpRange = mkOption {
+        type        = types.string;
+        description = "The range from which client IPs are drawn.";
+        default     = "10.124.124.2-11";
+      };
+
+      maxClients = mkOption {
+        type        = types.int;
+        description = "The maximum number of simultaneous connections.";
+        default     = 10;
+      };
+
+      extraPptpdOptions = mkOption {
+        type        = types.lines;
+        description = "Adds extra lines to the pptpd configuration file.";
+        default     = "";
+      };
+
+      extraPppdOptions = mkOption {
+        type        = types.lines;
+        description = "Adds extra lines to the pppd options file.";
+        default     = "";
+        example     = ''
+          ms-dns 8.8.8.8
+          ms-dns 8.8.4.4
+        '';
+      };
+    };
+  };
+
+  config = mkIf config.services.pptpd.enable {
+    systemd.services.pptpd = let
+      cfg = config.services.pptpd;
+
+      pptpd-conf = pkgs.writeText "pptpd.conf" ''
+        # Inspired from pptpd-1.4.0/samples/pptpd.conf
+        ppp ${ppp-pptpd-wrapped}/bin/pppd
+        option ${pppd-options}
+        pidfile /run/pptpd.pid
+        localip ${cfg.serverIp}
+        remoteip ${cfg.clientIpRange}
+        connections ${toString cfg.maxClients} # (Will get harmless warning if inconsistent with IP range)
+
+        # Extra
+        ${cfg.extraPptpdOptions}
+      '';
+
+      pppd-options = pkgs.writeText "ppp-options-pptpd.conf" ''
+        # From: cat pptpd-1.4.0/samples/options.pptpd | grep -v ^# | grep -v ^$
+        name pptpd
+        refuse-pap
+        refuse-chap
+        refuse-mschap
+        require-mschap-v2
+        require-mppe-128
+        proxyarp
+        lock
+        nobsdcomp
+        novj
+        novjccomp
+        nologfd
+
+        # Extra:
+        ${cfg.extraPppdOptions}
+      '';
+
+      ppp-pptpd-wrapped = pkgs.stdenv.mkDerivation {
+        name         = "ppp-pptpd-wrapped";
+        phases       = [ "installPhase" ];
+        buildInputs  = with pkgs; [ makeWrapper ];
+        installPhase = ''
+          mkdir -p $out/bin
+          makeWrapper ${pkgs.ppp}/bin/pppd $out/bin/pppd \
+            --set LD_PRELOAD    "${pkgs.libredirect}/lib/libredirect.so" \
+            --set NIX_REDIRECTS "/etc/ppp=/etc/ppp-pptpd"
+        '';
+      };
+    in {
+      description = "pptpd server";
+
+      requires = [ "network-online.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = ''
+        mkdir -p -m 700 /etc/ppp-pptpd
+
+        secrets="/etc/ppp-pptpd/chap-secrets"
+
+        [ -f "$secrets" ] || cat > "$secrets" << EOF
+        # From: pptpd-1.4.0/samples/chap-secrets
+        # Secrets for authentication using CHAP
+        # client	server	secret		IP addresses
+        #username	pptpd	password	*
+        EOF
+
+        chown root.root "$secrets"
+        chmod 600 "$secrets"
+      '';
+
+      serviceConfig = {
+        ExecStart = "${pkgs.pptpd}/bin/pptpd --conf ${pptpd-conf}";
+        KillMode  = "process";
+        Restart   = "on-success";
+        Type      = "forking";
+        PIDFile   = "/run/pptpd.pid";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
index 39ebaa45a794..ba913482e3cb 100644
--- a/nixos/modules/services/networking/skydns.nix
+++ b/nixos/modules/services/networking/skydns.nix
@@ -83,7 +83,7 @@ in {
         SKYDNS_NAMESERVERS = concatStringsSep "," cfg.nameservers;
       };
       serviceConfig = {
-        ExecStart = "${cfg.package}/bin/skydns";
+        ExecStart = "${cfg.package.bin}/bin/skydns";
       };
     };
 
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index 514c17c6e5d2..ef05e71ce076 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -121,7 +121,7 @@ in
           User = cfg.user;
           Group = cfg.group;
           PermissionsStartOnly = true;
-          ExecStart = "${pkgs.syncthing}/bin/syncthing -no-browser -home=${cfg.dataDir}";
+          ExecStart = "${cfg.package}/bin/syncthing -no-browser -home=${cfg.dataDir}";
         };
       };
     };
@@ -129,7 +129,7 @@ in
     systemd.user.services =  {
       syncthing = header // {
         serviceConfig = service // {
-          ExecStart = "${pkgs.syncthing}/bin/syncthing -no-browser";
+          ExecStart = "${cfg.package}/bin/syncthing -no-browser";
         };
       };
     };
diff --git a/nixos/modules/services/networking/toxvpn.nix b/nixos/modules/services/networking/toxvpn.nix
new file mode 100644
index 000000000000..c38424c8e273
--- /dev/null
+++ b/nixos/modules/services/networking/toxvpn.nix
@@ -0,0 +1,54 @@
+{ config, stdenv, pkgs, lib, ... }:
+
+with lib;
+
+{
+  options = {
+    services.toxvpn = {
+      enable = mkEnableOption "enable toxvpn running on startup";
+
+      localip = mkOption {
+        type        = types.string;
+        default     = "10.123.123.1";
+        description = "your ip on the vpn";
+      };
+
+      port = mkOption {
+        type        = types.int;
+        default     = 33445;
+        description = "udp port for toxcore, port-forward to help with connectivity if you run many nodes behind one NAT";
+      };
+    };
+  };
+
+  config = mkIf config.services.toxvpn.enable {
+    systemd.services.toxvpn = {
+      description = "toxvpn daemon";
+
+      requires = [ "network-online.target" ]; # consider replacing by NetworkManager-wait-online.service
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = ''
+        mkdir -p /run/toxvpn || true
+        chown toxvpn /run/toxvpn
+      '';
+
+      serviceConfig = {
+        ExecStart = "${pkgs.toxvpn}/bin/toxvpn -i ${config.services.toxvpn.localip} -l /run/toxvpn/control -u toxvpn -p ${toString config.services.toxvpn.port}";
+        KillMode  = "process";
+        Restart   = "on-success";
+        Type      = "notify";
+      };
+
+      restartIfChanged = false; # Likely to be used for remote admin
+    };
+
+    users.extraUsers = {
+      toxvpn = {
+        uid        = config.ids.uids.toxvpn;
+        home       = "/var/lib/toxvpn";
+        createHome = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index 89762fe52488..0dd24478f409 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -106,8 +106,10 @@ in
       preStart = ''
         mkdir -m 0755 -p ${stateDir}/dev/
         cp ${confFile} ${stateDir}/unbound.conf
+        ${optionalString cfg.enableRootTrustAnchor ''
         ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile}
         chown unbound ${stateDir} ${rootTrustAnchorFile}
+        ''}
         touch ${stateDir}/dev/random
         ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random
       '';
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 53648aef1e04..8d22c10d3f78 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -129,7 +129,7 @@ in {
       in {
         description = "WPA Supplicant";
 
-        after = [ "network-interfaces.target" ];
+        after = [ "network-interfaces.target" ] ++ lib.concatMap deviceUnit ifaces;
         requires = lib.concatMap deviceUnit ifaces;
         wantedBy = [ "network.target" ];
 
diff --git a/nixos/modules/services/networking/xl2tpd.nix b/nixos/modules/services/networking/xl2tpd.nix
new file mode 100644
index 000000000000..5e006c13f0d0
--- /dev/null
+++ b/nixos/modules/services/networking/xl2tpd.nix
@@ -0,0 +1,143 @@
+{ config, stdenv, pkgs, lib, ... }:
+
+with lib;
+
+{
+  options = {
+    services.xl2tpd = {
+      enable = mkEnableOption "Whether xl2tpd should be run on startup.";
+
+      serverIp = mkOption {
+        type        = types.string;
+        description = "The server-side IP address.";
+        default     = "10.125.125.1";
+      };
+
+      clientIpRange = mkOption {
+        type        = types.string;
+        description = "The range from which client IPs are drawn.";
+        default     = "10.125.125.2-11";
+      };
+
+      extraXl2tpOptions = mkOption {
+        type        = types.lines;
+        description = "Adds extra lines to the xl2tpd configuration file.";
+        default     = "";
+      };
+
+      extraPppdOptions = mkOption {
+        type        = types.lines;
+        description = "Adds extra lines to the pppd options file.";
+        default     = "";
+        example     = ''
+          ms-dns 8.8.8.8
+          ms-dns 8.8.4.4
+        '';
+      };
+    };
+  };
+
+  config = mkIf config.services.xl2tpd.enable {
+    systemd.services.xl2tpd = let
+      cfg = config.services.xl2tpd;
+
+      # Config files from https://help.ubuntu.com/community/L2TPServer
+      xl2tpd-conf = pkgs.writeText "xl2tpd.conf" ''
+        [global]
+        ipsec saref = no
+
+        [lns default]
+        local ip = ${cfg.serverIp}
+        ip range = ${cfg.clientIpRange}
+        pppoptfile = ${pppd-options}
+        length bit = yes
+
+        ; Extra
+        ${cfg.extraXl2tpOptions}
+      '';
+
+      pppd-options = pkgs.writeText "ppp-options-xl2tpd.conf" ''
+        refuse-pap
+        refuse-chap
+        refuse-mschap
+        require-mschap-v2
+        # require-mppe-128
+        asyncmap 0
+        auth
+        crtscts
+        idle 1800
+        mtu 1200
+        mru 1200
+        lock
+        hide-password
+        local
+        # debug
+        name xl2tpd
+        # proxyarp
+        lcp-echo-interval 30
+        lcp-echo-failure 4
+
+        # Extra:
+        ${cfg.extraPppdOptions}
+      '';
+
+      xl2tpd-ppp-wrapped = pkgs.stdenv.mkDerivation {
+        name         = "xl2tpd-ppp-wrapped";
+        phases       = [ "installPhase" ];
+        buildInputs  = with pkgs; [ makeWrapper ];
+        installPhase = ''
+          mkdir -p $out/bin
+
+          makeWrapper ${pkgs.ppp}/sbin/pppd $out/bin/pppd \
+            --set LD_PRELOAD    "${pkgs.libredirect}/lib/libredirect.so" \
+            --set NIX_REDIRECTS "/etc/ppp=/etc/xl2tpd/ppp"
+
+          makeWrapper ${pkgs.xl2tpd}/bin/xl2tpd $out/bin/xl2tpd \
+            --set LD_PRELOAD    "${pkgs.libredirect}/lib/libredirect.so" \
+            --set NIX_REDIRECTS "${pkgs.ppp}/sbin/pppd=$out/bin/pppd"
+        '';
+      };
+    in {
+      description = "xl2tpd server";
+
+      requires = [ "network-online.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = ''
+        mkdir -p -m 700 /etc/xl2tpd
+
+        pushd /etc/xl2tpd > /dev/null
+
+        mkdir -p -m 700 ppp
+
+        [ -f ppp/chap-secrets ] || cat > ppp/chap-secrets << EOF
+        # Secrets for authentication using CHAP
+        # client	server	secret		IP addresses
+        #username	xl2tpd	password	*
+        EOF
+
+        chown root.root ppp/chap-secrets
+        chmod 600 ppp/chap-secrets
+
+        # The documentation says this file should be present but doesn't explain why and things work even if not there:
+        [ -f l2tp-secrets ] || (echo -n "* * "; ${pkgs.apg}/bin/apg -n 1 -m 32 -x 32 -a 1 -M LCN) > l2tp-secrets
+        chown root.root l2tp-secrets
+        chmod 600 l2tp-secrets
+
+        popd > /dev/null
+
+        mkdir -p /run/xl2tpd
+        chown root.root /run/xl2tpd
+        chmod 700       /run/xl2tpd
+      '';
+
+      serviceConfig = {
+        ExecStart = "${xl2tpd-ppp-wrapped}/bin/xl2tpd -D -c ${xl2tpd-conf} -s /etc/xl2tpd/l2tp-secrets -p /run/xl2tpd/pid -C /run/xl2tpd/control";
+        KillMode  = "process";
+        Restart   = "on-success";
+        Type      = "simple";
+        PIDFile   = "/run/xl2tpd/pid";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index 33c4910fc0ce..22e3bb0066cc 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -102,7 +102,7 @@ in
         partOf = optional config.networking.firewall.enable "firewall.service";
 
         restartTriggers = [ fail2banConf jailConf ];
-        path = [ pkgs.fail2ban pkgs.iptables ];
+        path = [ pkgs.fail2ban pkgs.iptables pkgs.iproute ];
 
         preStart =
           ''
diff --git a/nixos/modules/services/security/hologram.nix b/nixos/modules/services/security/hologram.nix
index 58f308df7a21..e267fed27955 100644
--- a/nixos/modules/services/security/hologram.nix
+++ b/nixos/modules/services/security/hologram.nix
@@ -95,7 +95,7 @@ in {
       wantedBy    = [ "multi-user.target" ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.hologram}/bin/hologram-server --debug --conf ${cfgFile}";
+        ExecStart = "${pkgs.hologram.bin}/bin/hologram-server --debug --conf ${cfgFile}";
       };
     };
   };
diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix
new file mode 100644
index 000000000000..4c20392214fc
--- /dev/null
+++ b/nixos/modules/services/security/oauth2_proxy.nix
@@ -0,0 +1,523 @@
+# NixOS module for oauth2_proxy.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.oauth2_proxy;
+
+  # Use like:
+  #   repeatedArgs (arg: "--arg=${arg}") args
+  repeatedArgs = concatMapStringsSep " ";
+
+  # 'toString' doesn't quite do what we want for bools.
+  fromBool = x: if x then "true" else "false";
+
+  # oauth2_proxy provides many options that are only relevant if you are using
+  # a certain provider. This set maps from provider name to a function that
+  # takes the configuration and returns a string that can be inserted into the
+  # command-line to launch oauth2_proxy.
+  providerSpecificOptions = {
+    azure = cfg: ''
+      --azure-tenant=${cfg.azure.tenant} \
+      --resource=${cfg.azure.resource} \
+    '';
+
+    github = cfg: ''
+      $(optionalString (!isNull cfg.github.org) "--github-org=${cfg.github.org}") \
+      $(optionalString (!isNull cfg.github.team) "--github-org=${cfg.github.team}") \
+    '';
+
+    google = cfg: ''
+      --google-admin-email=${cfg.google.adminEmail} \
+      --google-service-account=${cfg.google.serviceAccountJSON} \
+      $(repeatedArgs (group: "--google-group=${group}") cfg.google.groups) \
+    '';
+  };
+
+  authenticatedEmailsFile = pkgs.writeText "authenticated-emails" cfg.email.addresses;
+
+  getProviderOptions = cfg: provider:
+    if providerSpecificOptions ? provider then providerSpecificOptions.provider cfg else "";
+
+  mkCommandLine = cfg: ''
+    --provider='${cfg.provider}' \
+    ${optionalString (!isNull cfg.email.addresses) "--authenticated-emails-file='${authenticatedEmailsFile}'"} \
+    --approval-prompt='${cfg.approvalPrompt}' \
+    ${optionalString (cfg.passBasicAuth && !isNull cfg.basicAuthPassword) "--basic-auth-password='${cfg.basicAuthPassword}'"} \
+    --client-id='${cfg.clientID}' \
+    --client-secret='${cfg.clientSecret}' \
+    ${optionalString (!isNull cfg.cookie.domain) "--cookie-domain='${cfg.cookie.domain}'"} \
+    --cookie-expire='${cfg.cookie.expire}' \
+    --cookie-httponly=${fromBool cfg.cookie.httpOnly} \
+    --cookie-name='${cfg.cookie.name}' \
+    --cookie-secret='${cfg.cookie.secret}' \
+    --cookie-secure=${fromBool cfg.cookie.secure} \
+    ${optionalString (!isNull cfg.cookie.refresh) "--cookie-refresh='${cfg.cookie.refresh}'"} \
+    ${optionalString (!isNull cfg.customTemplatesDir) "--custom-templates-dir='${cfg.customTemplatesDir}'"} \
+    ${repeatedArgs (x: "--email-domain='${x}'") cfg.email.domains} \
+    --http-address='${cfg.httpAddress}' \
+    ${optionalString (!isNull cfg.htpasswd.file) "--htpasswd-file='${cfg.htpasswd.file}' --display-htpasswd-form=${fromBool cfg.htpasswd.displayForm}"} \
+    ${optionalString (!isNull cfg.loginURL) "--login-url='${cfg.loginURL}'"} \
+    --pass-access-token=${fromBool cfg.passAccessToken} \
+    --pass-basic-auth=${fromBool cfg.passBasicAuth} \
+    --pass-host-header=${fromBool cfg.passHostHeader} \
+    --proxy-prefix='${cfg.proxyPrefix}' \
+    ${optionalString (!isNull cfg.profileURL) "--profile-url='${cfg.profileURL}'"} \
+    ${optionalString (!isNull cfg.redeemURL) "--redeem-url='${cfg.redeemURL}'"} \
+    ${optionalString (!isNull cfg.redirectURL) "--redirect-url='${cfg.redirectURL}'"} \
+    --request-logging=${fromBool cfg.requestLogging} \
+    ${optionalString (!isNull cfg.scope) "--scope='${cfg.scope}'"} \
+    ${repeatedArgs (x: "--skip-auth-regex='${x}'") cfg.skipAuthRegexes} \
+    ${optionalString (!isNull cfg.signatureKey) "--signature-key='${cfg.signatureKey}'"} \
+    --upstream='${cfg.upstream}' \
+    ${optionalString (!isNull cfg.validateURL) "--validate-url='${cfg.validateURL}'"} \
+    ${optionalString cfg.tls.enable "--tls-cert='${cfg.tls.certificate}' --tls-key='${cfg.tls.key}' --https-address='${cfg.tls.httpsAddress}'"} \
+  '' + getProviderOptions cfg cfg.provider;
+in
+{
+  options.services.oauth2_proxy = {
+    enable = mkEnableOption "oauth2_proxy";
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.oauth2_proxy;
+      defaultText = "pkgs.oauth2_proxy";
+      description = ''
+        The package that provides oauth2_proxy.
+      '';
+    };
+
+    ##############################################
+    # PROVIDER configuration
+    provider = mkOption {
+      type = types.enum [
+        "google"
+        "github"
+        "azure"
+        "gitlab"
+        "linkedin"
+        "myusa"
+      ];
+      default = "google";
+      description = ''
+        OAuth provider.
+      '';
+    };
+
+    approvalPrompt = mkOption {
+      type = types.enum ["force" "auto"];
+      default = "force";
+      description = ''
+        OAuth approval_prompt.
+      '';
+    };
+
+    clientID = mkOption {
+      type = types.str;
+      description = ''
+        The OAuth Client ID.
+      '';
+      example = "123456.apps.googleusercontent.com";
+    };
+
+    clientSecret = mkOption {
+      type = types.str;
+      description = ''
+        The OAuth Client Secret.
+      '';
+    };
+
+    skipAuthRegexes = mkOption {
+     type = types.listOf types.str;
+     default = [];
+     description = ''
+       Skip authentication for requests matching any of these regular
+       expressions.
+     '';
+    };
+
+    # XXX: Not clear whether these two options are mutually exclusive or not.
+    email = {
+      domains = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Authenticate emails with the specified domains. Use
+          <literal>*</literal> to authenticate any email.
+        '';
+      };
+
+      addresses = mkOption {
+        type = types.nullOr types.lines;
+        default = null;
+        description = ''
+          Line-separated email addresses that are allowed to authenticate.
+        '';
+      };
+    };
+
+    loginURL = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        Authentication endpoint.
+
+        You only need to set this if you are using a self-hosted provider (e.g.
+        Github Enterprise). If you're using a publicly hosted provider
+        (e.g github.com), then the default works.
+      '';
+      example = "https://provider.example.com/oauth/authorize";
+    };
+
+    redeemURL = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        Token redemption endpoint.
+
+        You only need to set this if you are using a self-hosted provider (e.g.
+        Github Enterprise). If you're using a publicly hosted provider
+        (e.g github.com), then the default works.
+      '';
+      example = "https://provider.example.com/oauth/token";
+    };
+
+    validateURL = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        Access token validation endpoint.
+
+        You only need to set this if you are using a self-hosted provider (e.g.
+        Github Enterprise). If you're using a publicly hosted provider
+        (e.g github.com), then the default works.
+      '';
+      example = "https://provider.example.com/user/emails";
+    };
+
+    redirectURL = mkOption {
+      # XXX: jml suspects this is always necessary, but the command-line
+      # doesn't require it so making it optional.
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The OAuth2 redirect URL.
+      '';
+      example = "https://internalapp.yourcompany.com/oauth2/callback";
+    };
+
+    azure = {
+      tenant = mkOption {
+        type = types.str;
+        default = "common";
+        description = ''
+          Go to a tenant-specific or common (tenant-independent) endpoint.
+        '';
+      };
+
+      resource = mkOption {
+        type = types.str;
+        description = ''
+          The resource that is protected.
+        '';
+      };
+    };
+
+    google = {
+      adminEmail = mkOption {
+        type = types.str;
+        description = ''
+          The Google Admin to impersonate for API calls.
+
+          Only users with access to the Admin APIs can access the Admin SDK
+          Directory API, thus the service account needs to impersonate one of
+          those users to access the Admin SDK Directory API.
+
+          See <link xlink:href="https://developers.google.com/admin-sdk/directory/v1/guides/delegation#delegate_domain-wide_authority_to_your_service_account" />.
+        '';
+      };
+
+      groups = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Restrict logins to members of these Google groups.
+        '';
+      };
+
+      serviceAccountJSON = mkOption {
+        type = types.path;
+        description = ''
+          The path to the service account JSON credentials.
+        '';
+      };
+    };
+
+    github = {
+      org = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Restrict logins to members of this organisation.
+        '';
+      };
+
+      team = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Restrict logins to members of this team.
+        '';
+      };
+    };
+
+
+    ####################################################
+    # UPSTREAM Configuration
+    upstream = mkOption {
+      type = types.commas;
+      description = ''
+        The http url(s) of the upstream endpoint or <literal>file://</literal>
+        paths for static files. Routing is based on the path.
+      '';
+    };
+
+    passAccessToken = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Pass OAuth access_token to upstream via X-Forwarded-Access-Token header.
+      '';
+    };
+
+    passBasicAuth = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream.
+      '';
+    };
+
+    basicAuthPassword = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The password to set when passing the HTTP Basic Auth header.
+      '';
+    };
+
+    passHostHeader = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Pass the request Host Header to upstream.
+      '';
+    };
+
+    signatureKey = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        GAP-Signature request signature key.
+      '';
+      example = "sha1:secret0";
+    };
+
+    cookie = {
+      domain = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          An optional cookie domain to force cookies to.
+        '';
+        example = ".yourcompany.com";
+      };
+
+      expire = mkOption {
+        type = types.str;
+        default = "168h0m0s";
+        description = ''
+          Expire timeframe for cookie.
+        '';
+      };
+
+      httpOnly = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Set HttpOnly cookie flag.
+        '';
+      };
+
+      name = mkOption {
+        type = types.str;
+        default = "_oauth2_proxy";
+        description = ''
+          The name of the cookie that the oauth_proxy creates.
+        '';
+      };
+
+      refresh = mkOption {
+        # XXX: Unclear what the behavior is when this is not specified.
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Refresh the cookie after this duration; 0 to disable.
+        '';
+        example = "168h0m0s";
+      };
+
+      secret = mkOption {
+        type = types.str;
+        description = ''
+          The seed string for secure cookies.
+        '';
+      };
+
+      secure = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Set secure (HTTPS) cookie flag.
+        '';
+      };
+    };
+
+    ####################################################
+    # OAUTH2 PROXY configuration
+
+    httpAddress = mkOption {
+      type = types.str;
+      default = "127.0.0.1:4180";
+      description = ''
+        HTTPS listening address.  This module does not expose the port by
+        default. If you want this URL to be accessible to other machines, please
+        add the port to <literal>networking.firewall.allowedTCPPorts</literal>.
+      '';
+    };
+
+    htpasswd = {
+      file = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          Additionally authenticate against a htpasswd file. Entries must be
+          created with <literal>htpasswd -s</literal> for SHA encryption.
+        '';
+      };
+
+      displayForm = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Display username / password login form if an htpasswd file is provided.
+        '';
+      };
+    };
+
+    customTemplatesDir = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        Path to custom HTML templates.
+      '';
+    };
+
+    proxyPrefix = mkOption {
+      type = types.str;
+      default = "/oauth2";
+      description = ''
+        The url root path that this proxy should be nested under.
+      '';
+    };
+
+    tls = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to serve over TLS.
+        '';
+      };
+
+      certificate = mkOption {
+        type = types.path;
+        description = ''
+          Path to certificate file.
+        '';
+      };
+
+      key = mkOption {
+        type = types.path;
+        description = ''
+          Path to private key file.
+        '';
+      };
+
+      httpsAddress = mkOption {
+        type = types.str;
+        default = ":443";
+        description = ''
+          <literal>addr:port</literal> to listen on for HTTPS clients.
+
+          Remember to add <literal>port</literal> to
+          <literal>allowedTCPPorts</literal> if you want other machines to be
+          able to connect to it.
+        '';
+      };
+    };
+
+    requestLogging = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Log requests to stdout.
+      '';
+    };
+
+    ####################################################
+    # UNKNOWN
+
+    # XXX: Is this mandatory? Is it part of another group? Is it part of the provider specification?
+    scope = mkOption {
+      # XXX: jml suspects this is always necessary, but the command-line
+      # doesn't require it so making it optional.
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        OAuth scope specification.
+      '';
+    };
+
+    profileURL = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+      	Profile access endpoint.
+      '';
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers.oauth2_proxy = {
+      description = "OAuth2 Proxy";
+    };
+
+    systemd.services.oauth2_proxy = {
+      description = "OAuth2 Proxy";
+      path = [ cfg.package ];
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-interfaces.target" ];
+
+      serviceConfig = {
+        User = "oauth2_proxy";
+        Restart = "always";
+        ExecStart = "${cfg.package.bin}/bin/oauth2_proxy ${mkCommandLine cfg}";
+      };
+    };
+
+  };
+}
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 32203a522b0c..5154aaca3bc2 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -113,22 +113,22 @@ in
           #include <abstractions/base>
           #include <abstractions/nameservice>
 
-          ${pkgs.glibc.out}/lib/*.so                    mr,
-          ${pkgs.libevent.out}/lib/libevent*.so*        mr,
-          ${pkgs.curl.out}/lib/libcurl*.so*             mr,
-          ${pkgs.openssl.out}/lib/libssl*.so*           mr,
-          ${pkgs.openssl.out}/lib/libcrypto*.so*        mr,
-          ${pkgs.zlib.out}/lib/libz*.so*                mr,
-          ${pkgs.libssh2.out}/lib/libssh2*.so*          mr,
-          ${pkgs.systemd}/lib/libsystemd*.so*       mr,
-          ${pkgs.xz.out}/lib/liblzma*.so*               mr,
-          ${pkgs.libgcrypt.out}/lib/libgcrypt*.so*      mr,
-          ${pkgs.libgpgerror.out}/lib/libgpg-error*.so* mr,
-          ${pkgs.nghttp2.lib}/lib/libnghttp2*.so*       mr,
-          ${pkgs.c-ares.out}/lib/libcares*.so*          mr,
-          ${pkgs.libcap.lib}/lib/libcap*.so*            mr,
-          ${pkgs.attr.out}/lib/libattr*.so*             mr,
-          ${pkgs.lz4}/lib/liblz4*.so*               mr,
+          ${getLib pkgs.glibc}/lib/*.so                    mr,
+          ${getLib pkgs.libevent}/lib/libevent*.so*        mr,
+          ${getLib pkgs.curl}/lib/libcurl*.so*             mr,
+          ${getLib pkgs.openssl}/lib/libssl*.so*           mr,
+          ${getLib pkgs.openssl}/lib/libcrypto*.so*        mr,
+          ${getLib pkgs.zlib}/lib/libz*.so*                mr,
+          ${getLib pkgs.libssh2}/lib/libssh2*.so*          mr,
+          ${getLib pkgs.systemd}/lib/libsystemd*.so*       mr,
+          ${getLib pkgs.xz}/lib/liblzma*.so*               mr,
+          ${getLib pkgs.libgcrypt}/lib/libgcrypt*.so*      mr,
+          ${getLib pkgs.libgpgerror}/lib/libgpg-error*.so* mr,
+          ${getLib pkgs.nghttp2}/lib/libnghttp2*.so*       mr,
+          ${getLib pkgs.c-ares}/lib/libcares*.so*          mr,
+          ${getLib pkgs.libcap}/lib/libcap*.so*            mr,
+          ${getLib pkgs.attr}/lib/libattr*.so*             mr,
+          ${getLib pkgs.lz4}/lib/liblz4*.so*               mr,
 
           @{PROC}/sys/kernel/random/uuid   r,
           @{PROC}/sys/vm/overcommit_memory r,
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index c23897192b4c..9844e3c435d1 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -337,6 +337,7 @@ let
         allModules =
           concatMap (svc: svc.extraModulesPre) allSubservices
           ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules
+          ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
           ++ optional enablePHP { name = "php5"; path = "${php}/modules/libphp5.so"; }
           ++ concatMap (svc: svc.extraModules) allSubservices
           ++ extraForeignModules;
@@ -541,6 +542,12 @@ in
         '';
       };
 
+      enableMellon = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the mod_auth_mellon module.";
+      };
+
       enablePHP = mkOption {
         type = types.bool;
         default = false;
@@ -650,6 +657,7 @@ in
 
         environment =
           optionalAttrs enablePHP { PHPRC = phpIni; }
+          // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH  = "${pkgs.xmlsec}/lib"; }
           // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices));
 
         preStart =
diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
index 0fe8d1a89cf3..b4b5a6fdc07e 100644
--- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
@@ -43,7 +43,7 @@ let
         # Paths to external programs.
         $wgDiff3 = "${pkgs.diffutils}/bin/diff3";
         $wgDiff = "${pkgs.diffutils}/bin/diff";
-        $wgImageMagickConvertCommand = "${pkgs.imagemagick}/bin/convert";
+        $wgImageMagickConvertCommand = "${pkgs.imagemagick.out}/bin/convert";
 
         #$wgDebugLogFile = "/tmp/mediawiki_debug_log.txt";
 
diff --git a/nixos/modules/services/web-servers/lighttpd/inginious.nix b/nixos/modules/services/web-servers/lighttpd/inginious.nix
new file mode 100644
index 000000000000..43deccb6aef8
--- /dev/null
+++ b/nixos/modules/services/web-servers/lighttpd/inginious.nix
@@ -0,0 +1,262 @@
+{ config, lib, pkgs, ... }:
+with lib;
+
+let
+  cfg = config.services.lighttpd.inginious;
+  inginious = pkgs.inginious;
+  execName = "inginious-${if cfg.useLTI then "lti" else "webapp"}";
+
+  inginiousConfigFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "inginious.yaml" ''
+    # Backend; can be:
+    # - "local" (run containers on the same machine)
+    # - "remote" (connect to distant docker daemon and auto start agents) (choose this if you use boot2docker)
+    # - "remote_manual" (connect to distant and manually installed agents)
+    backend: "${cfg.backendType}"
+
+    ## TODO (maybe): Add an option for the "remote" backend in this NixOS module.
+    # List of remote docker daemon to which the backend will try
+    # to connect (backend: remote only)
+    #docker_daemons:
+    #  - # Host of the docker daemon *from the webapp*
+    #    remote_host: "some.remote.server"
+    #    # Port of the distant docker daemon *from the webapp*
+    #    remote_docker_port: "2375"
+    #    # A mandatory port used by the backend and the agent that will be automatically started.
+    #    # Needs to be available on the remote host, and to be open in the firewall.
+    #    remote_agent_port: "63456"
+    #    # Does the remote docker requires tls? Defaults to false.
+    #    # Parameter can be set to true or path to the certificates
+    #    #use_tls: false
+    #    # Link to the docker daemon *from the host that runs the docker daemon*. Defaults to:
+    #    #local_location: "unix:///var/run/docker.sock"
+    #    # Path to the cgroups "mount" *from the host that runs the docker daemon*. Defaults to:
+    #    #cgroups_location: "/sys/fs/cgroup"
+    #    # Name that will be used to reference the agent
+    #    #"agent_name": "inginious-agent"
+
+    # List of remote agents to which the backend will try
+    # to connect (backend: remote_manual only)
+    # Example:
+    #agents:
+    #  - host: "192.168.59.103"
+    #    port: 5001
+    agents:
+    ${lib.concatMapStrings (agent:
+      "  - host: \"${agent.host}\"\n" +
+      "    port: ${agent.port}\n"
+    ) cfg.remoteAgents}
+
+    # Location of the task directory
+    tasks_directory: "${cfg.tasksDirectory}"
+
+    # Super admins: list of user names that can do everything in the backend
+    superadmins:
+    ${lib.concatMapStrings (x: "  - \"${x}\"\n") cfg.superadmins}
+
+    # Aliases for containers
+    # Only containers listed here can be used by tasks
+    containers:
+    ${lib.concatStrings (lib.mapAttrsToList (name: fullname:
+      "  ${name}: \"${fullname}\"\n"
+    ) cfg.containers)}
+
+    # Use single minified javascript file (production) or multiple files (dev) ?
+    use_minified_js: true
+
+    ## TODO (maybe): Add NixOS options for these parameters.
+
+    # MongoDB options
+    #mongo_opt:
+    #    host: localhost
+    #    database: INGInious
+
+    # Disable INGInious?
+    #maintenance: false
+
+    #smtp:
+    #    sendername: 'INGInious <no-reply@inginious.org>'
+    #    host: 'smtp.gmail.com'
+    #    port: 587
+    #    username: 'configme@gmail.com'
+    #    password: 'secret'
+    #    starttls: True
+
+    ## NixOS extra config
+
+    ${cfg.extraConfig}
+  '';
+in
+{
+  options.services.lighttpd.inginious = {
+    enable = mkEnableOption  "INGInious, an automated code testing and grading system.";
+
+    configFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      example = literalExample ''pkgs.writeText "configuration.yaml" "# custom config options ...";'';
+      description = ''The path to an INGInious configuration file.'';
+    };
+
+    extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      example = ''
+        # Load the dummy auth plugin.
+        plugins:
+          - plugin_module: inginious.frontend.webapp.plugins.auth.demo_auth
+            users:
+              # register the user "test" with the password "someverycomplexpassword"
+              test: someverycomplexpassword
+      '';
+      description = ''Extra option in YaML format, to be appended to the config file.'';
+    };
+
+    tasksDirectory = mkOption {
+      type = types.path;
+      default = "${inginious}/lib/python2.7/site-packages/inginious/tasks";
+      example = "/var/lib/INGInious/tasks";
+      description = ''
+        Path to the tasks folder.
+        Defaults to the provided test tasks folder (readonly).
+      '';
+    };
+
+    useLTI = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''Whether to start the LTI frontend in place of the webapp.'';
+    };
+
+    superadmins = mkOption {
+      type = types.uniq (types.listOf types.str);
+      default = [ "admin" ];
+      example = [ "john" "pepe" "emilia" ];
+      description = ''List of user logins allowed to administrate the whole server.'';
+    };
+
+    containers = mkOption {
+      type = types.attrsOf types.str;
+      default = {
+          default = "ingi/inginious-c-default";
+      };
+      example = {
+        default = "ingi/inginious-c-default";
+        sekexe  = "ingi/inginious-c-sekexe";
+        java    = "ingi/inginious-c-java";
+        oz      = "ingi/inginious-c-oz";
+        pythia1compat = "ingi/inginious-c-pythia1compat";
+      };
+      description = ''
+        An attrset describing the required containers
+        These containers will be available in INGInious using their short name (key)
+        and will be automatically downloaded before INGInious starts.
+      '';
+    };
+
+    hostPattern = mkOption {
+      type = types.str;
+      default = "^inginious.";
+      example = "^inginious.mydomain.xyz$";
+      description = ''
+        The domain that serves INGInious.
+        INGInious uses absolute paths which makes it difficult to relocate in its own subdir.
+        The default configuration will serve INGInious when the server is accessed with a hostname starting with "inginious.".
+        If left blank, INGInious will take the precedence over all the other lighttpd sites, which is probably not what you want.
+      '';
+    };
+
+    backendType = mkOption {
+      type = types.enum [ "local" "remote_manual" ]; # TODO: support backend "remote"
+      default = "local";
+      description = ''
+        Select how INGINious accesses to grading containers.
+        The default "local" option ensures that Docker is started and provisioned.
+        Fore more information, see http://inginious.readthedocs.io/en/latest/install_doc/config_reference.html
+        Not all backends are supported. Use services.inginious.configFile for full flexibility.
+      '';
+    };
+
+    remoteAgents = mkOption {
+      type = types.listOf (types.attrsOf types.str);
+      default = [];
+      example = [ { host = "192.0.2.25"; port = "1345"; } ];
+      description = ''A list of remote agents, used only when services.inginious.backendType is "remote_manual".'';
+    };
+  };
+
+  config = mkIf cfg.enable (
+    mkMerge [
+      # For a local install, we need docker.
+      (mkIf (cfg.backendType == "local") {
+        virtualisation.docker = {
+          enable = true;
+          # We need docker to listen on port 2375.
+          extraOptions = "-H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock";
+          storageDriver = mkDefault "overlay";
+          socketActivation = false;
+        };
+
+        users.extraUsers."lighttpd".extraGroups = [ "docker" ];
+
+        # Ensure that docker has pulled the required images.
+        systemd.services.inginious-prefetch = {
+          script = let
+            images = lib.unique (
+              [ "centos" "ingi/inginious-agent" ]
+              ++ lib.mapAttrsToList (_: image: image) cfg.containers
+            );
+          in lib.concatMapStrings (image: ''
+            ${pkgs.docker}/bin/docker pull ${image}
+          '') images;
+
+          serviceConfig.Type = "oneshot";
+          wants = [ "docker.service" ];
+          after = [ "docker.service" ];
+          wantedBy = [ "lighttpd.service" ];
+          before = [ "lighttpd.service" ];
+        };
+      })
+
+      # Common
+      {
+        # To access inginous tools (like inginious-test-task)
+        environment.systemPackages = [ inginious ];
+
+        services.mongodb.enable = true;
+
+        services.lighttpd.enable = true;
+        services.lighttpd.enableModules = [ "mod_access" "mod_alias" "mod_fastcgi" "mod_redirect" "mod_rewrite" ];
+        services.lighttpd.extraConfig = ''
+          $HTTP["host"] =~ "${cfg.hostPattern}" {
+            fastcgi.server = ( "/${execName}" =>
+              ((
+                "socket" => "/run/lighttpd/inginious-fastcgi.socket",
+                "bin-path" => "${inginious}/bin/${execName} --config=${inginiousConfigFile}",
+                "max-procs" => 1,
+                "bin-environment" => ( "REAL_SCRIPT_NAME" => "" ),
+                "check-local" => "disable"
+              ))
+            )
+            url.rewrite-once = (
+              "^/.well-known/.*" => "$0",
+              "^/static/.*" => "$0",
+              "^/.*$" => "/${execName}$0",
+              "^/favicon.ico$" => "/static/common/favicon.ico",
+            )
+            alias.url += (
+              "/static/webapp/" => "${inginious}/lib/python2.7/site-packages/inginious/frontend/webapp/static/",
+              "/static/common/" => "${inginious}/lib/python2.7/site-packages/inginious/frontend/common/static/"
+            )
+          }
+        '';
+
+        systemd.services.lighttpd.preStart = ''
+          mkdir -p /run/lighttpd
+          chown lighttpd.lighttpd /run/lighttpd
+        '';
+
+        systemd.services.lighttpd.wants = [ "mongodb.service" "docker.service" ];
+        systemd.services.lighttpd.after = [ "mongodb.service" "docker.service" ];
+      }
+    ]);
+}
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 16996b9f96c1..68579a1af836 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -44,7 +44,7 @@ let
        ${cfg.extraGSettingsOverrides}
      EOF
 
-     ${pkgs.glib}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/
+     ${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/
     '';
   };
 
@@ -78,10 +78,11 @@ in {
         type = types.listOf types.path;
         description = "List of packages for which gsettings are overridden.";
       };
+
+      debug = mkEnableOption "gnome-session debug messages";
     };  
 
     environment.gnome3.packageSet = mkOption {
-      type = types.nullOr types.package;
       default = null;
       example = literalExample "pkgs.gnome3_18";
       description = "Which GNOME 3 package set to use.";
@@ -118,6 +119,7 @@ in {
     services.telepathy.enable = mkDefault true;
     networking.networkmanager.enable = mkDefault true;
     services.upower.enable = config.powerManagement.enable;
+    services.dbus.packages = mkIf config.services.printing.enable [ pkgs.system-config-printer ];
     hardware.bluetooth.enable = mkDefault true;
 
     fonts.fonts = [ pkgs.dejavu_fonts pkgs.cantarell_fonts ];
@@ -160,7 +162,7 @@ in {
           # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
           ${pkgs.xdg-user-dirs}/bin/xdg-user-dirs-update
 
-          ${gnome3.gnome_session}/bin/gnome-session&
+          ${gnome3.gnome_session}/bin/gnome-session ${optionalString cfg.debug "--debug"} &
           waitPID=$!
         '';
       };
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 2e9183da970a..060dda1a70a8 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -117,6 +117,9 @@ in
       # Install activity manager if available
       ++ lib.optional (lib.hasAttr "kactivitymanagerd" kde5) kde5.kactivitymanagerd
 
+      # frameworkintegration was split with plasma-integration in Plasma 5.6
+      ++ lib.optional (lib.hasAttr "plasma-integration" kde5) kde5.plasma-integration
+
       # Optional hardware support features
       ++ lib.optional config.hardware.bluetooth.enable kde5.bluedevil
       ++ lib.optional config.networking.networkmanager.enable kde5.plasma-nm
@@ -167,7 +170,9 @@ in
     services.xserver.displayManager.sddm = {
       theme = "breeze";
       themes = [
+        kde5.extra-cmake-modules # for the setup-hook
         kde5.plasma-workspace
+        kde5.breeze-icons
         (kde5.oxygen-icons or kde5.oxygen-icons5)
       ];
     };
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 4c4e3d967988..634d2a39576a 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -33,6 +33,14 @@ in
         default = false;
         description = "Don't install XFCE desktop components (xfdesktop, panel and notification daemon).";
       };
+
+      extraSessionCommands = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Shell commands executed just before XFCE is started.
+        '';
+      };
     };
 
   };
@@ -45,6 +53,8 @@ in
         bgSupport = true;
         start =
           ''
+            ${cfg.extraSessionCommands}
+
             # Set GTK_PATH so that GTK+ can find the theme engines.
             export GTK_PATH="${config.system.path}/lib/gtk-2.0:${config.system.path}/lib/gtk-3.0"
 
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 376f9f4b46b5..862ddc1d13f2 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -32,6 +32,12 @@ let
     ''
       #! ${pkgs.bash}/bin/bash
 
+      ${optionalString cfg.displayManager.logToJournal ''
+        if [ -z "$_DID_SYSTEMD_CAT" ]; then
+          _DID_SYSTEMD_CAT=1 exec ${config.systemd.package}/bin/systemd-cat -t xsession -- "$0" "$1"
+        fi
+      ''}
+
       . /etc/profile
       cd "$HOME"
 
@@ -39,7 +45,7 @@ let
       sessionType="$1"
       if [ "$sessionType" = default ]; then sessionType=""; fi
 
-      ${optionalString (!cfg.displayManager.job.logsXsession) ''
+      ${optionalString (!cfg.displayManager.job.logsXsession && !cfg.displayManager.logToJournal) ''
         exec > ~/.xsession-errors 2>&1
       ''}
 
@@ -83,6 +89,8 @@ let
       # .local/share doesn't exist yet.
       mkdir -p $HOME/.local/share
 
+      unset _DID_SYSTEMD_CAT
+
       ${cfg.displayManager.sessionCommands}
 
       # Allow the user to execute commands at the beginning of the X session.
@@ -278,6 +286,16 @@ in
 
       };
 
+      logToJournal = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          By default, the stdout/stderr of sessions is written
+          to <filename>~/.xsession-errors</filename>. When this option
+          is enabled, it will instead be written to the journal.
+        '';
+      };
+
     };
 
   };
diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
index 9b937ff7ee18..d9f7f8f0dfc4 100644
--- a/nixos/modules/services/x11/display-managers/kdm.nix
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -139,7 +139,7 @@ in
             mkdir -m 0755 -p /var/lib/kdm
             chown kdm /var/lib/kdm
             ${(optionalString (config.system.boot.loader.id == "grub" && config.system.build.grub != null) "PATH=${config.system.build.grub}/sbin:$PATH ") +
-              "KDEDIRS=/run/current-system/sw exec ${kdebase_workspace}/bin/kdm -config ${kdmrc} -nodaemon"}
+              "KDEDIRS=/run/current-system/sw exec ${kdebase_workspace}/bin/kdm -config ${kdmrc} -nodaemon -logfile /dev/stderr"}
           '';
         logsXsession = true;
       };
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
index 2981e7545e81..e74b19c8e710 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -169,10 +169,10 @@ in {
 
   config = mkIf cfg.enable {
 
-    services.xserver.modules = [ pkg ];
+    services.xserver.modules = [ pkg.out ];
 
     environment.etc."${etcFile}".source =
-      "${pkg}/share/X11/xorg.conf.d/50-synaptics.conf";
+      "${pkg.out}/share/X11/xorg.conf.d/50-synaptics.conf";
 
     environment.systemPackages = [ pkg ];
 
diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix
index 2e2e10cc33b0..cfe9439b688c 100644
--- a/nixos/modules/services/x11/window-managers/i3.nix
+++ b/nixos/modules/services/x11/window-managers/i3.nix
@@ -3,37 +3,52 @@
 with lib;
 
 let
-  cfg = config.services.xserver.windowManager.i3;
-in
+  wmCfg = config.services.xserver.windowManager;
 
-{
-  options = {
-    services.xserver.windowManager.i3 = {
-      enable = mkEnableOption "i3";
-
-      configFile = mkOption {
-        default = null;
-        type = types.nullOr types.path;
-        description = ''
-          Path to the i3 configuration file.
-          If left at the default value, $HOME/.i3/config will be used.
-        '';
-      };
+  i3option = name: {
+    enable = mkEnableOption name;
+    configFile = mkOption {
+      default = null;
+      type = types.nullOr types.path;
+      description = ''
+        Path to the i3 configuration file.
+        If left at the default value, $HOME/.i3/config will be used.
+      '';
+    };
+    extraSessionCommands = mkOption {
+      default = "";
+      type = types.lines;
+      description = ''
+        Shell commands executed just before i3 is started.
+      '';
     };
   };
 
-  config = mkIf cfg.enable {
-    services.xserver.windowManager = {
-      session = [{
-        name = "i3";
-        start = ''
-          ${pkgs.i3}/bin/i3 ${optionalString (cfg.configFile != null)
-            "-c \"${cfg.configFile}\""
-          } &
-          waitPID=$!
-        '';
-      }];
-    };
-    environment.systemPackages = with pkgs; [ i3 ];
+  i3config = name: pkg: cfg: {
+    services.xserver.windowManager.session = [{
+      inherit name;
+      start = ''
+        ${cfg.extraSessionCommands}
+
+        ${pkg}/bin/i3 ${optionalString (cfg.configFile != null)
+          "-c \"${cfg.configFile}\""
+        } &
+        waitPID=$!
+      '';
+    }];
+    environment.systemPackages = [ pkg ];
   };
+
+in
+
+{
+  options.services.xserver.windowManager = {
+    i3 = i3option "i3";
+    i3-gaps = i3option "i3-gaps";
+  };
+
+  config = mkMerge [
+    (mkIf wmCfg.i3.enable (i3config "i3" pkgs.i3 wmCfg.i3))
+    (mkIf wmCfg.i3-gaps.enable (i3config "i3-gaps" pkgs.i3-gaps wmCfg.i3-gaps))
+  ];
 }
diff --git a/nixos/modules/services/x11/xbanish.nix b/nixos/modules/services/x11/xbanish.nix
new file mode 100644
index 000000000000..e1e3cbc8e441
--- /dev/null
+++ b/nixos/modules/services/x11/xbanish.nix
@@ -0,0 +1,30 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.services.xbanish;
+
+in {
+  options.services.xbanish = {
+
+    enable = mkEnableOption "xbanish";
+
+    arguments = mkOption {
+      description = "Arguments to pass to xbanish command";
+      default = "";
+      example = "-d -i shift";
+      type = types.str;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.user.services.xbanish = {
+      description = "xbanish hides the mouse pointer";
+      wantedBy = [ "default.target" ];
+      serviceConfig.ExecStart = ''
+        ${pkgs.xbanish}/bin/xbanish ${cfg.arguments}
+      '';
+      serviceConfig.Restart = "always";
+    };
+  };
+}
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 9cb9c8de31d7..35816c3a16dd 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -16,6 +16,7 @@ let
     virtualbox = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; };
     ati = { modules = with pkgs.xorg; [ xf86videoati glamoregl ]; };
     intel = { modules = with pkgs.xorg; [ xf86videointel glamoregl ]; };
+    modesetting = { modules = []; };
   };
 
   fontsForXServer =
@@ -462,7 +463,14 @@ in
           { source = "${cfg.xkbDir}";
             target = "X11/xkb";
           }
-        ]);
+        ])
+      # Needed since 1.18; see https://bugs.freedesktop.org/show_bug.cgi?id=89023#c5
+      ++ (let cfgPath = "/X11/xorg.conf.d/10-evdev.conf"; in
+        [{
+          source = xorg.xf86inputevdev.out + "/share" + cfgPath;
+          target = cfgPath;
+        }]
+      );
 
     environment.systemPackages =
       [ xorg.xorgserver.out
@@ -478,6 +486,7 @@ in
         xorg.xauth
         pkgs.xterm
         pkgs.xdg_utils
+        xorg.xf86inputevdev.out # get evdev.4 man page
       ]
       ++ optional (elem "virtualbox" cfg.videoDrivers) xorg.xrefresh;
 
@@ -519,6 +528,7 @@ in
         serviceConfig = {
           Restart = "always";
           RestartSec = "200ms";
+          SyslogIdentifier = "display-manager";
         };
       };
 
@@ -526,16 +536,17 @@ in
       [ "-terminate"
         "-config ${configFile}"
         "-xkbdir" "${cfg.xkbDir}"
+        # Log at the default verbosity level to stderr rather than /var/log/X.*.log.
+        "-verbose" "3" "-logfile" "/dev/null"
       ] ++ optional (cfg.display != null) ":${toString cfg.display}"
         ++ optional (cfg.tty     != null) "vt${toString cfg.tty}"
         ++ optional (cfg.dpi     != null) "-dpi ${toString cfg.dpi}"
-        ++ optionals (cfg.display != null) [ "-logfile" "/var/log/X.${toString cfg.display}.log" ]
         ++ optional (!cfg.enableTCP) "-nolisten tcp";
 
     services.xserver.modules =
       concatLists (catAttrs "modules" cfg.drivers) ++
       [ xorg.xorgserver.out
-        xorg.xf86inputevdev
+        xorg.xf86inputevdev.out
       ];
 
     services.xserver.xkbDir = mkDefault "${pkgs.xkeyboard_config}/etc/X11/xkb";
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
index a881459bed18..3e2805a8c341 100644
--- a/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -85,6 +85,10 @@ in
   };
 
   config = mkIf (config.boot.initrd.network.enable && cfg.enable) {
+    assertions = [ {
+      assertion = cfg.hostRSAKey != null || cfg.hostDSSKey != null || cfg.hostECDSAKey != null;
+      message = "You should specify at least one host key for initrd SSH";
+    } ];
 
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
diff --git a/nixos/modules/system/boot/loader/efi.nix b/nixos/modules/system/boot/loader/efi.nix
index 726634e664d7..6043c904c450 100644
--- a/nixos/modules/system/boot/loader/efi.nix
+++ b/nixos/modules/system/boot/loader/efi.nix
@@ -4,19 +4,16 @@ with lib;
 
 {
   options.boot.loader.efi = {
+
     canTouchEfiVariables = mkOption {
       default = false;
-
       type = types.bool;
-
-      description = "Whether or not the installation process should modify efi boot variables.";
+      description = "Whether the installation process is allowed to modify EFI boot variables.";
     };
 
     efiSysMountPoint = mkOption {
       default = "/boot";
-
       type = types.str;
-
       description = "Where the EFI System Partition is mounted.";
     };
   };
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 7fc467b60f7b..0640ec306e18 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -48,12 +48,13 @@ let
       bootPath = args.path;
       storePath = config.boot.loader.grub.storePath;
       bootloaderId = if args.efiBootloaderId == null then "NixOS${efiSysMountPoint'}" else args.efiBootloaderId;
+      timeout = if config.boot.loader.timeout == null then -1 else config.boot.loader.timeout;
       inherit efiSysMountPoint;
       inherit (args) devices;
       inherit (efi) canTouchEfiVariables;
       inherit (cfg)
         version extraConfig extraPerEntryConfig extraEntries
-        extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
+        extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels
         default fsIdentifier efiSupport gfxmodeEfi gfxmodeBios;
       path = (makeBinPath ([
         pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfs-progs
@@ -313,14 +314,6 @@ in
         '';
       };
 
-      timeout = mkOption {
-        default = if (config.boot.loader.timeout != null) then config.boot.loader.timeout else -1;
-        type = types.int;
-        description = ''
-          Timeout (in seconds) until GRUB boots the default menu item.
-        '';
-      };
-
       default = mkOption {
         default = 0;
         type = types.int;
@@ -495,7 +488,7 @@ in
         }
         {
           assertion = if args.efiSysMountPoint == null then true else hasPrefix "/" args.efiSysMountPoint;
-          message = "Efi paths must be absolute, not ${args.efiSysMountPoint}";
+          message = "EFI paths must be absolute, not ${args.efiSysMountPoint}";
         }
       ] ++ flip map args.devices (device: {
         assertion = device == "nodev" || hasPrefix "/" device;
diff --git a/nixos/modules/system/boot/loader/gummiboot/gummiboot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index ef431a7732e1..c38af1b67f17 100644
--- a/nixos/modules/system/boot/loader/gummiboot/gummiboot-builder.py
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -88,16 +88,16 @@ def remove_old_entries(gens):
         if not path in known_paths:
             os.unlink(path)
 
-parser = argparse.ArgumentParser(description='Update NixOS-related gummiboot files')
+parser = argparse.ArgumentParser(description='Update NixOS-related systemd-boot files')
 parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot')
 args = parser.parse_args()
 
 # We deserve our own env var!
 if os.getenv("NIXOS_INSTALL_GRUB") == "1":
     if "@canTouchEfiVariables@" == "1":
-        subprocess.check_call(["@gummiboot@/bin/gummiboot", "--path=@efiSysMountPoint@", "install"])
+        subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"])
     else:
-        subprocess.check_call(["@gummiboot@/bin/gummiboot", "--path=@efiSysMountPoint@", "--no-variables", "install"])
+        subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "--no-variables", "install"])
 
 mkdir_p("@efiSysMountPoint@/efi/nixos")
 mkdir_p("@efiSysMountPoint@/loader/entries")
diff --git a/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
index 69ad2c6d44f4..a778a4f539c9 100644
--- a/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
@@ -3,45 +3,38 @@
 with lib;
 
 let
-  cfg = config.boot.loader.gummiboot;
+  cfg = config.boot.loader.systemd-boot;
 
   efi = config.boot.loader.efi;
 
   gummibootBuilder = pkgs.substituteAll {
-    src = ./gummiboot-builder.py;
+    src = ./systemd-boot-builder.py;
 
     isExecutable = true;
 
-    inherit (pkgs) python gummiboot;
+    inherit (pkgs) python;
+
+    systemd = config.systemd.package;
 
     nix = config.nix.package.out;
 
-    timeout = if cfg.timeout != null then cfg.timeout else "";
+    timeout = if config.boot.loader.timeout != null then config.boot.loader.timeout else "";
 
     inherit (efi) efiSysMountPoint canTouchEfiVariables;
   };
 in {
-  options.boot.loader.gummiboot = {
+
+  imports =
+    [ (mkRenamedOptionModule [ "boot" "loader" "gummiboot" "enable" ] [ "boot" "loader" "systemd-boot" "enable" ])
+    ];
+
+  options.boot.loader.systemd-boot = {
     enable = mkOption {
       default = false;
 
       type = types.bool;
 
-      description = "Whether to enable the gummiboot UEFI boot manager";
-    };
-
-    timeout = mkOption {
-      default = if config.boot.loader.timeout == null then 10000 else config.boot.loader.timeout;
-
-      example = 4;
-
-      type = types.nullOr types.int;
-
-      description = ''
-        Timeout (in seconds) for how long to show the menu (null if none).
-        Note that even with no timeout the menu can be forced if the space
-        key is pressed during bootup
-      '';
+      description = "Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager";
     };
   };
 
@@ -59,7 +52,7 @@ in {
     system = {
       build.installBootLoader = gummibootBuilder;
 
-      boot.loader.id = "gummiboot";
+      boot.loader.id = "systemd-boot";
 
       requiredKernelConfig = with config.lib.kernelConfig; [
         (isYes "EFI_STUB")
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 77a82547031a..8dad09c89207 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -5,7 +5,7 @@ with lib;
 let
   luks = config.boot.initrd.luks;
 
-  openCommand = { name, device, header, keyFile, keyFileSize, allowDiscards, yubikey, ... }: ''
+  openCommand = name': { name, device, header, keyFile, keyFileSize, allowDiscards, yubikey, ... }: assert name' == name; ''
     # Wait for luksRoot to appear, e.g. if on a usb drive.
     # XXX: copied and adapted from stage-1-init.sh - should be
     # available as a function.
@@ -192,9 +192,8 @@ let
     ''}
   '';
 
-  isPreLVM = f: f.preLVM;
-  preLVM = filter isPreLVM luks.devices;
-  postLVM = filter (f: !(isPreLVM f)) luks.devices;
+  preLVM = filterAttrs (n: v: v.preLVM) luks.devices;
+  postLVM = filterAttrs (n: v: !v.preLVM) luks.devices;
 
 in
 {
@@ -228,31 +227,31 @@ in
     };
 
     boot.initrd.luks.devices = mkOption {
-      default = [ ];
-      example = literalExample ''[ { name = "luksroot"; device = "/dev/sda3"; preLVM = true; } ]'';
+      default = { };
+      example = { "luksroot".device = "/dev/disk/by-uuid/430e9eff-d852-4f68-aa3b-2fa3599ebe08"; };
       description = ''
-        The list of devices that should be decrypted using LUKS before trying to mount the
-        root partition. This works for both LVM-over-LUKS and LUKS-over-LVM setups.
-
-        The devices are decrypted to the device mapper names defined.
-
-        Make sure that initrd has the crypto modules needed for decryption.
+        The encrypted disk that should be opened before the root
+        filesystem is mounted. Both LVM-over-LUKS and LUKS-over-LVM
+        setups are sypported. The unencrypted devices can be accessed as
+        <filename>/dev/mapper/<replaceable>name</replaceable></filename>.
       '';
 
-      type = types.listOf types.optionSet;
+      type = types.loaOf types.optionSet;
 
-      options = {
+      options = { name, ... }: { options = {
 
         name = mkOption {
+          visible = false;
+          default = name;
           example = "luksroot";
           type = types.str;
-          description = "Named to be used for the generated device in /dev/mapper.";
+          description = "Name of the unencrypted device in <filename>/dev/mapper</filename>.";
         };
 
         device = mkOption {
-          example = "/dev/sda2";
+          example = "/dev/disk/by-uuid/430e9eff-d852-4f68-aa3b-2fa3599ebe08";
           type = types.str;
-          description = "Path of the underlying block device.";
+          description = "Path of the underlying encrypted block device.";
         };
 
         header = mkOption {
@@ -289,6 +288,7 @@ in
           '';
         };
 
+        # FIXME: get rid of this option.
         preLVM = mkOption {
           default = true;
           type = types.bool;
@@ -394,7 +394,7 @@ in
           };
         };
 
-      };
+      }; };
     };
 
     boot.initrd.luks.yubikeySupport = mkOption {
@@ -408,7 +408,7 @@ in
     };
   };
 
-  config = mkIf (luks.devices != []) {
+  config = mkIf (luks.devices != {}) {
 
     # actually, sbp2 driver is the one enabling the DMA attack, but this needs to be tested
     boot.blacklistedKernelModules = optionals luks.mitigateDMAAttacks
@@ -438,7 +438,7 @@ in
         copy_bin_and_libs ${pkgs.ykpers}/bin/ykinfo
         copy_bin_and_libs ${pkgs.openssl.bin}/bin/openssl
 
-        cc -O3 -I${pkgs.openssl}/include -L${pkgs.openssl.out}/lib ${./pbkdf2-sha512.c} -o pbkdf2-sha512 -lcrypto
+        cc -O3 -I${pkgs.openssl.dev}/include -L${pkgs.openssl.out}/lib ${./pbkdf2-sha512.c} -o pbkdf2-sha512 -lcrypto
         strip -s pbkdf2-sha512
         copy_bin_and_libs pbkdf2-sha512
 
@@ -463,8 +463,8 @@ in
       ''}
     '';
 
-    boot.initrd.preLVMCommands = concatMapStrings openCommand preLVM;
-    boot.initrd.postDeviceCommands = concatMapStrings openCommand postLVM;
+    boot.initrd.preLVMCommands = concatStrings (mapAttrsToList openCommand preLVM);
+    boot.initrd.postDeviceCommands = concatStrings (mapAttrsToList openCommand postLVM);
 
     environment.systemPackages = [ pkgs.cryptsetup ];
   };
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index 1b5b22c2005a..4a7f073ea8ad 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -41,6 +41,8 @@ if [ ! -e /proc/1 ]; then
     mount -n -t proc proc /proc
     mkdir -m 0755 -p /dev
     mount -t devtmpfs devtmpfs /dev
+    mkdir -m 0755 -p /sys
+    mount -t sysfs sysfs /sys
 fi
 
 
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index e7f892945315..3d8f29c80f95 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -669,6 +669,7 @@ in
 
       "systemd/logind.conf".text = ''
         [Login]
+        KillUserProcesses=no
         ${config.services.logind.extraConfig}
       '';
 
@@ -753,13 +754,6 @@ in
         "TMPFS_XATTR" "SECCOMP"
       ];
 
-    environment.shellAliases =
-      { start = "systemctl start";
-        stop = "systemctl stop";
-        restart = "systemctl restart";
-        status = "systemctl status";
-      };
-
     users.extraGroups.systemd-journal.gid = config.ids.gids.systemd-journal;
     users.extraUsers.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
     users.extraGroups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
diff --git a/nixos/modules/tasks/cpu-freq.nix b/nixos/modules/tasks/cpu-freq.nix
index 70bbee8474eb..1f4d1db33cef 100644
--- a/nixos/modules/tasks/cpu-freq.nix
+++ b/nixos/modules/tasks/cpu-freq.nix
@@ -38,7 +38,7 @@ in
       description = "CPU Frequency Governor Setup";
       after = [ "systemd-modules-load.service" ];
       wantedBy = [ "multi-user.target" ];
-      path = [ cpupower ];
+      path = [ cpupower config.system.sbin.modprobe ];
       unitConfig.ConditionVirtualization = false;
       serviceConfig = {
         Type = "oneshot";
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index dd351306cb63..cf8232c36154 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -111,15 +111,17 @@ in
 
     fileSystems = mkOption {
       default = {};
-      example = {
-        "/".device = "/dev/hda1";
-        "/data" = {
-          device = "/dev/hda2";
-          fsType = "ext3";
-          options = [ "data=journal" ];
-        };
-        "/bigdisk".label = "bigdisk";
-      };
+      example = literalExample ''
+        {
+          "/".device = "/dev/hda1";
+          "/data" = {
+            device = "/dev/hda2";
+            fsType = "ext3";
+            options = [ "data=journal" ];
+          };
+          "/bigdisk".label = "bigdisk";
+        }
+      '';
       type = types.loaOf types.optionSet;
       options = [ fileSystemOpts ];
       description = ''
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index f0f56b17f20f..e216351b4347 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -113,6 +113,16 @@ let kernel = config.boot.kernelPackages.kernel; in
     # Make it easy to log in as root when running the test interactively.
     users.extraUsers.root.initialHashedPassword = mkOverride 150 "";
 
+    services.xserver.displayManager.logToJournal = true;
+
+    # Bump kdm's X server start timeout to account for heavily loaded
+    # VM host systems.
+    services.xserver.displayManager.kdm.extraConfig =
+      ''
+        [X-:*-Core]
+        ServerTimeout=240
+      '';
+
   };
 
 }
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index 5d99bccb0e93..9e8417cde1df 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -32,8 +32,8 @@ let cfg = config.ec2; in
     # Generate a GRUB menu.  Amazon's pv-grub uses this to boot our kernel/initrd.
     boot.loader.grub.version = if cfg.hvm then 2 else 1;
     boot.loader.grub.device = if cfg.hvm then "/dev/xvda" else "nodev";
-    boot.loader.grub.timeout = 0;
     boot.loader.grub.extraPerEntryConfig = mkIf (!cfg.hvm) "root (hd0)";
+    boot.loader.timeout = 0;
 
     boot.initrd.postDeviceCommands =
       ''
diff --git a/nixos/modules/virtualisation/azure-common.nix b/nixos/modules/virtualisation/azure-common.nix
index eedf115ee150..70a3d752f6d1 100644
--- a/nixos/modules/virtualisation/azure-common.nix
+++ b/nixos/modules/virtualisation/azure-common.nix
@@ -10,10 +10,10 @@ with lib;
   boot.kernelParams = [ "console=ttyS0" "earlyprintk=ttyS0" "rootdelay=300" "panic=1" "boot.panic_on_fail" ];
   boot.initrd.kernelModules = [ "hv_vmbus" "hv_netvsc" "hv_utils" "hv_storvsc" ];
 
-  # Generate a GRUB menu. 
+  # Generate a GRUB menu.
   boot.loader.grub.device = "/dev/sda";
   boot.loader.grub.version = 2;
-  boot.loader.grub.timeout = 0;
+  boot.loader.timeout = 0;
 
   # Don't put old configurations in the GRUB menu.  The user has no
   # way to select them anyway.
diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix
index bcafc06e47c0..456a19fc2512 100644
--- a/nixos/modules/virtualisation/brightbox-image.nix
+++ b/nixos/modules/virtualisation/brightbox-image.nix
@@ -94,7 +94,7 @@ in
 
   # Generate a GRUB menu.  Amazon's pv-grub uses this to boot our kernel/initrd.
   boot.loader.grub.device = "/dev/vda";
-  boot.loader.grub.timeout = 0;
+  boot.loader.timeout = 0;
 
   # Don't put old configurations in the GRUB menu.  The user has no
   # way to select them anyway.
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index fca21a8610be..13ecb8e25ed5 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -309,6 +309,10 @@ in
             touch "$root/etc/os-release"
           fi
 
+          if ! [ -e "$root/etc/machine-id" ]; then
+            touch "$root/etc/machine-id"
+          fi
+
           mkdir -p -m 0755 \
             "/nix/var/nix/profiles/per-container/$INSTANCE" \
             "/nix/var/nix/gcroots/per-container/$INSTANCE"
@@ -338,7 +342,7 @@ in
             fi
           ''}
 
-
+          rm -f $root/var/lib/private/host-notify
 
           # Run systemd-nspawn without startup notification (we'll
           # wait for the container systemd to signal readiness).
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index 97b2927cf1bd..c99fc78d49e7 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -95,7 +95,7 @@ in
           LimitNPROC = 1048576;
         } // proxy_env;
 
-        path = [ pkgs.kmod ] ++ (optional (cfg.storageDriver == "zfs") pkgs.zfs);
+        path = [ config.system.sbin.modprobe ] ++ (optional (cfg.storageDriver == "zfs") pkgs.zfs);
         environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules";
 
         postStart = if cfg.socketActivation then "" else cfg.postStart;
diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix
index 38417315df5b..2b522dbe2660 100644
--- a/nixos/modules/virtualisation/google-compute-image.nix
+++ b/nixos/modules/virtualisation/google-compute-image.nix
@@ -102,7 +102,7 @@ in
 
   # Generate a GRUB menu.  Amazon's pv-grub uses this to boot our kernel/initrd.
   boot.loader.grub.device = "/dev/sda";
-  boot.loader.grub.timeout = 0;
+  boot.loader.timeout = 0;
 
   # Don't put old configurations in the GRUB menu.  The user has no
   # way to select them anyway.
diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
index 845f14352f3d..9d76b890872a 100644
--- a/nixos/modules/virtualisation/lxd.nix
+++ b/nixos/modules/virtualisation/lxd.nix
@@ -47,7 +47,7 @@ in
         # TODO(wkennington): Add lvm2 and thin-provisioning-tools
         path = with pkgs; [ acl rsync gnutar xz btrfs-progs ];
 
-        serviceConfig.ExecStart = "@${pkgs.lxd}/bin/lxd lxd --syslog --group lxd";
+        serviceConfig.ExecStart = "@${pkgs.lxd.bin}/bin/lxd lxd --syslog --group lxd";
         serviceConfig.Type = "simple";
         serviceConfig.KillMode = "process"; # when stopping, leave the containers alone
       };
diff --git a/nixos/modules/virtualisation/nova-image.nix b/nixos/modules/virtualisation/nova-image.nix
index 13e36e7888b5..7971212b47c5 100644
--- a/nixos/modules/virtualisation/nova-image.nix
+++ b/nixos/modules/virtualisation/nova-image.nix
@@ -27,7 +27,7 @@ with lib;
 
   boot.kernelParams = [ "console=ttyS0" ];
   boot.loader.grub.device = "/dev/vda";
-  boot.loader.grub.timeout = 0;
+  boot.loader.timeout = 0;
 
   # Allow root logins
   services.openssh.enable = true;
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 8aa643687557..9d9b725a805d 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -465,7 +465,7 @@ in
       });
 
     swapDevices = mkVMOverride [ ];
-    boot.initrd.luks.devices = mkVMOverride [];
+    boot.initrd.luks.devices = mkVMOverride {};
 
     # Don't run ntpd in the guest.  It should get the correct time from KVM.
     services.ntp.enable = false;
diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix
index 3a10871ce840..59bac24a7537 100644
--- a/nixos/modules/virtualisation/virtualbox-guest.nix
+++ b/nixos/modules/virtualisation/virtualbox-guest.nix
@@ -77,7 +77,7 @@ in
         KERNEL=="vboxuser",  OWNER="root", GROUP="root", MODE="0666"
 
         # Allow systemd dependencies on vboxguest.
-        KERNEL=="vboxguest", TAG+="systemd"
+        SUBSYSTEM=="misc", KERNEL=="vboxguest", TAG+="systemd"
       '';
   };
 
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index c8c4df5c9138..f275291c716c 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -69,6 +69,7 @@ in rec {
         (all nixos.tests.boot.uefiUsb)
         (all nixos.tests.boot-stage1)
         (all nixos.tests.ipv6)
+        (all nixos.tests.i3wm)
         (all nixos.tests.kde4)
         #(all nixos.tests.lightdm)
         (all nixos.tests.login)
diff --git a/nixos/tests/boot.nix b/nixos/tests/boot.nix
index af7db5aa8164..3ea0df65c8b5 100644
--- a/nixos/tests/boot.nix
+++ b/nixos/tests/boot.nix
@@ -12,7 +12,6 @@ let
       modules =
         [ ../modules/installer/cd-dvd/installation-cd-minimal.nix
           ../modules/testing/test-instrumentation.nix
-          { key = "serial"; }
         ];
     }).config.system.build.isoImage;
 
@@ -30,20 +29,25 @@ let
         '';
     };
 in {
+
     biosCdrom = makeBootTest "bios-cdrom" ''
         cdrom => glob("${iso}/iso/*.iso")
       '';
+
     biosUsb = makeBootTest "bios-usb" ''
         usb => glob("${iso}/iso/*.iso")
       '';
+
     uefiCdrom = makeBootTest "uefi-cdrom" ''
         cdrom => glob("${iso}/iso/*.iso"),
         bios => '${pkgs.OVMF}/FV/OVMF.fd'
       '';
+
     uefiUsb = makeBootTest "uefi-usb" ''
         usb => glob("${iso}/iso/*.iso"),
         bios => '${pkgs.OVMF}/FV/OVMF.fd'
       '';
+
     netboot = let
       config = (import ../lib/eval-config.nix {
           inherit system;
diff --git a/nixos/tests/gnome3_20-gdm.nix b/nixos/tests/gnome3_20-gdm.nix
new file mode 100644
index 000000000000..8b1e9afedfb9
--- /dev/null
+++ b/nixos/tests/gnome3_20-gdm.nix
@@ -0,0 +1,41 @@
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "gnome3-gdm";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ lethalman ];
+  };
+
+  machine =
+    { config, pkgs, ... }:
+
+    { imports = [ ./common/user-account.nix ];
+
+      services.xserver.enable = true;
+
+      services.xserver.displayManager.gdm = {
+        enable = true;
+        autoLogin = {
+          enable = true;
+          user = "alice";
+        };
+      };
+      services.xserver.desktopManager.gnome3.enable = true;
+      environment.gnome3.packageSet = pkgs.gnome3_20;
+
+      virtualisation.memorySize = 512;
+    };
+
+  testScript =
+    ''
+      $machine->waitForX;
+      $machine->sleep(15);
+
+      # Check that logging in has given the user ownership of devices.
+      $machine->succeed("getfacl /dev/snd/timer | grep -q alice");
+
+      $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'");
+      $machine->succeed("xauth merge ~alice/.Xauthority");
+      $machine->waitForWindow(qr/Terminal/);
+      $machine->sleep(20);
+      $machine->screenshot("screen");
+    '';
+})
diff --git a/nixos/tests/gnome3_20.nix b/nixos/tests/gnome3_20.nix
new file mode 100644
index 000000000000..51c83a4e3129
--- /dev/null
+++ b/nixos/tests/gnome3_20.nix
@@ -0,0 +1,38 @@
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "gnome3";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ domenkozar eelco chaoflow lethalman ];
+  };
+
+  machine =
+    { config, pkgs, ... }:
+
+    { imports = [ ./common/user-account.nix ];
+
+      services.xserver.enable = true;
+
+      services.xserver.displayManager.auto.enable = true;
+      services.xserver.displayManager.auto.user = "alice";
+      services.xserver.desktopManager.gnome3.enable = true;
+
+      environment.gnome3.packageSet = pkgs.gnome3_20;
+
+      virtualisation.memorySize = 512;
+    };
+
+  testScript =
+    ''
+      $machine->waitForX;
+      $machine->sleep(15);
+
+      # Check that logging in has given the user ownership of devices.
+      $machine->succeed("getfacl /dev/snd/timer | grep -q alice");
+
+      $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'");
+      $machine->succeed("xauth merge ~alice/.Xauthority");
+      $machine->waitForWindow(qr/Terminal/);
+      $machine->mustSucceed("timeout 900 bash -c 'journalctl -f|grep -m 1 \"GNOME Shell started\"'");
+      $machine->sleep(10);
+      $machine->screenshot("screen");
+    '';
+})
diff --git a/nixos/tests/grsecurity.nix b/nixos/tests/grsecurity.nix
index 14f1aa9ff885..aadbfd8371ff 100644
--- a/nixos/tests/grsecurity.nix
+++ b/nixos/tests/grsecurity.nix
@@ -3,17 +3,39 @@
 import ./make-test.nix ({ pkgs, ...} : {
   name = "grsecurity";
   meta = with pkgs.stdenv.lib.maintainers; {
-    maintainers = [ copumpkin ];
+    maintainers = [ copumpkin joachifm ];
   };
 
   machine = { config, pkgs, ... }:
-    { boot.kernelPackages = pkgs.linuxPackages_grsec_testing_server; };
+    { security.grsecurity.enable = true;
+      boot.kernel.sysctl."kernel.grsecurity.deter_bruteforce" = 0;
+      security.apparmor.enable = true;
+    };
 
-  testScript =
-    ''
-      $machine->succeed("uname -a") =~ /grsec/;
-      # FIXME: this seems to hang the whole test. Unclear why, but let's fix it
-      # $machine->succeed("${pkgs.paxtest}/bin/paxtest blackhat");
-    '';
-})
+  testScript = ''
+    subtest "grsec-lock", sub {
+      $machine->succeed("systemctl is-active grsec-lock");
+      $machine->succeed("grep -Fq 1 /proc/sys/kernel/grsecurity/grsec_lock");
+      $machine->fail("echo -n 0 >/proc/sys/kernel/grsecurity/grsec_lock");
+    };
+
+    subtest "paxtest", sub {
+      # TODO: running paxtest blackhat hangs the vm
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/anonmap") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/execbss") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/execdata") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/execheap") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/execstack") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotanon") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotbss") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotdata") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotheap") =~ /Killed/ or die;
+      $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotstack") =~ /Killed/ or die;
+    };
 
+    subtest "tcc", sub {
+      $machine->execute("echo -e '#include <stdio.h>\nint main(void) { puts(\"hello\"); return 0; }' >main.c");
+      $machine->succeed("${pkgs.tinycc.bin}/bin/tcc -run main.c");
+    };
+  '';
+})
diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 0b0e53ee7324..4a30cc18b021 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -30,8 +30,8 @@ let
           boot.loader.grub.configurationLimit = 100 + ${toString forceGrubReinstallCount};
         ''}
 
-        ${optionalString (bootLoader == "gummiboot") ''
-          boot.loader.gummiboot.enable = true;
+        ${optionalString (bootLoader == "systemd-boot") ''
+          boot.loader.systemd-boot.enable = true;
         ''}
 
         hardware.enableAllFirmware = lib.mkForce false;
@@ -57,7 +57,7 @@ let
         (if system == "x86_64-linux" then "-m 768 " else "-m 512 ") +
         (optionalString (system == "x86_64-linux") "-cpu kvm64 ");
       hdFlags = ''hda => "vm-state-machine/machine.qcow2", hdaInterface => "${iface}", ''
-        + optionalString (bootLoader == "gummiboot") ''bios => "${pkgs.OVMF}/FV/OVMF.fd", '';
+        + optionalString (bootLoader == "systemd-boot") ''bios => "${pkgs.OVMF}/FV/OVMF.fd", '';
     in
     ''
       $machine->start;
@@ -159,7 +159,7 @@ let
 
   makeInstallerTest = name:
     { createPartitions, preBootCommands ? "", extraConfig ? ""
-    , bootLoader ? "grub" # either "grub" or "gummiboot"
+    , bootLoader ? "grub" # either "grub" or "systemd-boot"
     , grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid"
     , enableOCR ? false, meta ? {}
     }:
@@ -195,7 +195,7 @@ let
             virtualisation.qemu.diskInterface =
               if grubVersion == 1 then "scsi" else "virtio";
 
-            boot.loader.gummiboot.enable = mkIf (bootLoader == "gummiboot") true;
+            boot.loader.systemd-boot.enable = mkIf (bootLoader == "systemd-boot") true;
 
             hardware.enableAllFirmware = mkForce false;
 
@@ -208,7 +208,6 @@ let
                 pkgs.unionfs-fuse
                 pkgs.ntp
                 pkgs.nixos-artwork
-                pkgs.gummiboot
                 pkgs.perlPackages.XMLLibXML
                 pkgs.perlPackages.ListCompare
               ]
@@ -250,7 +249,7 @@ in {
         '';
     };
 
-  # Simple GPT/UEFI configuration using Gummiboot with 3 partitions: ESP, swap & root filesystem
+  # Simple GPT/UEFI configuration using systemd-boot with 3 partitions: ESP, swap & root filesystem
   simpleUefiGummiboot = makeInstallerTest "simpleUefiGummiboot"
     { createPartitions =
         ''
@@ -270,7 +269,7 @@ in {
               "mount LABEL=BOOT /mnt/boot",
           );
         '';
-        bootLoader = "gummiboot";
+        bootLoader = "systemd-boot";
     };
 
   # Same as the previous, but now with a separate /boot partition.
@@ -360,14 +359,8 @@ in {
           "mount LABEL=boot /mnt/boot",
         );
       '';
-      # XXX: Currently, generate-config doesn't detect LUKS yet.
       extraConfig = ''
         boot.kernelParams = lib.mkAfter [ "console=tty0" ];
-        boot.initrd.luks.devices = lib.singleton {
-          name = "cryptroot";
-          device = "/dev/vda3";
-          preLVM = true;
-        };
       '';
       enableOCR = true;
       preBootCommands = ''
@@ -403,8 +396,6 @@ in {
               "mkdir /mnt/boot",
               "mount LABEL=boot /mnt/boot",
               "udevadm settle",
-              "mdadm --verbose -W /dev/md0", # wait for sync to finish; booting off an unsynced device tends to fail
-              "mdadm --verbose -W /dev/md1",
           );
         '';
       preBootCommands = ''
diff --git a/nixos/tests/sddm-kde5.nix b/nixos/tests/sddm-kde5.nix
index f97a6d12b63c..0247d267aaa4 100644
--- a/nixos/tests/sddm-kde5.nix
+++ b/nixos/tests/sddm-kde5.nix
@@ -1,4 +1,6 @@
-import ./make-test.nix ({ pkgs, ...} : {
+import ./make-test.nix ({ pkgs, ...} :
+
+{
   name = "sddm";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ ttuegel ];
@@ -6,6 +8,7 @@ import ./make-test.nix ({ pkgs, ...} : {
 
   machine = { lib, ... }: {
     imports = [ ./common/user-account.nix ];
+    virtualisation.memorySize = 1024;
     services.xserver.enable = true;
     services.xserver.displayManager.sddm = {
       enable = true;
@@ -14,18 +17,38 @@ import ./make-test.nix ({ pkgs, ...} : {
         user = "alice";
       };
     };
-    services.xserver.windowManager.default = "icewm";
-    services.xserver.windowManager.icewm.enable = true;
-    services.xserver.desktopManager.default = "none";
     services.xserver.desktopManager.kde5.enable = true;
   };
 
   enableOCR = true;
 
-  testScript = { nodes, ... }: ''
-    startAll;
-    $machine->waitForFile("/home/alice/.Xauthority");
-    $machine->succeed("xauth merge ~alice/.Xauthority");
-    $machine->waitForWindow("^IceWM ");
+  testScript = { nodes, ... }:
+  let xdo = "${pkgs.xdotool}/bin/xdotool"; in
+   ''     
+    sub krunner {
+      my ($win,) = @_;
+      $machine->execute("${xdo} key Alt+F2 sleep 1 type $win");
+      $machine->execute("${xdo} search --sync --onlyvisible --class krunner sleep 5 key Return");
+    }
+
+    $machine->waitUntilSucceeds("pgrep plasmashell");
+    $machine->succeed("xauth merge ~alice/.Xauthority");    
+    $machine->waitForWindow(qr/Desktop.*/);
+
+    # Check that logging in has given the user ownership of devices.
+    $machine->succeed("getfacl /dev/snd/timer | grep -q alice");
+    
+    krunner("dolphin");
+    $machine->waitForWindow(qr/.*Dolphin/);
+    
+    krunner("konsole");
+    $machine->waitForWindow(qr/.*Konsole/);
+    
+    krunner("systemsettings5");
+    $machine->waitForWindow(qr/.*Settings/);
+    $machine->sleep(20);
+
+    $machine->execute("${xdo} key Alt+F1 sleep 10");
+    $machine->screenshot("screen");
   '';
 })
diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix
index da4c0bddc348..e9bc14a6cdb4 100644
--- a/nixos/tests/virtualbox.nix
+++ b/nixos/tests/virtualbox.nix
@@ -11,7 +11,7 @@ let
       #!${pkgs.stdenv.shell} -xe
       export PATH="${pkgs.coreutils}/bin:${pkgs.utillinux}/bin"
 
-      mkdir -p /etc/dbus-1 /var/run/dbus
+      mkdir -p /var/run/dbus
       cat > /etc/passwd <<EOF
       root:x:0:0::/root:/bin/false
       messagebus:x:1:1::/var/run/dbus:/bin/false
@@ -20,9 +20,9 @@ let
       root:x:0:
       messagebus:x:1:
       EOF
-      cp -v "${pkgs.dbus.daemon}/etc/dbus-1/system.conf" \
-        /etc/dbus-1/system.conf
-      "${pkgs.dbus.daemon}/bin/dbus-daemon" --fork --system
+
+      "${pkgs.dbus.daemon}/bin/dbus-daemon" --fork \
+        --config-file="${pkgs.dbus.daemon}/share/dbus-1/system.conf"
 
       ${guestAdditions}/bin/VBoxService
       ${(attrs.vmScript or (const "")) pkgs}
@@ -326,6 +326,7 @@ let
       in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs;
       virtualisation.memorySize = 2048;
       virtualisation.virtualbox.host.enable = true;
+      services.xserver.displayManager.auto.user = "alice";
       users.extraUsers.alice.extraGroups = let
         inherit (config.virtualisation.virtualbox.host) enableHardening;
       in lib.mkIf enableHardening (lib.singleton "vboxusers");
@@ -363,7 +364,9 @@ in mapAttrs mkVBoxTest {
   simple-gui = ''
     createVM_simple;
     $machine->succeed(ru "VirtualBox &");
-    $machine->waitForWindow(qr/Oracle VM VirtualBox Manager/);
+    $machine->waitUntilSucceeds(
+      ru "xprop -name 'Oracle VM VirtualBox Manager'"
+    );
     $machine->sleep(5);
     $machine->screenshot("gui_manager_started");
     $machine->sendKeys("ret");