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/configuration/configuration.xml1
-rw-r--r--nixos/doc/manual/configuration/profiles.xml39
-rw-r--r--nixos/doc/manual/configuration/profiles/all-hardware.xml20
-rw-r--r--nixos/doc/manual/configuration/profiles/base.xml15
-rw-r--r--nixos/doc/manual/configuration/profiles/clone-config.xml14
-rw-r--r--nixos/doc/manual/configuration/profiles/demo.xml13
-rw-r--r--nixos/doc/manual/configuration/profiles/docker-container.xml15
-rw-r--r--nixos/doc/manual/configuration/profiles/graphical.xml21
-rw-r--r--nixos/doc/manual/configuration/profiles/hardened.xml22
-rw-r--r--nixos/doc/manual/configuration/profiles/headless.xml18
-rw-r--r--nixos/doc/manual/configuration/profiles/installation-device.xml35
-rw-r--r--nixos/doc/manual/configuration/profiles/minimal.xml17
-rw-r--r--nixos/doc/manual/configuration/profiles/qemu-guest.xml16
-rw-r--r--nixos/doc/manual/development/option-types.xml13
-rw-r--r--nixos/doc/manual/release-notes/rl-1903.xml43
-rw-r--r--nixos/lib/build-vms.nix16
-rw-r--r--nixos/lib/testing.nix15
-rw-r--r--nixos/modules/config/gtk/gtk-icon-cache.nix86
-rw-r--r--nixos/modules/config/networking.nix4
-rw-r--r--nixos/modules/config/system-path.nix4
-rw-r--r--nixos/modules/hardware/ckb-next.nix49
-rw-r--r--nixos/modules/hardware/ckb.nix40
-rw-r--r--nixos/modules/installer/tools/nixos-build-vms/build-vms.nix6
-rw-r--r--nixos/modules/misc/ids.nix8
-rw-r--r--nixos/modules/misc/nixpkgs.nix58
-rw-r--r--nixos/modules/misc/version.nix4
-rw-r--r--nixos/modules/module-list.nix8
-rw-r--r--nixos/modules/programs/dmrconfig.nix38
-rw-r--r--nixos/modules/rename.nix4
-rw-r--r--nixos/modules/services/amqp/rabbitmq.nix29
-rw-r--r--nixos/modules/services/backup/bacula.nix24
-rw-r--r--nixos/modules/services/backup/postgresql-backup.nix2
-rw-r--r--nixos/modules/services/databases/mysql.nix4
-rw-r--r--nixos/modules/services/development/jupyter/default.nix1
-rw-r--r--nixos/modules/services/games/minetest-server.nix3
-rw-r--r--nixos/modules/services/mail/rspamd.nix107
-rw-r--r--nixos/modules/services/misc/exhibitor.nix3
-rw-r--r--nixos/modules/services/misc/gitea.nix12
-rw-r--r--nixos/modules/services/misc/gitlab.nix4
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix18
-rw-r--r--nixos/modules/services/monitoring/alerta.nix116
-rw-r--r--nixos/modules/services/monitoring/grafana-reporter.nix66
-rw-r--r--nixos/modules/services/monitoring/kapacitor.nix38
-rw-r--r--nixos/modules/services/monitoring/monit.nix33
-rw-r--r--nixos/modules/services/network-filesystems/glusterfs.nix7
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix2
-rw-r--r--nixos/modules/services/system/cloud-init.nix29
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix7
-rw-r--r--nixos/modules/services/web-apps/selfoss.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix14
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/xpra.nix44
-rw-r--r--nixos/modules/services/x11/xserver.nix5
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh5
-rw-r--r--nixos/modules/tasks/filesystems/bcachefs.nix61
-rw-r--r--nixos/modules/virtualisation/gce-images.nix4
-rw-r--r--nixos/release.nix241
-rw-r--r--nixos/tests/all-tests.nix214
-rw-r--r--nixos/tests/boot.nix7
-rw-r--r--nixos/tests/buildbot.nix7
-rw-r--r--nixos/tests/certmgr.nix7
-rw-r--r--nixos/tests/chromium.nix5
-rw-r--r--nixos/tests/cloud-init.nix7
-rw-r--r--nixos/tests/ec2.nix7
-rw-r--r--nixos/tests/elk.nix10
-rw-r--r--nixos/tests/gitea.nix77
-rw-r--r--nixos/tests/gitlab.nix1
-rw-r--r--nixos/tests/handbrake.nix25
-rwxr-xr-xnixos/tests/hydra/create-trivial-project.sh3
-rw-r--r--nixos/tests/incron.nix52
-rw-r--r--nixos/tests/installer.nix7
-rw-r--r--nixos/tests/kafka.nix8
-rw-r--r--nixos/tests/keymap.nix7
-rw-r--r--nixos/tests/kubernetes/base.nix7
-rw-r--r--nixos/tests/make-test.nix8
-rw-r--r--nixos/tests/networking.nix4
-rw-r--r--nixos/tests/nextcloud/default.nix11
-rw-r--r--nixos/tests/opensmtpd.nix2
-rw-r--r--nixos/tests/postgresql.nix10
-rw-r--r--nixos/tests/predictable-interface-names.nix7
-rw-r--r--nixos/tests/rspamd.nix109
-rw-r--r--nixos/tests/rsyslogd.nix8
-rw-r--r--nixos/tests/run-in-machine.nix7
-rw-r--r--nixos/tests/sddm.nix7
-rw-r--r--nixos/tests/statsd.nix51
-rw-r--r--nixos/tests/virtualbox.nix11
-rw-r--r--nixos/tests/zfs.nix7
87 files changed, 1678 insertions, 542 deletions
diff --git a/nixos/doc/manual/configuration/configuration.xml b/nixos/doc/manual/configuration/configuration.xml
index 8d05dcd34b4d..cebc4122c6c6 100644
--- a/nixos/doc/manual/configuration/configuration.xml
+++ b/nixos/doc/manual/configuration/configuration.xml
@@ -22,5 +22,6 @@
  <xi:include href="networking.xml" />
  <xi:include href="linux-kernel.xml" />
  <xi:include href="../generated/modules.xml" xpointer="xpointer(//section[@id='modules']/*)" />
+ <xi:include href="profiles.xml" />
 <!-- Apache; libvirtd virtualisation -->
 </part>
diff --git a/nixos/doc/manual/configuration/profiles.xml b/nixos/doc/manual/configuration/profiles.xml
new file mode 100644
index 000000000000..92c0f6202f28
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles.xml
@@ -0,0 +1,39 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="ch-profiles">
+ <title>Profiles</title>
+ <para>
+  In some cases, it may be desirable to take advantage of commonly-used,
+  predefined configurations provided by nixpkgs, but different from those that
+  come as default. This is a role fulfilled by NixOS's Profiles, which come as
+  files living in <filename>&lt;nixpkgs/nixos/modules/profiles&gt;</filename>.
+  That is to say, expected usage is to add them to the imports list of your
+  <filename>/etc/configuration.nix</filename> as such:
+ </para>
+ <programlisting>
+  imports = [
+   &lt;nixpkgs/nixos/modules/profiles/profile-name.nix&gt;
+  ];
+ </programlisting>
+ <para>
+  Even if some of these profiles seem only useful in the context of
+  install media, many are actually intended to be used in real installs.
+ </para>
+ <para>
+  What follows is a brief explanation on the purpose and use-case for each
+  profile. Detailing each option configured by each one is out of scope.
+ </para>
+ <xi:include href="profiles/all-hardware.xml" />
+ <xi:include href="profiles/base.xml" />
+ <xi:include href="profiles/clone-config.xml" />
+ <xi:include href="profiles/demo.xml" />
+ <xi:include href="profiles/docker-container.xml" />
+ <xi:include href="profiles/graphical.xml" />
+ <xi:include href="profiles/hardened.xml" />
+ <xi:include href="profiles/headless.xml" />
+ <xi:include href="profiles/installation-device.xml" />
+ <xi:include href="profiles/minimal.xml" />
+ <xi:include href="profiles/qemu-guest.xml" />
+</chapter>
diff --git a/nixos/doc/manual/configuration/profiles/all-hardware.xml b/nixos/doc/manual/configuration/profiles/all-hardware.xml
new file mode 100644
index 000000000000..172975199474
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/all-hardware.xml
@@ -0,0 +1,20 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-all-hardware">
+ <title>All Hardware</title>
+ <para>
+  Enables all hardware supported by NixOS: i.e., all firmware is
+  included, and all devices from which one may boot are enabled in the initrd.
+  Its primary use is in the NixOS installation CDs.
+ </para>
+ <para>
+  The enabled kernel modules include support for SATA and PATA, SCSI
+  (partially), USB, Firewire (untested), Virtio (QEMU, KVM, etc.), VMware, and
+  Hyper-V. Additionally, <xref linkend="opt-hardware.enableAllFirmware"/> is
+  enabled, and the firmware for the ZyDAS ZD1211 chipset is specifically
+  installed.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/base.xml b/nixos/doc/manual/configuration/profiles/base.xml
new file mode 100644
index 000000000000..f58a35d626ed
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/base.xml
@@ -0,0 +1,15 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-base">
+ <title>Base</title>
+ <para>
+  Defines the software packages included in the "minimal"
+  installation CD. It installs several utilities useful in a simple recovery or
+  install media, such as a text-mode web browser, and tools for manipulating
+  block devices, networking, hardware diagnostics, and filesystems (with their
+  respective kernel modules).
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/clone-config.xml b/nixos/doc/manual/configuration/profiles/clone-config.xml
new file mode 100644
index 000000000000..87c8b9ee31b6
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/clone-config.xml
@@ -0,0 +1,14 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-clone-config">
+ <title>Clone Config</title>
+ <para>
+  This profile is used in installer images.
+  It provides an editable configuration.nix that imports all the modules that
+  were also used when creating the image in the first place.
+  As a result it allows users to edit and rebuild the live-system.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/demo.xml b/nixos/doc/manual/configuration/profiles/demo.xml
new file mode 100644
index 000000000000..98829e4696df
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/demo.xml
@@ -0,0 +1,13 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-demo">
+ <title>Demo</title>
+ <para>
+  This profile just enables a <systemitem class="username">demo</systemitem> user, with password <literal>demo</literal>, uid <literal>1000</literal>, <systemitem class="groupname">wheel</systemitem>
+  group and <link linkend="opt-services.xserver.displayManager.sddm.autoLogin">
+   autologin in the SDDM display manager</link>.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/docker-container.xml b/nixos/doc/manual/configuration/profiles/docker-container.xml
new file mode 100644
index 000000000000..bf962442ccef
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/docker-container.xml
@@ -0,0 +1,15 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-docker-container">
+ <title>Docker Container</title>
+ <para>
+  This is the profile from which the Docker images are generated. It prepares a
+  working system by importing the <link linkend="sec-profile-minimal">Minimal</link> and
+  <link linkend="sec-profile-clone-config">Clone Config</link> profiles, and setting appropriate
+  configuration options that are useful inside a container context, like
+  <xref linkend="opt-boot.isContainer"/>.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/graphical.xml b/nixos/doc/manual/configuration/profiles/graphical.xml
new file mode 100644
index 000000000000..5ded61d9763b
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/graphical.xml
@@ -0,0 +1,21 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-graphical">
+ <title>Graphical</title>
+ <para>
+  Defines a NixOS configuration with the Plasma 5 desktop. It's used by the
+  graphical installation CD.
+ </para>
+ <para>
+  It sets <xref linkend="opt-services.xserver.enable"/>,
+  <xref linkend="opt-services.xserver.displayManager.sddm.enable"/>,
+  <xref linkend="opt-services.xserver.desktopManager.plasma5.enable"/> (
+  <link linkend="opt-services.xserver.desktopManager.plasma5.enableQt4Support">
+   without Qt4 Support</link>), and
+  <xref linkend="opt-services.xserver.libinput.enable"/> to true. It also
+  includes glxinfo and firefox in the system packages list.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/hardened.xml b/nixos/doc/manual/configuration/profiles/hardened.xml
new file mode 100644
index 000000000000..b3b433792f53
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/hardened.xml
@@ -0,0 +1,22 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-hardened">
+ <title>Hardened</title>
+ <para>
+  A profile with most (vanilla) hardening options enabled by default,
+  potentially at the cost of features and performance.
+ </para>
+ <para>
+  This includes a hardened kernel, and limiting the system information
+  available to processes through the <filename>/sys</filename> and
+  <filename>/proc</filename> filesystems. It also disables the User Namespaces
+  feature of the kernel, which stops Nix from being able to build anything
+  (this particular setting can be overriden via
+  <xref linkend="opt-security.allowUserNamespaces"/>). See the <literal
+   xlink:href="https://github.com/nixos/nixpkgs/tree/master/nixos/modules/profiles/hardened.nix">
+   profile source</literal> for further detail on which settings are altered.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/headless.xml b/nixos/doc/manual/configuration/profiles/headless.xml
new file mode 100644
index 000000000000..54dc61f236e0
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/headless.xml
@@ -0,0 +1,18 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-headless">
+ <title>Headless</title>
+ <para>
+  Common configuration for headless machines (e.g., Amazon EC2 instances).
+ </para>
+ <para>
+  Disables <link linkend="opt-sound.enable">sound</link>,
+  <link linkend="opt-boot.vesa">vesa</link>, serial consoles,
+  <link linkend="opt-systemd.enableEmergencyMode">emergency mode</link>,
+  <link linkend="opt-boot.loader.grub.splashImage">grub splash images</link> and
+  configures the kernel to reboot automatically on panic.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/installation-device.xml b/nixos/doc/manual/configuration/profiles/installation-device.xml
new file mode 100644
index 000000000000..44ccfc538ad1
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/installation-device.xml
@@ -0,0 +1,35 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-installation-device">
+ <title>Installation Device</title>
+ <para>
+  Provides a basic configuration for installation devices like CDs. This means
+  enabling hardware scans, using the <link linkend="sec-profile-clone-config">
+   Clone Config profile</link> to guarantee
+  <filename>/etc/nixos/configuration.nix</filename> exists (for
+  <command>nixos-rebuild</command> to work), a copy of the Nixpkgs channel
+  snapshot used to create the install media.
+ </para>
+ <para>
+  Additionally, documentation for <link linkend="opt-documentation.enable">
+   Nixpkgs</link> and <link linkend="opt-documentation.nixos.enable">NixOS
+   </link> are forcefully enabled (to override the
+   <link linkend="sec-profile-minimal">Minimal profile</link> preference); the
+   NixOS manual is shown automatically on TTY 8, sudo and udisks are disabled.
+   Autologin is enabled as root.
+ </para>
+ <para>
+  A message is shown to the user to start a display manager if needed,
+  ssh with <xref linkend="opt-services.openssh.permitRootLogin"/> are enabled (but
+  doesn't autostart). WPA Supplicant is also enabled without autostart.
+ </para>
+ <para>
+  Finally, vim is installed, root is set to not have a password, the kernel is
+  made more silent for remote public IP installs, and several settings are
+  tweaked so that the installer has a better chance of succeeding under
+  low-memory environments.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/minimal.xml b/nixos/doc/manual/configuration/profiles/minimal.xml
new file mode 100644
index 000000000000..a24af21bd7f7
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/minimal.xml
@@ -0,0 +1,17 @@
+
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-minimal">
+ <title>Minimal</title>
+ <para>
+  This profile defines a small NixOS configuration. It does not contain any
+  graphical stuff. It's a very short file that enables
+  <link linkend="opt-environment.noXlibs">noXlibs</link>, sets
+  <link linkend="opt-i18n.supportedLocales">i18n.supportedLocales</link>
+  to only support the user-selected locale,
+  <link linkend="opt-documentation.enable">disables packages' documentation
+  </link>, and <link linkend="opt-sound.enable">disables sound</link>.
+ </para>
+</section>
diff --git a/nixos/doc/manual/configuration/profiles/qemu-guest.xml b/nixos/doc/manual/configuration/profiles/qemu-guest.xml
new file mode 100644
index 000000000000..d08068650fbe
--- /dev/null
+++ b/nixos/doc/manual/configuration/profiles/qemu-guest.xml
@@ -0,0 +1,16 @@
+<section xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="sec-profile-qemu-guest">
+ <title>QEMU Guest</title>
+ <para>
+  This profile contains common configuration for virtual machines running under
+  QEMU (using virtio).
+ </para>
+ <para>
+  It makes virtio modules available on the initrd, sets the system time from
+  the hardware clock to work around a bug in qemu-kvm, and
+  <link linkend="opt-security.rngd.enable">enables rngd</link>.
+ </para>
+</section>
diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml
index e6c9eae11a72..d993e47bc914 100644
--- a/nixos/doc/manual/development/option-types.xml
+++ b/nixos/doc/manual/development/option-types.xml
@@ -106,7 +106,7 @@
      </para>
     </listitem>
    </varlistentry>
-   <varlistentry>
+   <varlistentry xml:id='types.ints.ux'>
     <term>
      <varname>types.ints.{u8, u16, u32}</varname>
     </term>
@@ -131,6 +131,17 @@
      </para>
     </listitem>
    </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.port</varname>
+    </term>
+    <listitem>
+     <para>
+      A port number. This type is an alias to
+      <link linkend='types.ints.ux'><varname>types.ints.u16</varname></link>.
+     </para>
+    </listitem>
+   </varlistentry>
   </variablelist>
 
   <para>
diff --git a/nixos/doc/manual/release-notes/rl-1903.xml b/nixos/doc/manual/release-notes/rl-1903.xml
index a3cfa7784996..a1f715a3adf1 100644
--- a/nixos/doc/manual/release-notes/rl-1903.xml
+++ b/nixos/doc/manual/release-notes/rl-1903.xml
@@ -97,20 +97,20 @@
        start org.nixos.nix-daemon</command>.
       </para>
      </listitem>
-     <listitem>
-      <para>
-        The Syncthing state and configuration data has been moved from
-        <varname>services.syncthing.dataDir</varname> to the newly defined
-        <varname>services.syncthing.configDir</varname>, which default to
-        <literal>/var/lib/syncthing/.config/syncthing</literal>.
-        This change makes possible to share synced directories using ACLs
-        without Syncthing resetting the permission on every start.
-      </para>
-     </listitem>
     </itemizedlist>
    </listitem>
    <listitem>
     <para>
+      The Syncthing state and configuration data has been moved from
+      <varname>services.syncthing.dataDir</varname> to the newly defined
+      <varname>services.syncthing.configDir</varname>, which default to
+      <literal>/var/lib/syncthing/.config/syncthing</literal>.
+      This change makes possible to share synced directories using ACLs
+      without Syncthing resetting the permission on every start.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      Package <varname>rabbitmq_server</varname> is renamed to
      <varname>rabbitmq-server</varname>.
     </para>
@@ -149,6 +149,14 @@
    </listitem>
    <listitem>
     <para>
+     When the <literal>nixpkgs.pkgs</literal> option is set, NixOS will no
+     longer ignore the <literal>nixpkgs.overlays</literal> option. The old
+     behavior can be recovered by setting <literal>nixpkgs.overlays =
+     lib.mkForce [];</literal>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      OpenSMTPD has been upgraded to version 6.4.0p1. This release makes
      backwards-incompatible changes to the configuration file format. See
      <command>man smtpd.conf</command> for more information on the new file
@@ -197,6 +205,21 @@
       these changes. Please review http://lucene.apache.org/solr/ carefully before upgrading.
     </para>
    </listitem>
+   <listitem>
+    <para>
+     Package <literal>ckb</literal> is renamed to <literal>ckb-next</literal>,
+     and options <literal>hardware.ckb.*</literal> are renamed to
+     <literal>hardware.ckb-next.*</literal>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The option <literal>services.xserver.displayManager.job.logToFile</literal> which was
+     previously set to <literal>true</literal> when using the display managers
+     <literal>lightdm</literal>, <literal>sddm</literal> or <literal>xpra</literal> has been
+     reset to the default value (<literal>false</literal>).
+    </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/lib/build-vms.nix b/nixos/lib/build-vms.nix
index 4f65501f89c6..024f4414ebeb 100644
--- a/nixos/lib/build-vms.nix
+++ b/nixos/lib/build-vms.nix
@@ -1,6 +1,13 @@
-{ system, minimal ? false, config ? {} }:
-
-let pkgs = import ../.. { inherit system config; }; in
+{ system
+, # Use a minimal kernel?
+  minimal ? false
+, # Ignored
+  config ? null
+  # Nixpkgs, for qemu, lib and more
+, pkgs
+, # NixOS configuration to add to the VMs
+  extraConfigurations ? []
+}:
 
 with pkgs.lib;
 with import ../lib/qemu-flags.nix { inherit pkgs; };
@@ -30,7 +37,8 @@ rec {
           ../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs
           { key = "no-manual"; documentation.nixos.enable = false; }
           { key = "qemu"; system.build.qemu = qemu; }
-        ] ++ optional minimal ../modules/testing/minimal-kernel.nix;
+        ] ++ optional minimal ../modules/testing/minimal-kernel.nix
+          ++ extraConfigurations;
       extraArgs = { inherit nodes; };
     };
 
diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix
index 42a0c60c7e19..690f7dfd5fac 100644
--- a/nixos/lib/testing.nix
+++ b/nixos/lib/testing.nix
@@ -1,6 +1,13 @@
-{ system, minimal ? false, config ? {} }:
-
-with import ./build-vms.nix { inherit system minimal config; };
+{ system
+, pkgs
+  # Use a minimal kernel?
+, minimal ? false
+  # Ignored
+, config ? null
+  # Modules to add to each VM
+, extraConfigurations ? [] }:
+
+with import ./build-vms.nix { inherit system pkgs minimal extraConfigurations; };
 with pkgs;
 
 let
@@ -69,7 +76,7 @@ in rec {
             mkdir -p $out/coverage-data
             mv $i $out/coverage-data/$(dirname $(dirname $i))
           done
-        ''; # */
+        '';
     };
 
 
diff --git a/nixos/modules/config/gtk/gtk-icon-cache.nix b/nixos/modules/config/gtk/gtk-icon-cache.nix
new file mode 100644
index 000000000000..d4e0cf97c660
--- /dev/null
+++ b/nixos/modules/config/gtk/gtk-icon-cache.nix
@@ -0,0 +1,86 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+{
+  options = {
+    gtk.iconCache.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to build icon theme caches for GTK+ applications.
+      '';
+    };
+  };
+
+  config = mkIf config.gtk.iconCache.enable {
+
+    # (Re)build icon theme caches
+    # ---------------------------
+    # Each icon theme has its own cache. The difficult is that many
+    # packages may contribute with icons to the same theme by installing
+    # some icons.
+    #
+    # For instance, on my current NixOS system, the following packages
+    # (among many others) have icons installed into the hicolor icon
+    # theme: hicolor-icon-theme, psensor, wpa_gui, caja, etc.
+    #
+    # As another example, the mate icon theme has icons installed by the
+    # packages mate-icon-theme, mate-settings-daemon, and libmateweather.
+    #
+    # The HighContrast icon theme also has icons from different packages,
+    # like gnome-theme-extras and meld.
+
+    # When the cache is built all of its icons has to be known. How to
+    # implement this?
+    #
+    # I think that most themes have all icons installed by only one
+    # package. On my system there are 71 themes installed. Only 3 of them
+    # have icons installed from more than one package.
+    #
+    # If the main package of the theme provides a cache, presumably most
+    # of its icons will be available to applications without running this
+    # module. But additional icons offered by other packages will not be
+    # available. Therefore I think that it is good that the main theme
+    # package installs a cache (although it does not completely fixes the
+    # situation for packages installed with nix-env).
+    #
+    # The module solution presented here keeps the cache when there is
+    # only one package contributing with icons to the theme. Otherwise it
+    # rebuilds the cache taking into account the icons provided all
+    # packages.
+
+    environment.extraSetup = ''
+      # For each icon theme directory ...
+
+      find $out/share/icons -mindepth 1 -maxdepth 1 -print0 | while read -d $'\0' themedir
+      do
+
+        # In order to build the cache, the theme dir should be
+        # writable. When the theme dir is a symbolic link to somewhere
+        # in the nix store it is not writable and it means that only
+        # one package is contributing to the theme. If it already has
+        # a cache, no rebuild is needed. Otherwise a cache has to be
+        # built, and to be able to do that we first remove the
+        # symbolic link and make a directory, and then make symbolic
+        # links from the original directory into the new one.
+
+        if [ ! -w "$themedir" -a -L "$themedir" -a ! -r "$themedir"/icon-theme.cache ]; then
+          name=$(basename "$themedir")
+          path=$(readlink -f "$themedir")
+          rm "$themedir"
+          mkdir -p "$themedir"
+          ln -s "$path"/* "$themedir"/
+        fi
+
+        # (Re)build the cache if the theme dir is writable, replacing any
+        # existing cache for the theme
+
+        if [ -w "$themedir" ]; then
+          rm -f "$themedir"/icon-theme.cache
+          ${pkgs.gtk3.out}/bin/gtk-update-icon-cache --ignore-theme-index "$themedir"
+        fi
+      done
+    '';
+  };
+
+}
diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix
index 627cce67e97d..e6b49d4c2194 100644
--- a/nixos/modules/config/networking.nix
+++ b/nixos/modules/config/networking.nix
@@ -260,9 +260,9 @@ in
             '';
 
       } // optionalAttrs config.services.resolved.enable {
-        # symlink the static version of resolv.conf as recommended by upstream:
+        # symlink the dynamic stub resolver of resolv.conf as recommended by upstream:
         # https://www.freedesktop.org/software/systemd/man/systemd-resolved.html#/etc/resolv.conf
-        "resolv.conf".source = "${pkgs.systemd}/lib/systemd/resolv.conf";
+        "resolv.conf".source = "/run/systemd/resolve/stub-resolv.conf";
       } // optionalAttrs (config.services.resolved.enable && dnsmasqResolve) {
         "dnsmasq-resolv.conf".source = "/run/systemd/resolve/resolv.conf";
       } // optionalAttrs (pkgs.stdenv.hostPlatform.libc == "glibc") {
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 1793dc628edf..aece7aa67ac3 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -135,10 +135,6 @@ in
       # outputs TODO: note that the tools will often not be linked by default
       postBuild =
         ''
-          if [ -x $out/bin/gtk-update-icon-cache -a -f $out/share/icons/hicolor/index.theme ]; then
-              $out/bin/gtk-update-icon-cache $out/share/icons/hicolor
-          fi
-
           if [ -x $out/bin/glib-compile-schemas -a -w $out/share/glib-2.0/schemas ]; then
               $out/bin/glib-compile-schemas $out/share/glib-2.0/schemas
           fi
diff --git a/nixos/modules/hardware/ckb-next.nix b/nixos/modules/hardware/ckb-next.nix
new file mode 100644
index 000000000000..20b2756d8b26
--- /dev/null
+++ b/nixos/modules/hardware/ckb-next.nix
@@ -0,0 +1,49 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.hardware.ckb-next;
+
+in
+  {
+    options.hardware.ckb-next = {
+      enable = mkEnableOption "the Corsair keyboard/mouse driver";
+
+      gid = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 100;
+        description = ''
+          Limit access to the ckb daemon to a particular group.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.ckb-next;
+        defaultText = "pkgs.ckb-next";
+        description = ''
+          The package implementing the Corsair keyboard/mouse driver.
+        '';
+      };
+    };
+
+    config = mkIf cfg.enable {
+      environment.systemPackages = [ cfg.package ];
+
+      systemd.services.ckb-next = {
+        description = "Corsair Keyboards and Mice Daemon";
+        wantedBy = ["multi-user.target"];
+        serviceConfig = {
+          ExecStart = "${cfg.package}/bin/ckb-next-daemon ${optionalString (cfg.gid != null) "--gid=${builtins.toString cfg.gid}"}";
+          Restart = "on-failure";
+          StandardOutput = "syslog";
+        };
+      };
+    };
+
+    meta = {
+      maintainers = with lib.maintainers; [ kierdavis ];
+    };
+  }
diff --git a/nixos/modules/hardware/ckb.nix b/nixos/modules/hardware/ckb.nix
deleted file mode 100644
index 8429572a8822..000000000000
--- a/nixos/modules/hardware/ckb.nix
+++ /dev/null
@@ -1,40 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.hardware.ckb;
-
-in
-  {
-    options.hardware.ckb = {
-      enable = mkEnableOption "the Corsair keyboard/mouse driver";
-
-      package = mkOption {
-        type = types.package;
-        default = pkgs.ckb;
-        defaultText = "pkgs.ckb";
-        description = ''
-          The package implementing the Corsair keyboard/mouse driver.
-        '';
-      };
-    };
-
-    config = mkIf cfg.enable {
-      environment.systemPackages = [ cfg.package ];
-
-      systemd.services.ckb = {
-        description = "Corsair Keyboard Daemon";
-        wantedBy = ["multi-user.target"];
-        script = "${cfg.package}/bin/ckb-daemon";
-        serviceConfig = {
-          Restart = "always";
-          StandardOutput = "syslog";
-        };
-      };
-    };
-
-    meta = {
-      maintainers = with lib.maintainers; [ kierdavis ];
-    };
-  }
diff --git a/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix b/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
index 4372d196261e..2625f7661b78 100644
--- a/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
+++ b/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
@@ -1,9 +1,13 @@
 { system ? builtins.currentSystem
+, config ? {}
 , networkExpr
 }:
 
 let nodes = import networkExpr; in
 
-with import ../../../../lib/testing.nix { inherit system; };
+with import ../../../../lib/testing.nix {
+  inherit system;
+  pkgs = import ../.. { inherit system config; };
+};
 
 (makeTest { inherit nodes; testScript = ""; }).driver
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 6e7f0a007bc2..082b2732cc58 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -101,7 +101,7 @@
       iodined = 66;
       #libvirtd = 67; # unused
       graphite = 68;
-      statsd = 69;
+      #statsd = 69; # removed 2018-11-14
       transmission = 70;
       postgres = 71;
       #vboxusers = 72; # unused
@@ -334,6 +334,8 @@
       slurm = 307;
       kapacitor = 308;
       solr = 309;
+      alerta = 310;
+      minetest = 311;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -409,7 +411,7 @@
       iodined = 66;
       libvirtd = 67;
       graphite = 68;
-      #statsd = 69; # unused
+      #statsd = 69; # removed 2018-11-14
       transmission = 70;
       postgres = 71;
       vboxusers = 72;
@@ -628,6 +630,8 @@
       slurm = 307;
       kapacitor = 308;
       solr = 309;
+      alerta = 310;
+      minetest = 311;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix
index 1dfd2c3c6cf3..93fbf16841e5 100644
--- a/nixos/modules/misc/nixpkgs.nix
+++ b/nixos/modules/misc/nixpkgs.nix
@@ -1,9 +1,10 @@
-{ config, lib, pkgs, ... }:
+{ config, options, lib, pkgs, ... }:
 
 with lib;
 
 let
   cfg = config.nixpkgs;
+  opt = options.nixpkgs;
 
   isConfig = x:
     builtins.isAttrs x || lib.isFunction x;
@@ -54,6 +55,12 @@ let
     check = builtins.isAttrs;
   };
 
+  defaultPkgs = import ../../../pkgs/top-level/default.nix {
+    inherit (cfg) config overlays localSystem crossSystem;
+  };
+
+  finalPkgs = if opt.pkgs.isDefined then cfg.pkgs.appendOverlays cfg.overlays else defaultPkgs;
+
 in
 
 {
@@ -61,21 +68,25 @@ in
 
     pkgs = mkOption {
       defaultText = literalExample
-        ''import "''${nixos}/.." {
+        ''import "''${nixos}/../pkgs/top-level" {
             inherit (cfg) config overlays localSystem crossSystem;
           }
         '';
-      default = import ../../.. {
-        inherit (cfg) config overlays localSystem crossSystem;
-      };
       type = pkgsType;
       example = literalExample ''import <nixpkgs> {}'';
       description = ''
-        This is the evaluation of Nixpkgs that will be provided to
-        all NixOS modules. Defining this option has the effect of
-        ignoring the other options that would otherwise be used to
-        evaluate Nixpkgs, because those are arguments to the default
-        value. The default value imports the Nixpkgs source files
+        If set, the pkgs argument to all NixOS modules is the value of
+        this option, extended with <code>nixpkgs.overlays</code>, if
+        that is also set. Either <code>nixpkgs.crossSystem</code> or
+        <code>nixpkgs.localSystem</code> will be used in an assertion
+        to check that the NixOS and Nixpkgs architectures match. Any
+        other options in <code>nixpkgs.*</code>, notably <code>config</code>,
+        will be ignored.
+
+        If unset, the pkgs argument to all NixOS modules is determined
+        as shown in the default value for this option.
+
+        The default value imports the Nixpkgs source files
         relative to the location of this NixOS module, because
         NixOS and Nixpkgs are distributed together for consistency,
         so the <code>nixos</code> in the default value is in fact a
@@ -128,12 +139,14 @@ in
       description = ''
         List of overlays to use with the Nix Packages collection.
         (For details, see the Nixpkgs documentation.)  It allows
-        you to override packages globally. This is a function that
+        you to override packages globally. Each function in the list
         takes as an argument the <emphasis>original</emphasis> Nixpkgs.
         The first argument should be used for finding dependencies, and
         the second should be used for overriding recipes.
 
-        Ignored when <code>nixpkgs.pkgs</code> is set.
+        If <code>nixpkgs.pkgs</code> is set, overlays specified here
+        will be applied after the overlays that were already present
+        in <code>nixpkgs.pkgs</code>.
       '';
     };
 
@@ -207,7 +220,26 @@ in
 
   config = {
     _module.args = {
-      pkgs = cfg.pkgs;
+      pkgs = finalPkgs;
     };
+
+    assertions = [
+      (
+        let
+          nixosExpectedSystem =
+            if config.nixpkgs.crossSystem != null
+            then config.nixpkgs.crossSystem.system
+            else config.nixpkgs.localSystem.system;
+          nixosOption =
+            if config.nixpkgs.crossSystem != null
+            then "nixpkgs.crossSystem"
+            else "nixpkgs.localSystem";
+          pkgsSystem = finalPkgs.stdenv.targetPlatform.system;
+        in {
+          assertion = nixosExpectedSystem == pkgsSystem;
+          message = "The NixOS nixpkgs.pkgs option was set to a Nixpkgs invocation that compiles to target system ${pkgsSystem} but NixOS was configured for system ${nixosExpectedSystem} via NixOS option ${nixosOption}. The NixOS system settings must match the Nixpkgs target system.";
+        }
+      )
+    ];
   };
 }
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix
index 6d78b7c593f8..fd77f6372720 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -43,6 +43,7 @@ in
     nixos.codeName = mkOption {
       readOnly = true;
       type = types.str;
+      default = lib.trivial.codeName;
       description = "The NixOS release code name (e.g. <literal>Emu</literal>).";
     };
 
@@ -79,9 +80,6 @@ in
       version = mkDefault (cfg.release + cfg.versionSuffix);
       revision      = mkIf (pathIsDirectory gitRepo) (mkDefault            gitCommitId);
       versionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId));
-
-      # Note: the first letter is bumped on every release.  It's an animal.
-      codeName = "Koi";
     };
 
     # Generate /etc/os-release.  See
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 37e90232da2a..2b7ee13ef71e 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -11,6 +11,7 @@
   ./config/xdg/icons.nix
   ./config/xdg/menus.nix
   ./config/xdg/mime.nix
+  ./config/gtk/gtk-icon-cache.nix
   ./config/gnu.nix
   ./config/i18n.nix
   ./config/iproute2.nix
@@ -34,7 +35,7 @@
   ./config/zram.nix
   ./hardware/all-firmware.nix
   ./hardware/brightnessctl.nix
-  ./hardware/ckb.nix
+  ./hardware/ckb-next.nix
   ./hardware/cpu/amd-microcode.nix
   ./hardware/cpu/intel-microcode.nix
   ./hardware/digitalbitbox.nix
@@ -90,6 +91,7 @@
   ./programs/criu.nix
   ./programs/dconf.nix
   ./programs/digitalbitbox/default.nix
+  ./programs/dmrconfig.nix
   ./programs/environment.nix
   ./programs/firejail.nix
   ./programs/fish.nix
@@ -301,6 +303,7 @@
   ./services/logging/graylog.nix
   ./services/logging/heartbeat.nix
   ./services/logging/journalbeat.nix
+  ./services/logging/journaldriver.nix
   ./services/logging/journalwatch.nix
   ./services/logging/klogd.nix
   ./services/logging/logcheck.nix
@@ -419,6 +422,7 @@
   ./services/misc/weechat.nix
   ./services/misc/xmr-stak.nix
   ./services/misc/zookeeper.nix
+  ./services/monitoring/alerta.nix
   ./services/monitoring/apcupsd.nix
   ./services/monitoring/arbtt.nix
   ./services/monitoring/bosun.nix
@@ -429,6 +433,7 @@
   ./services/monitoring/dd-agent/dd-agent.nix
   ./services/monitoring/fusion-inventory.nix
   ./services/monitoring/grafana.nix
+  ./services/monitoring/grafana-reporter.nix
   ./services/monitoring/graphite.nix
   ./services/monitoring/hdaps.nix
   ./services/monitoring/heapster.nix
@@ -448,7 +453,6 @@
   ./services/monitoring/riemann-tools.nix
   ./services/monitoring/scollector.nix
   ./services/monitoring/smartd.nix
-  ./services/monitoring/statsd.nix
   ./services/monitoring/sysstat.nix
   ./services/monitoring/systemhealth.nix
   ./services/monitoring/teamviewer.nix
diff --git a/nixos/modules/programs/dmrconfig.nix b/nixos/modules/programs/dmrconfig.nix
new file mode 100644
index 000000000000..e48a4f318370
--- /dev/null
+++ b/nixos/modules/programs/dmrconfig.nix
@@ -0,0 +1,38 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.dmrconfig;
+
+in {
+  meta.maintainers = [ maintainers.etu ];
+
+  ###### interface
+  options = {
+    programs.dmrconfig = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to configure system to enable use of dmrconfig. This
+          enables the required udev rules and installs the program.
+        '';
+        relatedPackages = [ "dmrconfig" ];
+      };
+
+      package = mkOption {
+        default = pkgs.dmrconfig;
+        type = types.package;
+        defaultText = "pkgs.dmrconfig";
+        description = "dmrconfig derivation to use";
+      };
+    };
+  };
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ cfg.package ];
+    services.udev.packages = [ cfg.package ];
+  };
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index aa2b5c0b2dfb..dc0a175d5bb8 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -282,6 +282,10 @@ with lib;
     (mkRenamedOptionModule [ "programs" "man"  "enable" ] [ "documentation" "man"  "enable" ])
     (mkRenamedOptionModule [ "services" "nixosManual" "enable" ] [ "documentation" "nixos" "enable" ])
 
+    # ckb
+    (mkRenamedOptionModule [ "hardware" "ckb" "enable" ] [ "hardware" "ckb-next" "enable" ])
+    (mkRenamedOptionModule [ "hardware" "ckb" "package" ] [ "hardware" "ckb-next" "package" ])
+
   ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter"
                    "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter"
                    "snmpExporter" "unifiExporter" "varnishExporter" ]
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix
index c6878dd67dbf..7373be2a9b0b 100644
--- a/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixos/modules/services/amqp/rabbitmq.nix
@@ -87,9 +87,19 @@ in {
           }
         '';
         description = ''
-          New style config options.
-
-          See http://www.rabbitmq.com/configure.html
+          Configuration options in RabbitMQ's new config file format,
+          which is a simple key-value format that can not express nested
+          data structures. This is known as the <literal>rabbitmq.conf</literal> file,
+          although outside NixOS that filename may have Erlang syntax, particularly
+          prior to RabbitMQ 3.7.0.
+
+          If you do need to express nested data structures, you can use
+          <literal>config</literal> option. Configuration from <literal>config</literal>
+          will be merged into these options by RabbitMQ at runtime to
+          form the final configuration.
+
+          See http://www.rabbitmq.com/configure.html#config-items
+          For the distinct formats, see http://www.rabbitmq.com/configure.html#config-file-formats
         '';
       };
 
@@ -97,10 +107,17 @@ in {
         default = "";
         type = types.str;
         description = ''
-          Verbatim advanced configuration file contents.
-          Prefered way is to use configItems.
+          Verbatim advanced configuration file contents using the Erlang syntax.
+          This is also known as the <literal>advanced.config</literal> file or the old config format.
+
+          <literal>configItems</literal> is preferred whenever possible. However, nested
+          data structures can only be expressed properly using the <literal>config</literal> option.
+
+          The contents of this option will be merged into the <literal>configItems</literal>
+          by RabbitMQ at runtime to form the final configuration.
 
-          See http://www.rabbitmq.com/configure.html
+          See the second table on http://www.rabbitmq.com/configure.html#config-items
+          For the distinct formats, see http://www.rabbitmq.com/configure.html#config-file-formats
         '';
       };
 
diff --git a/nixos/modules/services/backup/bacula.nix b/nixos/modules/services/backup/bacula.nix
index a0565ca26204..24cad6128260 100644
--- a/nixos/modules/services/backup/bacula.nix
+++ b/nixos/modules/services/backup/bacula.nix
@@ -346,8 +346,12 @@ in {
       description = "Bacula File Daemon";
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.bacula ];
-      serviceConfig.ExecStart = "${pkgs.bacula}/sbin/bacula-fd -f -u root -g bacula -c ${fd_conf}";
-      serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      serviceConfig = {
+        ExecStart = "${pkgs.bacula}/sbin/bacula-fd -f -u root -g bacula -c ${fd_conf}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        LogsDirectory = "bacula";
+        StateDirectory = "bacula";
+      };
     };
 
     systemd.services.bacula-sd = mkIf sd_cfg.enable {
@@ -355,8 +359,12 @@ in {
       description = "Bacula Storage Daemon";
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.bacula ];
-      serviceConfig.ExecStart = "${pkgs.bacula}/sbin/bacula-sd -f -u bacula -g bacula -c ${sd_conf}";
-      serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      serviceConfig = {
+        ExecStart = "${pkgs.bacula}/sbin/bacula-sd -f -u bacula -g bacula -c ${sd_conf}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        LogsDirectory = "bacula";
+        StateDirectory = "bacula";
+      };
     };
 
     services.postgresql.enable = dir_cfg.enable == true;
@@ -366,8 +374,12 @@ in {
       description = "Bacula Director Daemon";
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.bacula ];
-      serviceConfig.ExecStart = "${pkgs.bacula}/sbin/bacula-dir -f -u bacula -g bacula -c ${dir_conf}";
-      serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      serviceConfig = {
+        ExecStart = "${pkgs.bacula}/sbin/bacula-dir -f -u bacula -g bacula -c ${dir_conf}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        LogsDirectory = "bacula";
+        StateDirectory = "bacula";
+      };
       preStart = ''
         if ! test -e "${libDir}/db-created"; then
             ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole bacula
diff --git a/nixos/modules/services/backup/postgresql-backup.nix b/nixos/modules/services/backup/postgresql-backup.nix
index 2ec78ce6f2cf..f9f9568faa5c 100644
--- a/nixos/modules/services/backup/postgresql-backup.nix
+++ b/nixos/modules/services/backup/postgresql-backup.nix
@@ -20,6 +20,8 @@ let
       '';
 
       script = ''
+        umask 0077 # ensure backup is only readable by postgres user
+
         if [ -e ${cfg.location}/${db}.sql.gz ]; then
           ${pkgs.coreutils}/bin/mv ${cfg.location}/${db}.sql.gz ${cfg.location}/${db}.prev.sql.gz
         fi
diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix
index dc9e248713e9..5f184df34c68 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -148,7 +148,7 @@ in
           option is changed. This means that users created and permissions assigned once through this option or
           otherwise have to be removed manually.
         '';
-        example = [
+        example = literalExample ''[
           {
             name = "nextcloud";
             ensurePermissions = {
@@ -161,7 +161,7 @@ in
               "*.*" = "SELECT, LOCK TABLES";
             };
           }
-        ];
+        ]'';
       };
 
       # FIXME: remove this option; it's a really bad idea.
diff --git a/nixos/modules/services/development/jupyter/default.nix b/nixos/modules/services/development/jupyter/default.nix
index 9fcc00431865..f20860af6e12 100644
--- a/nixos/modules/services/development/jupyter/default.nix
+++ b/nixos/modules/services/development/jupyter/default.nix
@@ -145,6 +145,7 @@ in {
       systemd.services.jupyter = {
         description = "Jupyter development server";
 
+        after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
 
         # TODO: Patch notebook so we can explicitly pass in a shell
diff --git a/nixos/modules/services/games/minetest-server.nix b/nixos/modules/services/games/minetest-server.nix
index 2de42f20f6cc..98e69c6dc0ea 100644
--- a/nixos/modules/services/games/minetest-server.nix
+++ b/nixos/modules/services/games/minetest-server.nix
@@ -84,7 +84,9 @@ in
       home            = "/var/lib/minetest";
       createHome      = true;
       uid             = config.ids.uids.minetest;
+      group           = "minetest";
     };
+    users.groups.minetest.gid = config.ids.gids.minetest;
 
     systemd.services.minetest-server = {
       description   = "Minetest Server Service";
@@ -93,6 +95,7 @@ in
 
       serviceConfig.Restart = "always";
       serviceConfig.User    = "minetest";
+      serviceConfig.Group   = "minetest";
 
       script = ''
         cd /var/lib/minetest
diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix
index d83d6f1f750c..1c37ae41e07d 100644
--- a/nixos/modules/services/mail/rspamd.nix
+++ b/nixos/modules/services/mail/rspamd.nix
@@ -6,6 +6,7 @@ let
 
   cfg = config.services.rspamd;
   opts = options.services.rspamd;
+  postfixCfg = config.services.postfix;
 
   bindSocketOpts = {options, config, ... }: {
     options = {
@@ -58,7 +59,7 @@ let
       };
       type = mkOption {
         type = types.nullOr (types.enum [
-          "normal" "controller" "fuzzy_storage" "proxy" "lua"
+          "normal" "controller" "fuzzy_storage" "rspamd_proxy" "lua"
         ]);
         description = "The type of this worker";
       };
@@ -99,19 +100,21 @@ let
         description = "Additional entries to put verbatim into worker section of rspamd config file.";
       };
     };
-    config = mkIf (name == "normal" || name == "controller" || name == "fuzzy") {
+    config = mkIf (name == "normal" || name == "controller" || name == "fuzzy" || name == "rspamd_proxy") {
       type = mkDefault name;
-      includes = mkDefault [ "$CONFDIR/worker-${name}.inc" ];
-      bindSockets = mkDefault (if name == "normal"
-        then [{
-              socket = "/run/rspamd/rspamd.sock";
-              mode = "0660";
-              owner = cfg.user;
-              group = cfg.group;
-            }]
-        else if name == "controller"
-        then [ "localhost:11334" ]
-        else [] );
+      includes = mkDefault [ "$CONFDIR/worker-${if name == "rspamd_proxy" then "proxy" else name}.inc" ];
+      bindSockets =
+        let
+          unixSocket = name: {
+            mode = "0660";
+            socket = "/run/rspamd/${name}.sock";
+            owner = cfg.user;
+            group = cfg.group;
+          };
+        in mkDefault (if name == "normal" then [(unixSocket "rspamd")]
+          else if name == "controller" then [ "localhost:11334" ]
+          else if name == "rspamd_proxy" then [ (unixSocket "proxy") ]
+          else [] );
     };
   };
 
@@ -138,24 +141,31 @@ let
         .include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/logging.inc"
       }
 
-      ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
-        worker ${optionalString (value.name != "normal" && value.name != "controller") "${value.name}"} {
+      ${concatStringsSep "\n" (mapAttrsToList (name: value: let
+          includeName = if name == "rspamd_proxy" then "proxy" else name;
+          tryOverride = if value.extraConfig == "" then "true" else "false";
+        in ''
+        worker "${value.type}" {
           type = "${value.type}";
           ${optionalString (value.enable != null)
             "enabled = ${if value.enable != false then "yes" else "no"};"}
           ${mkBindSockets value.enable value.bindSockets}
           ${optionalString (value.count != null) "count = ${toString value.count};"}
           ${concatStringsSep "\n  " (map (each: ".include \"${each}\"") value.includes)}
-          ${value.extraConfig}
+          .include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/worker-${includeName}.inc"
+          .include(try=${tryOverride}; priority=10) "$LOCAL_CONFDIR/override.d/worker-${includeName}.inc"
         }
       '') cfg.workers)}
 
-      ${cfg.extraConfig}
+      ${optionalString (cfg.extraConfig != "") ''
+        .include(priority=10) "$LOCAL_CONFDIR/override.d/extra-config.inc"
+      ''}
    '';
 
+  filterFiles = files: filterAttrs (n: v: v.enable) files;
   rspamdDir = pkgs.linkFarm "etc-rspamd-dir" (
-    (mapAttrsToList (name: file: { name = "local.d/${name}"; path = file.source; }) cfg.locals) ++
-    (mapAttrsToList (name: file: { name = "override.d/${name}"; path = file.source; }) cfg.overrides) ++
+    (mapAttrsToList (name: file: { name = "local.d/${name}"; path = file.source; }) (filterFiles cfg.locals)) ++
+    (mapAttrsToList (name: file: { name = "override.d/${name}"; path = file.source; }) (filterFiles cfg.overrides)) ++
     (optional (cfg.localLuaRules != null) { name = "rspamd.local.lua"; path = cfg.localLuaRules; }) ++
     [ { name = "rspamd.conf"; path = rspamdConfFile; } ]
   );
@@ -188,6 +198,15 @@ let
         in mkDefault (pkgs.writeText name' config.text));
     };
   };
+
+  configOverrides =
+    (mapAttrs' (n: v: nameValuePair "worker-${if n == "rspamd_proxy" then "proxy" else n}.inc" {
+      text = v.extraConfig;
+    })
+    (filterAttrs (n: v: v.extraConfig != "") cfg.workers))
+    // (if cfg.extraConfig == "" then {} else {
+      "extra-config.inc".text = cfg.extraConfig;
+    });
 in
 
 {
@@ -207,7 +226,7 @@ in
       };
 
       locals = mkOption {
-        type = with types; loaOf (submodule (configFileModule "locals"));
+        type = with types; attrsOf (submodule (configFileModule "locals"));
         default = {};
         description = ''
           Local configuration files, written into <filename>/etc/rspamd/local.d/{name}</filename>.
@@ -220,7 +239,7 @@ in
       };
 
       overrides = mkOption {
-        type = with types; loaOf (submodule (configFileModule "overrides"));
+        type = with types; attrsOf (submodule (configFileModule "overrides"));
         default = {};
         description = ''
           Overridden configuration files, written into <filename>/etc/rspamd/override.d/{name}</filename>.
@@ -284,7 +303,7 @@ in
         description = ''
           User to use when no root privileges are required.
         '';
-       };
+      };
 
       group = mkOption {
         type = types.string;
@@ -292,7 +311,30 @@ in
         description = ''
           Group to use when no root privileges are required.
         '';
-       };
+      };
+
+      postfix = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = "Add rspamd milter to postfix main.conf";
+        };
+
+        config = mkOption {
+          type = with types; attrsOf (either bool (either str (listOf str)));
+          description = ''
+            Addon to postfix configuration
+          '';
+          default = {
+            smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
+            non_smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
+          };
+          example = {
+            smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
+            non_smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
+          };
+        };
+      };
     };
   };
 
@@ -300,6 +342,25 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
+    services.rspamd.overrides = configOverrides;
+    services.rspamd.workers = mkIf cfg.postfix.enable {
+      controller = {};
+      rspamd_proxy = {
+        bindSockets = [ {
+          mode = "0660";
+          socket = "/run/rspamd/rspamd-milter.sock";
+          owner = cfg.user;
+          group = postfixCfg.group;
+        } ];
+        extraConfig = ''
+          upstream "local" {
+            default = yes; # Self-scan upstreams are always default
+            self_scan = yes; # Enable self-scan
+          }
+        '';
+      };
+    };
+    services.postfix.config = mkIf cfg.postfix.enable cfg.postfix.config;
 
     # Allow users to run 'rspamc' and 'rspamadm'.
     environment.systemPackages = [ pkgs.rspamd ];
diff --git a/nixos/modules/services/misc/exhibitor.nix b/nixos/modules/services/misc/exhibitor.nix
index a90c7f402e7f..665084a8ae05 100644
--- a/nixos/modules/services/misc/exhibitor.nix
+++ b/nixos/modules/services/misc/exhibitor.nix
@@ -405,6 +405,9 @@ in
         cp -Rf ${pkgs.zookeeper}/* ${cfg.baseDir}/zookeeper
         chown -R zookeeper ${cfg.baseDir}/zookeeper/conf
         chmod -R u+w ${cfg.baseDir}/zookeeper/conf
+        replace_what=$(echo ${pkgs.zookeeper} | sed 's/[\/&]/\\&/g')
+        replace_with=$(echo ${cfg.baseDir}/zookeeper | sed 's/[\/&]/\\&/g')
+        sed -i 's/'"$replace_what"'/'"$replace_with"'/g' ${cfg.baseDir}/zookeeper/bin/zk*.sh
       '';
     };
     users.users = singleton {
diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix
index a222325579fe..7a10bd872994 100644
--- a/nixos/modules/services/misc/gitea.nix
+++ b/nixos/modules/services/misc/gitea.nix
@@ -6,6 +6,7 @@ let
   cfg = config.services.gitea;
   gitea = cfg.package;
   pg = config.services.postgresql;
+  useMysql = cfg.database.type == "mysql";
   usePostgresql = cfg.database.type == "postgres";
   configFile = pkgs.writeText "app.ini" ''
     APP_NAME = ${cfg.appName}
@@ -14,7 +15,7 @@ let
 
     [database]
     DB_TYPE = ${cfg.database.type}
-    HOST = ${cfg.database.host}:${toString cfg.database.port}
+    HOST = ${if cfg.database.socket != null then cfg.database.socket else cfg.database.host + ":" + toString cfg.database.port}
     NAME = ${cfg.database.name}
     USER = ${cfg.database.user}
     PASSWD = #dbpass#
@@ -148,6 +149,13 @@ in
           '';
         };
 
+        socket = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          example = "/run/mysqld/mysqld.sock";
+          description = "Path to the unix socket file to use for authentication.";
+        };
+
         path = mkOption {
           type = types.str;
           default = "${cfg.stateDir}/data/gitea.db";
@@ -253,7 +261,7 @@ in
 
     systemd.services.gitea = {
       description = "gitea";
-      after = [ "network.target" "postgresql.service" ];
+      after = [ "network.target" ] ++ lib.optional usePostgresql "postgresql.service" ++ lib.optional useMysql "mysql.service";
       wantedBy = [ "multi-user.target" ];
       path = [ gitea.bin ];
 
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index aa72cda70453..07adf58c9b26 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -564,11 +564,11 @@ in {
         [ -L /run/gitlab/log ] || ln -sf ${cfg.statePath}/log /run/gitlab/log
         [ -L /run/gitlab/tmp ] || ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp
         [ -L /run/gitlab/uploads ] || ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads
+        cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
+        cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
         ${optionalString cfg.smtp.enable ''
           ln -sf ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb
         ''}
-        cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
-        cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
         ${pkgs.openssl}/bin/openssl rand -hex 32 > ${cfg.statePath}/config/gitlab_shell_secret
 
         # JSON is a subset of YAML
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 5e171c08d893..9a8116a03e88 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -62,11 +62,15 @@ let
         ''}
         $extraOptions
         END
-      '' + optionalString cfg.checkConfig ''
-        echo "Checking that Nix can read nix.conf..."
-        ln -s $out ./nix.conf
-        NIX_CONF_DIR=$PWD ${cfg.package}/bin/nix show-config >/dev/null
-      '');
+      '' + optionalString cfg.checkConfig (
+            if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
+              echo "Ignore nix.checkConfig when cross-compiling"
+            '' else ''
+              echo "Checking that Nix can read nix.conf..."
+              ln -s $out ./nix.conf
+              NIX_CONF_DIR=$PWD ${cfg.package}/bin/nix show-config >/dev/null
+            '')
+      );
 
 in
 
@@ -113,11 +117,11 @@ in
 
       buildCores = mkOption {
         type = types.int;
-        default = 1;
+        default = 0;
         example = 64;
         description = ''
           This option defines the maximum number of concurrent tasks during
-          one build. It affects, e.g., -j option for make. The default is 1.
+          one build. It affects, e.g., -j option for make.
           The special value 0 means that the builder should use all
           available CPU cores in the system. Some builds may become
           non-deterministic with this option; use with care! Packages will
diff --git a/nixos/modules/services/monitoring/alerta.nix b/nixos/modules/services/monitoring/alerta.nix
new file mode 100644
index 000000000000..8f4258e26ded
--- /dev/null
+++ b/nixos/modules/services/monitoring/alerta.nix
@@ -0,0 +1,116 @@
+{ options, config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.alerta;
+
+  alertaConf = pkgs.writeTextFile {
+    name = "alertad.conf";
+    text = ''
+      DATABASE_URL = '${cfg.databaseUrl}'
+      DATABASE_NAME = '${cfg.databaseName}'
+      LOG_FILE = '${cfg.logDir}/alertad.log'
+      LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+      CORS_ORIGINS = [ ${concatMapStringsSep ", " (s: "\"" + s + "\"") cfg.corsOrigins} ];
+      AUTH_REQUIRED = ${if cfg.authenticationRequired then "True" else "False"}
+      SIGNUP_ENABLED = ${if cfg.signupEnabled then "True" else "False"}
+      ${cfg.extraConfig}
+    '';
+  };
+in
+{
+  options.services.alerta = {
+    enable = mkEnableOption "alerta";
+
+    port = mkOption {
+      type = types.int;
+      default = 5000;
+      description = "Port of Alerta";
+    };
+
+    bind = mkOption {
+      type = types.str;
+      default = "0.0.0.0";
+      example = literalExample "0.0.0.0";
+      description = "Address to bind to. The default is to bind to all addresses";
+    };
+
+    logDir = mkOption {
+      type = types.path;
+      description = "Location where the logfiles are stored";
+      default = "/var/log/alerta";
+    };
+
+    databaseUrl = mkOption {
+      type = types.str;
+      description = "URL of the MongoDB or PostgreSQL database to connect to";
+      default = "mongodb://localhost";
+      example = "mongodb://localhost";
+    };
+
+    databaseName = mkOption {
+      type = types.str;
+      description = "Name of the database instance to connect to";
+      default = "monitoring";
+      example = "monitoring";
+    };
+
+    corsOrigins = mkOption {
+      type = types.listOf types.str;
+      description = "List of URLs that can access the API for Cross-Origin Resource Sharing (CORS)";
+      example = [ "http://localhost" "http://localhost:5000" ];
+      default = [ "http://localhost" "http://localhost:5000" ];
+    };
+
+    authenticationRequired = mkOption {
+      type = types.bool;
+      description = "Whether users must authenticate when using the web UI or command-line tool";
+      default = false;
+    };
+
+    signupEnabled = mkOption {
+      type = types.bool;
+      description = "Whether to prevent sign-up of new users via the web UI";
+      default = true;
+    };
+
+    extraConfig = mkOption {
+      description = "These lines go into alertad.conf verbatim.";
+      default = "";
+      type = types.lines;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.alerta = {
+      description = "Alerta Monitoring System";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "networking.target" ];
+      environment = {
+        ALERTA_SVR_CONF_FILE = alertaConf;
+      };
+      serviceConfig = {
+        ExecStart = "${pkgs.python36Packages.alerta-server}/bin/alertad run --port ${toString cfg.port} --host ${cfg.bind}";
+        User = "alerta";
+        Group = "alerta";
+        PermissionsStartOnly = true;
+      };
+      preStart = ''
+        mkdir -p ${cfg.logDir}
+        chown alerta:alerta ${cfg.logDir}
+      '';
+    };
+
+    environment.systemPackages = [ pkgs.python36Packages.alerta ];
+
+    users.users.alerta = {
+      uid = config.ids.uids.alerta;
+      description = "Alerta user";
+    };
+
+    users.groups.alerta = {
+      gid = config.ids.gids.alerta;
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/grafana-reporter.nix b/nixos/modules/services/monitoring/grafana-reporter.nix
new file mode 100644
index 000000000000..149026d20188
--- /dev/null
+++ b/nixos/modules/services/monitoring/grafana-reporter.nix
@@ -0,0 +1,66 @@
+{ options, config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.grafana_reporter;
+
+in {
+  options.services.grafana_reporter = {
+    enable = mkEnableOption "grafana_reporter";
+
+    grafana = {
+      protocol = mkOption {
+        description = "Grafana protocol.";
+        default = "http";
+        type = types.enum ["http" "https"];
+      };
+      addr = mkOption {
+        description = "Grafana address.";
+        default = "127.0.0.1";
+        type = types.str;
+      };
+      port = mkOption {
+        description = "Grafana port.";
+        default = 3000;
+        type = types.int;
+      };
+
+    };
+    addr = mkOption {
+      description = "Listening address.";
+      default = "127.0.0.1";
+      type = types.str;
+    };
+
+    port = mkOption {
+      description = "Listening port.";
+      default = 8686;
+      type = types.int;
+    };
+
+    templateDir = mkOption {
+      description = "Optional template directory to use custom tex templates";
+      default = "${pkgs.grafana_reporter}";
+      type = types.str;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.grafana_reporter = {
+      description = "Grafana Reporter Service Daemon";
+      wantedBy = ["multi-user.target"];
+      after = ["network.target"];
+      serviceConfig = let
+        args = lib.concatSepString " " [
+          "-proto ${cfg.grafana.protocol}://"
+          "-ip ${cfg.grafana.addr}:${toString cfg.grafana.port}"
+          "-port :${toString cfg.port}"
+          "-templates ${cfg.templateDir}"
+        ];
+      in {
+        ExecStart = "${pkgs.grafana_reporter.bin}/bin/grafana-reporter ${args}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/kapacitor.nix b/nixos/modules/services/monitoring/kapacitor.nix
index 1de0a8d5af2f..a4bdfa8f8053 100644
--- a/nixos/modules/services/monitoring/kapacitor.nix
+++ b/nixos/modules/services/monitoring/kapacitor.nix
@@ -42,6 +42,15 @@ let
           password = "${cfg.defaultDatabase.password}"
       ''}
 
+      ${optionalString (cfg.alerta.enable) ''
+        [alerta]
+          enabled = true
+          url = "${cfg.alerta.url}"
+          token = "${cfg.alerta.token}"
+          environment = "${cfg.alerta.environment}"
+          origin = "${cfg.alerta.origin}"
+      ''}
+
       ${cfg.extraConfig}
     '';
   };
@@ -120,6 +129,35 @@ in
         type = types.string;
       };
     };
+
+    alerta = {
+      enable = mkEnableOption "kapacitor alerta integration";
+
+      url = mkOption {
+        description = "The URL to the Alerta REST API";
+        default = "http://localhost:5000";
+        example = "http://localhost:5000";
+        type = types.string;
+      };
+
+      token = mkOption {
+        description = "Default Alerta authentication token";
+        type = types.str;
+        default = "";
+      };
+
+      environment = mkOption {
+        description = "Default Alerta environment";
+        type = types.str;
+        default = "Production";
+      };
+
+      origin = mkOption {
+        description = "Default origin of alert";
+        type = types.str;
+        default = "kapacitor";
+      };
+    };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/monitoring/monit.nix b/nixos/modules/services/monitoring/monit.nix
index d48e5c550abb..32e14ab21ffc 100644
--- a/nixos/modules/services/monitoring/monit.nix
+++ b/nixos/modules/services/monitoring/monit.nix
@@ -1,33 +1,30 @@
-# Monit system watcher
-# http://mmonit.org/monit/
-
 {config, pkgs, lib, ...}:
 
-let inherit (lib) mkOption mkIf;
+with lib;
+
+let
+  cfg = config.services.monit;
 in
 
 {
-  options = {
-    services.monit = {
-      enable = mkOption {
-        default = false;
-        description = ''
-          Whether to run Monit system watcher.
-        '';
-      };
-      config = mkOption {
-        default = "";
-        description = "monitrc content";
-      };
+  options.services.monit = {
+
+    enable = mkEnableOption "Monit";
+
+    config = mkOption {
+      type = types.lines;
+      default = "";
+      description = "monitrc content";
     };
+
   };
 
-  config = mkIf config.services.monit.enable {
+  config = mkIf cfg.enable {
 
     environment.systemPackages = [ pkgs.monit ];
 
     environment.etc."monitrc" = {
-      text = config.services.monit.config;
+      text = cfg.config;
       mode = "0400";
     };
 
diff --git a/nixos/modules/services/network-filesystems/glusterfs.nix b/nixos/modules/services/network-filesystems/glusterfs.nix
index 8ac9f801dcb8..eb7f060c7da0 100644
--- a/nixos/modules/services/network-filesystems/glusterfs.nix
+++ b/nixos/modules/services/network-filesystems/glusterfs.nix
@@ -176,10 +176,8 @@ in
       '';
 
       serviceConfig = {
-        Type="forking";
-        PIDFile="/run/glusterd.pid";
         LimitNOFILE=65536;
-        ExecStart="${glusterfs}/sbin/glusterd -p /run/glusterd.pid --log-level=${cfg.logLevel} ${toString cfg.extraFlags}";
+        ExecStart="${glusterfs}/sbin/glusterd --no-daemon --log-level=${cfg.logLevel} ${toString cfg.extraFlags}";
         KillMode=cfg.killMode;
         TimeoutStopSec=cfg.stopKillTimeout;
       };
@@ -198,6 +196,9 @@ in
         install -m 0755 -d /var/log/glusterfs
       '';
 
+      # glustereventsd uses the `gluster` executable
+      path = [ glusterfs ];
+
       serviceConfig = {
         Type="simple";
         Environment="PYTHONPATH=${glusterfs}/usr/lib/python2.7/site-packages";
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index c16fbe8a52fa..5fab79f1b3d7 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -130,7 +130,7 @@ in
       };
 
       ports = mkOption {
-        type = types.listOf types.int;
+        type = types.listOf types.port;
         default = [22];
         description = ''
           Specifies on which ports the SSH daemon listens.
diff --git a/nixos/modules/services/system/cloud-init.nix b/nixos/modules/services/system/cloud-init.nix
index 1a700828ce77..f22bd45dfebc 100644
--- a/nixos/modules/services/system/cloud-init.nix
+++ b/nixos/modules/services/system/cloud-init.nix
@@ -3,13 +3,20 @@
 with lib;
 
 let cfg = config.services.cloud-init;
-    path = with pkgs; [ cloud-init nettools utillinux e2fsprogs shadow openssh iproute ];
+    path = with pkgs; [
+      cloud-init
+      iproute
+      nettools
+      openssh
+      shadow
+      utillinux
+    ] ++ optional cfg.btrfs.enable btrfs-progs
+      ++ optional cfg.ext4.enable e2fsprogs
+    ;
 in
 {
   options = {
-
     services.cloud-init = {
-
       enable = mkOption {
         type = types.bool;
         default = false;
@@ -29,6 +36,22 @@ in
         '';
       };
 
+      btrfs.enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Allow the cloud-init service to operate `btrfs` filesystem.
+        '';
+      };
+
+      ext4.enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Allow the cloud-init service to operate `ext4` filesystem.
+        '';
+      };
+
       config = mkOption {
         type = types.str;
         default = ''
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index c7e97bbeba9a..d0efdf88d73c 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -171,7 +171,12 @@ in {
       dbhost = mkOption {
         type = types.nullOr types.str;
         default = "localhost";
-        description = "Database host.";
+        description = ''
+          Database host.
+
+          Note: for using Unix authentication with PostgreSQL, this should be
+          set to <literal>/tmp</literal>.
+        '';
       };
       dbport = mkOption {
         type = with types; nullOr (either int str);
diff --git a/nixos/modules/services/web-apps/selfoss.nix b/nixos/modules/services/web-apps/selfoss.nix
index 5571f77334cc..7b0ce8a8d03f 100644
--- a/nixos/modules/services/web-apps/selfoss.nix
+++ b/nixos/modules/services/web-apps/selfoss.nix
@@ -21,8 +21,8 @@ let
       db_database=${cfg.database.name}
       db_username=${cfg.database.user}
       db_password=${cfg.database.password}
-      db_port=${if (cfg.database.port != null) then cfg.database.port
-                    else default_port}
+      db_port=${toString (if (cfg.database.port != null) then cfg.database.port
+                    else default_port)}
     ''
     }
     ${cfg.extraConfig}
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index a685dbfff2a0..e1688c451045 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -208,15 +208,11 @@ in
       }
     ];
 
-    services.xserver.displayManager.job = {
-      logToFile = true;
-
-      # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
-      execCmd = ''
-        export PATH=${lightdm}/sbin:$PATH
-        exec ${lightdm}/sbin/lightdm
-      '';
-    };
+    # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
+    services.xserver.displayManager.job.execCmd = ''
+      export PATH=${lightdm}/sbin:$PATH
+      exec ${lightdm}/sbin/lightdm
+    '';
 
     environment.etc."lightdm/lightdm.conf".source = lightdmConf;
     environment.etc."lightdm/users.conf".source = usersConf;
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 522a0dc92d6f..b7511dfd5a8b 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -209,8 +209,6 @@ in
     ];
 
     services.xserver.displayManager.job = {
-      logToFile = true;
-
       environment = {
         # Load themes from system environment
         QT_PLUGIN_PATH = "/run/current-system/sw/" + pkgs.qt5.qtbase.qtPluginPrefix;
diff --git a/nixos/modules/services/x11/display-managers/xpra.nix b/nixos/modules/services/x11/display-managers/xpra.nix
index b46ede550c16..a4b57cfdab64 100644
--- a/nixos/modules/services/x11/display-managers/xpra.nix
+++ b/nixos/modules/services/x11/display-managers/xpra.nix
@@ -219,30 +219,26 @@ in
       VideoRam 192000
     '';
 
-    services.xserver.displayManager.job = {
-      logToFile = true;
-
-      execCmd = ''
-        ${optionalString (cfg.pulseaudio)
-          "export PULSE_COOKIE=/var/run/pulse/.config/pulse/cookie"}
-        exec ${pkgs.xpra}/bin/xpra start \
-          --daemon=off \
-          --log-dir=/var/log \
-          --log-file=xpra.log \
-          --opengl=on \
-          --clipboard=on \
-          --notifications=on \
-          --speaker=yes \
-          --mdns=no \
-          --pulseaudio=no \
-          ${optionalString (cfg.pulseaudio) "--sound-source=pulse"} \
-          --socket-dirs=/var/run/xpra \
-          --xvfb="xpra_Xdummy ${concatStringsSep " " dmcfg.xserverArgs}" \
-          ${optionalString (cfg.bindTcp != null) "--bind-tcp=${cfg.bindTcp}"} \
-          --auth=${cfg.auth} \
-          ${concatStringsSep " " cfg.extraOptions}
-      '';
-    };
+    services.xserver.displayManager.job.execCmd = ''
+      ${optionalString (cfg.pulseaudio)
+        "export PULSE_COOKIE=/var/run/pulse/.config/pulse/cookie"}
+      exec ${pkgs.xpra}/bin/xpra start \
+        --daemon=off \
+        --log-dir=/var/log \
+        --log-file=xpra.log \
+        --opengl=on \
+        --clipboard=on \
+        --notifications=on \
+        --speaker=yes \
+        --mdns=no \
+        --pulseaudio=no \
+        ${optionalString (cfg.pulseaudio) "--sound-source=pulse"} \
+        --socket-dirs=/var/run/xpra \
+        --xvfb="xpra_Xdummy ${concatStringsSep " " dmcfg.xserverArgs}" \
+        ${optionalString (cfg.bindTcp != null) "--bind-tcp=${cfg.bindTcp}"} \
+        --auth=${cfg.auth} \
+        ${concatStringsSep " " cfg.extraOptions}
+    '';
 
     services.xserver.terminateOnReset = false;
 
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 070a02473437..34ae8c11a3f0 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -13,7 +13,8 @@ let
 
   # Map video driver names to driver packages. FIXME: move into card-specific modules.
   knownVideoDrivers = {
-    virtualbox = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; };
+    # Alias so people can keep using "virtualbox" instead of "vboxvideo".
+    virtualbox = { modules = [ xorg.xf86videovboxvideo ]; driverName = "vboxvideo"; };
 
     # modesetting does not have a xf86videomodesetting package as it is included in xorgserver
     modesetting = {};
@@ -564,8 +565,6 @@ in
           knownVideoDrivers;
       in optional (driver != null) ({ inherit name; modules = []; driverName = name; } // driver));
 
-    nixpkgs.config = optionalAttrs (elem "vboxvideo" cfg.videoDrivers) { xorg.abiCompat = "1.18"; };
-
     assertions = [
       { assertion = config.security.polkit.enable;
         message = "X11 requires Polkit to be enabled (‘security.polkit.enable = true’).";
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 3bc33a20a09f..6a4ac8128ab3 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -246,10 +246,7 @@ checkFS() {
     if [ "$fsType" = iso9660 -o "$fsType" = udf ]; then return 0; fi
 
     # Don't check resilient COWs as they validate the fs structures at mount time
-    if [ "$fsType" = btrfs -o "$fsType" = zfs ]; then return 0; fi
-
-    # Skip fsck for bcachefs - not implemented yet.
-    if [ "$fsType" = bcachefs ]; then return 0; fi
+    if [ "$fsType" = btrfs -o "$fsType" = zfs -o "$fsType" = bcachefs ]; then return 0; fi
 
     # Skip fsck for nilfs2 - not needed by design and no fsck tool for this filesystem.
     if [ "$fsType" = nilfs2 ]; then return 0; fi
diff --git a/nixos/modules/tasks/filesystems/bcachefs.nix b/nixos/modules/tasks/filesystems/bcachefs.nix
index 227707173a3d..5fda24adb978 100644
--- a/nixos/modules/tasks/filesystems/bcachefs.nix
+++ b/nixos/modules/tasks/filesystems/bcachefs.nix
@@ -1,26 +1,65 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, utils, ... }:
 
 with lib;
 
 let
 
-  inInitrd = any (fs: fs == "bcachefs") config.boot.initrd.supportedFilesystems;
+  bootFs = filterAttrs (n: fs: (fs.fsType == "bcachefs") && (utils.fsNeededForBoot fs)) config.fileSystems;
+
+  commonFunctions = ''
+    prompt() {
+        local name="$1"
+        printf "enter passphrase for $name: "
+    }
+    tryUnlock() {
+        local name="$1"
+        local path="$2"
+        if bcachefs unlock -c $path > /dev/null 2> /dev/null; then    # test for encryption
+            prompt $name
+            until bcachefs unlock $path 2> /dev/null; do              # repeat until sucessfully unlocked
+                printf "unlocking failed!\n"
+                prompt $name
+            done
+            printf "unlocking successful.\n"
+        fi
+    }
+  '';
+
+  openCommand = name: fs:
+    let
+      # we need only unlock one device manually, and cannot pass multiple at once
+      # remove this adaptation when bcachefs implements mounting by filesystem uuid
+      # also, implement automatic waiting for the constituent devices when that happens
+      # bcachefs does not support mounting devices with colons in the path, ergo we don't (see #49671)
+      firstDevice = head (splitString ":" fs.device);
+    in
+      ''
+        tryUnlock ${name} ${firstDevice}
+      '';
 
 in
 
 {
-  config = mkIf (any (fs: fs == "bcachefs") config.boot.supportedFilesystems) {
+  config = mkIf (elem "bcachefs" config.boot.supportedFilesystems) (mkMerge [
+    {
+      system.fsPackages = [ pkgs.bcachefs-tools ];
 
-    system.fsPackages = [ pkgs.bcachefs-tools ];
+      # use kernel package with bcachefs support until it's in mainline
+      boot.kernelPackages = pkgs.linuxPackages_testing_bcachefs;
+    }
 
-    # use kernel package with bcachefs support until it's in mainline
-    boot.kernelPackages = pkgs.linuxPackages_testing_bcachefs;
-    boot.initrd.availableKernelModules = mkIf inInitrd [ "bcachefs" ];
+    (mkIf ((elem "bcachefs" config.boot.initrd.supportedFilesystems) || (bootFs != {})) {
+      # the cryptographic modules are required only for decryption attempts
+      boot.initrd.availableKernelModules = [ "bcachefs" "chacha20" "poly1305" ];
 
-    boot.initrd.extraUtilsCommands = mkIf inInitrd
-      ''
-        copy_bin_and_libs ${pkgs.bcachefs-tools}/bin/fsck.bcachefs
+      boot.initrd.extraUtilsCommands = ''
+        copy_bin_and_libs ${pkgs.bcachefs-tools}/bin/bcachefs
+      '';
+      boot.initrd.extraUtilsCommandsTest = ''
+        $out/bin/bcachefs version
       '';
 
-  };
+      boot.initrd.postDeviceCommands = commonFunctions + concatStrings (mapAttrsToList openCommand bootFs);
+    })
+  ]);
 }
diff --git a/nixos/modules/virtualisation/gce-images.nix b/nixos/modules/virtualisation/gce-images.nix
index 575bbaadbcdb..5354d91deb93 100644
--- a/nixos/modules/virtualisation/gce-images.nix
+++ b/nixos/modules/virtualisation/gce-images.nix
@@ -4,6 +4,6 @@ let self = {
   "16.03" = "gs://nixos-cloud-images/nixos-image-16.03.847.8688c17-x86_64-linux.raw.tar.gz";
   "17.03" = "gs://nixos-cloud-images/nixos-image-17.03.1082.4aab5c5798-x86_64-linux.raw.tar.gz";
   "18.03" = "gs://nixos-cloud-images/nixos-image-18.03.132536.fdb5ba4cdf9-x86_64-linux.raw.tar.gz";
-
-  latest = self."18.03";
+  "18.09" = "gs://nixos-cloud-images/nixos-image-18.09.1228.a4c4cbb613c-x86_64-linux.raw.tar.gz";
+  latest = self."18.09";
 }; in self
diff --git a/nixos/release.nix b/nixos/release.nix
index 4647f28be186..e6abd003e881 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -14,28 +14,19 @@ let
   versionSuffix =
     (if stableBranch then "." else "pre") + "${toString nixpkgs.revCount}.${nixpkgs.shortRev}";
 
-  importTest = fn: args: system: import fn ({
-    inherit system;
-  } // args);
-
-  # Note: only supportedSystems are considered.
-  callTestOnMatchingSystems = systems: fn: args:
-    forMatchingSystems
-      (intersectLists supportedSystems systems)
-      (system: hydraJob (importTest fn args system));
-  callTest = callTestOnMatchingSystems supportedSystems;
-
-  callSubTests = callSubTestsOnMatchingSystems supportedSystems;
-  callSubTestsOnMatchingSystems = systems: fn: args: let
-    discover = attrs: let
-      subTests = filterAttrs (const (hasAttr "test")) attrs;
-    in mapAttrs (const (t: hydraJob t.test)) subTests;
-
-    discoverForSystem = system: mapAttrs (_: test: {
-      ${system} = test;
-    }) (discover (importTest fn args system));
-
-  in foldAttrs mergeAttrs {} (map discoverForSystem (intersectLists systems supportedSystems));
+  # Run the tests for each platform.  You can run a test by doing
+  # e.g. ‘nix-build -A tests.login.x86_64-linux’, or equivalently,
+  # ‘nix-build tests/login.nix -A result’.
+  allTestsForSystem = system:
+    import ./tests/all-tests.nix {
+      inherit system;
+      pkgs = import nixpkgs { inherit system; };
+      callTest = t: {
+        ${system} = hydraJob t.test;
+      };
+    };
+  allTests =
+    foldAttrs recursiveUpdate {} (map allTestsForSystem supportedSystems);
 
   pkgs = import nixpkgs { system = "x86_64-linux"; };
 
@@ -45,6 +36,7 @@ let
       system.nixos.revision = nixpkgs.rev or nixpkgs.shortRev;
     };
 
+  makeModules = module: rest: [ configuration versionModule module rest ];
 
   makeIso =
     { module, type, system, ... }:
@@ -53,7 +45,9 @@ let
 
     hydraJob ((import lib/eval-config.nix {
       inherit system;
-      modules = [ configuration module versionModule { isoImage.isoBaseName = "nixos-${type}"; } ];
+      modules = makeModules module {
+        isoImage.isoBaseName = "nixos-${type}";
+      };
     }).config.system.build.isoImage);
 
 
@@ -64,7 +58,7 @@ let
 
     hydraJob ((import lib/eval-config.nix {
       inherit system;
-      modules = [ configuration module versionModule ];
+      modules = makeModules module {};
     }).config.system.build.sdImage);
 
 
@@ -77,7 +71,7 @@ let
 
       config = (import lib/eval-config.nix {
         inherit system;
-        modules = [ configuration module versionModule ];
+        modules = makeModules module {};
       }).config;
 
       tarball = config.system.build.tarball;
@@ -97,7 +91,7 @@ let
 
   buildFromConfig = module: sel: forAllSystems (system: hydraJob (sel (import ./lib/eval-config.nix {
     inherit system;
-    modules = [ configuration module versionModule ] ++ singleton
+    modules = makeModules module
       ({ ... }:
       { fileSystems."/".device  = mkDefault "/dev/sda1";
         boot.loader.grub.device = mkDefault "/dev/sda";
@@ -108,7 +102,7 @@ let
     let
       configEvaled = import lib/eval-config.nix {
         inherit system;
-        modules = [ module versionModule ];
+        modules = makeModules module {};
       };
       build = configEvaled.config.system.build;
       kernelTarget = configEvaled.pkgs.stdenv.hostPlatform.platform.kernelTarget;
@@ -242,198 +236,7 @@ in rec {
     };
   */
 
-
-  # Run the tests for each platform.  You can run a test by doing
-  # e.g. ‘nix-build -A tests.login.x86_64-linux’, or equivalently,
-  # ‘nix-build tests/login.nix -A result’.
-  tests.atd = callTest tests/atd.nix {};
-  tests.acme = callTest tests/acme.nix {};
-  tests.avahi = callTest tests/avahi.nix {};
-  tests.beegfs = callTest tests/beegfs.nix {};
-  tests.upnp = callTest tests/upnp.nix {};
-  tests.bittorrent = callTest tests/bittorrent.nix {};
-  tests.bind = callTest tests/bind.nix {};
-  #tests.blivet = callTest tests/blivet.nix {};   # broken since 2017-07024
-  tests.boot = callSubTests tests/boot.nix {};
-  tests.boot-stage1 = callTest tests/boot-stage1.nix {};
-  tests.borgbackup = callTest tests/borgbackup.nix {};
-  tests.buildbot = callSubTests tests/buildbot.nix {};
-  tests.cadvisor = callTestOnMatchingSystems ["x86_64-linux"] tests/cadvisor.nix {};
-  tests.ceph = callTestOnMatchingSystems ["x86_64-linux"] tests/ceph.nix {};
-  tests.certmgr = callSubTests tests/certmgr.nix {};
-  tests.cfssl = callTestOnMatchingSystems ["x86_64-linux"] tests/cfssl.nix {};
-  tests.chromium = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/chromium.nix {}).stable or {};
-  tests.cjdns = callTest tests/cjdns.nix {};
-  tests.cloud-init = callTest tests/cloud-init.nix {};
-  tests.codimd = callTest tests/codimd.nix {};
-  tests.containers-ipv4 = callTest tests/containers-ipv4.nix {};
-  tests.containers-ipv6 = callTest tests/containers-ipv6.nix {};
-  tests.containers-bridge = callTest tests/containers-bridge.nix {};
-  tests.containers-imperative = callTest tests/containers-imperative.nix {};
-  tests.containers-extra_veth = callTest tests/containers-extra_veth.nix {};
-  tests.containers-physical_interfaces = callTest tests/containers-physical_interfaces.nix {};
-  tests.containers-restart_networking = callTest tests/containers-restart_networking.nix {};
-  tests.containers-tmpfs = callTest tests/containers-tmpfs.nix {};
-  tests.containers-hosts = callTest tests/containers-hosts.nix {};
-  tests.containers-macvlans = callTest tests/containers-macvlans.nix {};
-  tests.couchdb = callTest tests/couchdb.nix {};
-  tests.deluge = callTest tests/deluge.nix {};
-  tests.dhparams = callTest tests/dhparams.nix {};
-  tests.docker = callTestOnMatchingSystems ["x86_64-linux"] tests/docker.nix {};
-  tests.docker-tools = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-tools.nix {};
-  tests.docker-tools-overlay = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-tools-overlay.nix {};
-  tests.docker-edge = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-edge.nix {};
-  tests.docker-preloader = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-preloader.nix {};
-  tests.docker-registry = callTest tests/docker-registry.nix {};
-  tests.dovecot = callTest tests/dovecot.nix {};
-  tests.dnscrypt-proxy = callTestOnMatchingSystems ["x86_64-linux"] tests/dnscrypt-proxy.nix {};
-  tests.ecryptfs = callTest tests/ecryptfs.nix {};
-  tests.etcd = callTestOnMatchingSystems ["x86_64-linux"] tests/etcd.nix {};
-  tests.ec2-nixops = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-nixops or {};
-  # ec2-config doesn't work in a sandbox as the simulated ec2 instance needs network access
-  #tests.ec2-config = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-config or {};
-  tests.elk = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/elk.nix {};
-  tests.env = callTest tests/env.nix {};
-  tests.ferm = callTest tests/ferm.nix {};
-  tests.firefox = callTest tests/firefox.nix {};
-  tests.flatpak = callTest tests/flatpak.nix {};
-  tests.firewall = callTest tests/firewall.nix {};
-  tests.fsck = callTest tests/fsck.nix {};
-  tests.fwupd = callTest tests/fwupd.nix {};
-  tests.gdk-pixbuf = callTest tests/gdk-pixbuf.nix {};
-  tests.gitlab = callTest tests/gitlab.nix {};
-  tests.gitolite = callTest tests/gitolite.nix {};
-  tests.gjs = callTest tests/gjs.nix {};
-  tests.gocd-agent = callTest tests/gocd-agent.nix {};
-  tests.gocd-server = callTest tests/gocd-server.nix {};
-  tests.gnome3 = callTest tests/gnome3.nix {};
-  tests.gnome3-gdm = callTest tests/gnome3-gdm.nix {};
-  tests.grafana = callTest tests/grafana.nix {};
-  tests.graphite = callTest tests/graphite.nix {};
-  tests.hadoop.hdfs = callTestOnMatchingSystems [ "x86_64-linux" ] tests/hadoop/hdfs.nix {};
-  tests.hadoop.yarn = callTestOnMatchingSystems [ "x86_64-linux" ] tests/hadoop/yarn.nix {};
-  tests.hardened = callTest tests/hardened.nix { };
-  tests.haproxy = callTest tests/haproxy.nix {};
-  tests.hibernate = callTest tests/hibernate.nix {};
-  tests.hitch = callTest tests/hitch {};
-  tests.home-assistant = callTest tests/home-assistant.nix { };
-  tests.hound = callTest tests/hound.nix {};
-  tests.hocker-fetchdocker = callTest tests/hocker-fetchdocker {};
-  tests.hydra = callTest tests/hydra {};
-  tests.i3wm = callTest tests/i3wm.nix {};
-  tests.iftop = callTest tests/iftop.nix {};
-  tests.initrd-network-ssh = callTest tests/initrd-network-ssh {};
-  tests.installer = callSubTests tests/installer.nix {};
-  tests.influxdb = callTest tests/influxdb.nix {};
-  tests.ipv6 = callTest tests/ipv6.nix {};
-  tests.jenkins = callTest tests/jenkins.nix {};
-  tests.ostree = callTest tests/ostree.nix {};
-  tests.osquery = callTest tests/osquery.nix {};
-  tests.plasma5 = callTest tests/plasma5.nix {};
-  tests.plotinus = callTest tests/plotinus.nix {};
-  tests.keymap = callSubTests tests/keymap.nix {};
-  tests.initrdNetwork = callTest tests/initrd-network.nix {};
-  tests.kafka = callSubTests tests/kafka.nix {};
-  tests.kernel-latest = callTest tests/kernel-latest.nix {};
-  tests.kernel-lts = callTest tests/kernel-lts.nix {};
-  tests.kubernetes.dns = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/kubernetes/dns.nix {};
-  ## kubernetes.e2e should eventually replace kubernetes.rbac when it works
-  #tests.kubernetes.e2e = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/kubernetes/e2e.nix {};
-  tests.kubernetes.rbac = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/kubernetes/rbac.nix {};
-  tests.latestKernel.login = callTest tests/login.nix { latestKernel = true; };
-  tests.ldap = callTest tests/ldap.nix {};
-  #tests.lightdm = callTest tests/lightdm.nix {};
-  tests.login = callTest tests/login.nix {};
-  #tests.logstash = callTest tests/logstash.nix {};
-  tests.mathics = callTest tests/mathics.nix {};
-  tests.matrix-synapse = callTest tests/matrix-synapse.nix {};
-  tests.memcached = callTest tests/memcached.nix {};
-  tests.mesos = callTest tests/mesos.nix {};
-  tests.misc = callTest tests/misc.nix {};
-  tests.mongodb = callTest tests/mongodb.nix {};
-  tests.mpd = callTest tests/mpd.nix {};
-  tests.mumble = callTest tests/mumble.nix {};
-  tests.munin = callTest tests/munin.nix {};
-  tests.mutableUsers = callTest tests/mutable-users.nix {};
-  tests.mysql = callTest tests/mysql.nix {};
-  tests.mysqlBackup = callTest tests/mysql-backup.nix {};
-  tests.mysqlReplication = callTest tests/mysql-replication.nix {};
-  tests.nat.firewall = callTest tests/nat.nix { withFirewall = true; };
-  tests.nat.firewall-conntrack = callTest tests/nat.nix { withFirewall = true; withConntrackHelpers = true; };
-  tests.nat.standalone = callTest tests/nat.nix { withFirewall = false; };
-  tests.netdata = callTest tests/netdata.nix { };
-  tests.networking.networkd = callSubTests tests/networking.nix { networkd = true; };
-  tests.networking.scripted = callSubTests tests/networking.nix { networkd = false; };
-  tests.nextcloud = callSubTests tests/nextcloud { };
-  # TODO: put in networking.nix after the test becomes more complete
-  tests.networkingProxy = callTest tests/networking-proxy.nix {};
-  tests.nexus = callTest tests/nexus.nix { };
-  tests.nfs3 = callTest tests/nfs.nix { version = 3; };
-  tests.nfs4 = callTest tests/nfs.nix { version = 4; };
-  tests.nginx = callTest tests/nginx.nix { };
-  tests.nghttpx = callTest tests/nghttpx.nix { };
-  tests.nix-ssh-serve = callTest tests/nix-ssh-serve.nix { };
-  tests.novacomd = callTestOnMatchingSystems ["x86_64-linux"] tests/novacomd.nix { };
-  tests.leaps = callTest tests/leaps.nix { };
-  tests.nsd = callTest tests/nsd.nix {};
-  tests.openssh = callTest tests/openssh.nix {};
-  tests.openldap = callTest tests/openldap.nix {};
-  tests.opensmtpd = callTest tests/opensmtpd.nix {};
-  tests.owncloud = callTest tests/owncloud.nix {};
-  tests.pam-oath-login = callTest tests/pam-oath-login.nix {};
-  tests.peerflix = callTest tests/peerflix.nix {};
-  tests.php-pcre = callTest tests/php-pcre.nix {};
-  tests.postgresql = callSubTests tests/postgresql.nix {};
-  tests.pgmanage = callTest tests/pgmanage.nix {};
-  tests.postgis = callTest tests/postgis.nix {};
-  tests.powerdns = callTest tests/powerdns.nix {};
-  tests.pgjwt = callTest tests/pgjwt.nix {};
-  tests.predictable-interface-names = callSubTests tests/predictable-interface-names.nix {};
-  tests.printing = callTest tests/printing.nix {};
-  tests.prometheus = callTest tests/prometheus.nix {};
-  tests.prometheus-exporters = callTest tests/prometheus-exporters.nix {};
-  tests.prosody = callTest tests/prosody.nix {};
-  tests.proxy = callTest tests/proxy.nix {};
-  tests.quagga = callTest tests/quagga.nix {};
-  tests.quake3 = callTest tests/quake3.nix {};
-  tests.rabbitmq = callTest tests/rabbitmq.nix {};
-  tests.radicale = callTest tests/radicale.nix {};
-  tests.redmine = callTest tests/redmine.nix {};
-  tests.rspamd = callSubTests tests/rspamd.nix {};
-  tests.rsyslogd = callSubTests tests/rsyslogd.nix {};
-  tests.runInMachine = callTest tests/run-in-machine.nix {};
-  tests.rxe = callTest tests/rxe.nix {};
-  tests.samba = callTest tests/samba.nix {};
-  tests.sddm = callSubTests tests/sddm.nix {};
-  tests.simple = callTest tests/simple.nix {};
-  tests.slim = callTest tests/slim.nix {};
-  tests.slurm = callTest tests/slurm.nix {};
-  tests.smokeping = callTest tests/smokeping.nix {};
-  tests.snapper = callTest tests/snapper.nix {};
-  tests.solr = callTest tests/solr.nix {};
-  #tests.statsd = callTest tests/statsd.nix {}; # statsd is broken: #45946
-  tests.strongswan-swanctl = callTest tests/strongswan-swanctl.nix {};
-  tests.sudo = callTest tests/sudo.nix {};
-  tests.systemd = callTest tests/systemd.nix {};
-  tests.switchTest = callTest tests/switch-test.nix {};
-  tests.taskserver = callTest tests/taskserver.nix {};
-  tests.tomcat = callTest tests/tomcat.nix {};
-  tests.tor = callTest tests/tor.nix {};
-  tests.transmission = callTest tests/transmission.nix {};
-  tests.udisks2 = callTest tests/udisks2.nix {};
-  tests.vault = callTest tests/vault.nix {};
-  tests.virtualbox = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/virtualbox.nix {};
-  tests.wordpress = callTest tests/wordpress.nix {};
-  tests.xautolock = callTest tests/xautolock.nix {};
-  tests.xdg-desktop-portal = callTest tests/xdg-desktop-portal.nix {};
-  tests.xfce = callTest tests/xfce.nix {};
-  tests.xmonad = callTest tests/xmonad.nix {};
-  tests.xrdp = callTest tests/xrdp.nix {};
-  tests.xss-lock = callTest tests/xss-lock.nix {};
-  tests.yabar = callTest tests/yabar.nix {};
-  tests.zookeeper = callTest tests/zookeeper.nix {};
-  tests.morty = callTest tests/morty.nix { };
-  tests.bcachefs = callTest tests/bcachefs.nix { };
+  tests = allTests;
 
   /* Build a bunch of typical closures so that Hydra can keep track of
      the evolution of closure sizes. */
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
new file mode 100644
index 000000000000..ec7178ec9cad
--- /dev/null
+++ b/nixos/tests/all-tests.nix
@@ -0,0 +1,214 @@
+{ system, pkgs, callTest }:
+# The return value of this function will be an attrset with arbitrary depth and
+# the `anything` returned by callTest at its test leafs.
+# The tests not supported by `system` will be replaced with `{}`, so that
+# `passthru.tests` can contain links to those without breaking on architectures
+# where said tests are unsupported.
+# Example callTest that just extracts the derivation from the test:
+#   callTest = t: t.test;
+
+with pkgs.lib;
+
+let
+  discoverTests = val:
+    if !isAttrs val then val
+    else if hasAttr "test" val then callTest val
+    else mapAttrs (n: s: discoverTests s) val;
+  handleTest = path: args:
+    discoverTests (import path ({ inherit system pkgs; } // args));
+  handleTestOn = systems: path: args:
+    if elem system systems then handleTest path args
+    else {};
+in
+{
+  acme = handleTestOn ["x86_64-linux"] ./acme.nix {};
+  atd = handleTest ./atd.nix {};
+  avahi = handleTest ./avahi.nix {};
+  bcachefs = handleTestOn ["x86_64-linux"] ./bcachefs.nix {}; # linux-4.18.2018.10.12 is unsupported on aarch64
+  beegfs = handleTestOn ["x86_64-linux"] ./beegfs.nix {}; # beegfs is unsupported on aarch64
+  bind = handleTest ./bind.nix {};
+  bittorrent = handleTest ./bittorrent.nix {};
+  #blivet = handleTest ./blivet.nix {};   # broken since 2017-07024
+  boot = handleTestOn ["x86_64-linux"] ./boot.nix {}; # syslinux is unsupported on aarch64
+  boot-stage1 = handleTest ./boot-stage1.nix {};
+  borgbackup = handleTest ./borgbackup.nix {};
+  buildbot = handleTest ./buildbot.nix {};
+  cadvisor = handleTestOn ["x86_64-linux"] ./cadvisor.nix {};
+  ceph = handleTestOn ["x86_64-linux"] ./ceph.nix {};
+  certmgr = handleTest ./certmgr.nix {};
+  cfssl = handleTestOn ["x86_64-linux"] ./cfssl.nix {};
+  chromium = (handleTestOn ["x86_64-linux"] ./chromium.nix {}).stable or {};
+  cjdns = handleTest ./cjdns.nix {};
+  cloud-init = handleTest ./cloud-init.nix {};
+  codimd = handleTest ./codimd.nix {};
+  containers-bridge = handleTest ./containers-bridge.nix {};
+  containers-extra_veth = handleTest ./containers-extra_veth.nix {};
+  containers-hosts = handleTest ./containers-hosts.nix {};
+  containers-imperative = handleTest ./containers-imperative.nix {};
+  containers-ipv4 = handleTest ./containers-ipv4.nix {};
+  containers-ipv6 = handleTest ./containers-ipv6.nix {};
+  containers-macvlans = handleTest ./containers-macvlans.nix {};
+  containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {};
+  containers-restart_networking = handleTest ./containers-restart_networking.nix {};
+  containers-tmpfs = handleTest ./containers-tmpfs.nix {};
+  #couchdb = handleTest ./couchdb.nix {}; # spidermonkey-1.8.5 is marked as broken
+  deluge = handleTest ./deluge.nix {};
+  dhparams = handleTest ./dhparams.nix {};
+  dnscrypt-proxy = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy.nix {};
+  docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
+  docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
+  docker-preloader = handleTestOn ["x86_64-linux"] ./docker-preloader.nix {};
+  docker-registry = handleTest ./docker-registry.nix {};
+  docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
+  docker-tools-overlay = handleTestOn ["x86_64-linux"] ./docker-tools-overlay.nix {};
+  dovecot = handleTest ./dovecot.nix {};
+  # ec2-config doesn't work in a sandbox as the simulated ec2 instance needs network access
+  #ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
+  ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {};
+  ecryptfs = handleTest ./ecryptfs.nix {};
+  elk = handleTestOn ["x86_64-linux"] ./elk.nix {};
+  env = handleTest ./env.nix {};
+  etcd = handleTestOn ["x86_64-linux"] ./etcd.nix {};
+  ferm = handleTest ./ferm.nix {};
+  firefox = handleTest ./firefox.nix {};
+  firewall = handleTest ./firewall.nix {};
+  flatpak = handleTest ./flatpak.nix {};
+  fsck = handleTest ./fsck.nix {};
+  fwupd = handleTestOn ["x86_64-linux"] ./fwupd.nix {}; # libsmbios is unsupported on aarch64
+  gdk-pixbuf = handleTest ./gdk-pixbuf.nix {};
+  gitea = handleTest ./gitea.nix {};
+  gitlab = handleTest ./gitlab.nix {};
+  gitolite = handleTest ./gitolite.nix {};
+  gjs = handleTest ./gjs.nix {};
+  gnome3 = handleTestOn ["x86_64-linux"] ./gnome3.nix {}; # libsmbios is unsupported on aarch64
+  gnome3-gdm = handleTestOn ["x86_64-linux"] ./gnome3-gdm.nix {}; # libsmbios is unsupported on aarch64
+  gocd-agent = handleTest ./gocd-agent.nix {};
+  gocd-server = handleTest ./gocd-server.nix {};
+  grafana = handleTest ./grafana.nix {};
+  graphite = handleTest ./graphite.nix {};
+  hadoop.hdfs = handleTestOn [ "x86_64-linux" ] ./hadoop/hdfs.nix {};
+  hadoop.yarn = handleTestOn [ "x86_64-linux" ] ./hadoop/yarn.nix {};
+  handbrake = handleTestOn ["x86_64-linux"] ./handbrake.nix {};
+  haproxy = handleTest ./haproxy.nix {};
+  #hardened = handleTest ./hardened.nix {}; # broken due useSandbox = true
+  hibernate = handleTest ./hibernate.nix {};
+  hitch = handleTest ./hitch {};
+  hocker-fetchdocker = handleTest ./hocker-fetchdocker {};
+  home-assistant = handleTest ./home-assistant.nix {};
+  hound = handleTest ./hound.nix {};
+  hydra = handleTest ./hydra {};
+  i3wm = handleTest ./i3wm.nix {};
+  iftop = handleTest ./iftop.nix {};
+  incron = handleTest ./incron.nix {};
+  influxdb = handleTest ./influxdb.nix {};
+  initrd-network-ssh = handleTest ./initrd-network-ssh {};
+  initrdNetwork = handleTest ./initrd-network.nix {};
+  installer = handleTest ./installer.nix {};
+  ipv6 = handleTest ./ipv6.nix {};
+  jenkins = handleTest ./jenkins.nix {};
+  kafka = handleTest ./kafka.nix {};
+  kernel-latest = handleTest ./kernel-latest.nix {};
+  kernel-lts = handleTest ./kernel-lts.nix {};
+  keymap = handleTest ./keymap.nix {};
+  kubernetes.dns = handleTestOn ["x86_64-linux"] ./kubernetes/dns.nix {};
+  # kubernetes.e2e should eventually replace kubernetes.rbac when it works
+  #kubernetes.e2e = handleTestOn ["x86_64-linux"] ./kubernetes/e2e.nix {};
+  kubernetes.rbac = handleTestOn ["x86_64-linux"] ./kubernetes/rbac.nix {};
+  latestKernel.login = handleTest ./login.nix { latestKernel = true; };
+  ldap = handleTest ./ldap.nix {};
+  leaps = handleTest ./leaps.nix {};
+  #lightdm = handleTest ./lightdm.nix {};
+  login = handleTest ./login.nix {};
+  #logstash = handleTest ./logstash.nix {};
+  mathics = handleTest ./mathics.nix {};
+  matrix-synapse = handleTest ./matrix-synapse.nix {};
+  memcached = handleTest ./memcached.nix {};
+  mesos = handleTest ./mesos.nix {};
+  misc = handleTest ./misc.nix {};
+  mongodb = handleTest ./mongodb.nix {};
+  morty = handleTest ./morty.nix {};
+  mpd = handleTest ./mpd.nix {};
+  mumble = handleTest ./mumble.nix {};
+  munin = handleTest ./munin.nix {};
+  mutableUsers = handleTest ./mutable-users.nix {};
+  mysql = handleTest ./mysql.nix {};
+  mysqlBackup = handleTest ./mysql-backup.nix {};
+  mysqlReplication = handleTest ./mysql-replication.nix {};
+  nat.firewall = handleTest ./nat.nix { withFirewall = true; };
+  nat.firewall-conntrack = handleTest ./nat.nix { withFirewall = true; withConntrackHelpers = true; };
+  nat.standalone = handleTest ./nat.nix { withFirewall = false; };
+  netdata = handleTest ./netdata.nix {};
+  networking.networkd = handleTest ./networking.nix { networkd = true; };
+  networking.scripted = handleTest ./networking.nix { networkd = false; };
+  # TODO: put in networking.nix after the test becomes more complete
+  networkingProxy = handleTest ./networking-proxy.nix {};
+  nextcloud = handleTest ./nextcloud {};
+  nexus = handleTest ./nexus.nix {};
+  nfs3 = handleTest ./nfs.nix { version = 3; };
+  nfs4 = handleTest ./nfs.nix { version = 4; };
+  nghttpx = handleTest ./nghttpx.nix {};
+  nginx = handleTest ./nginx.nix {};
+  nix-ssh-serve = handleTest ./nix-ssh-serve.nix {};
+  novacomd = handleTestOn ["x86_64-linux"] ./novacomd.nix {};
+  nsd = handleTest ./nsd.nix {};
+  openldap = handleTest ./openldap.nix {};
+  opensmtpd = handleTest ./opensmtpd.nix {};
+  openssh = handleTest ./openssh.nix {};
+  osquery = handleTest ./osquery.nix {};
+  ostree = handleTest ./ostree.nix {};
+  owncloud = handleTest ./owncloud.nix {};
+  pam-oath-login = handleTest ./pam-oath-login.nix {};
+  peerflix = handleTest ./peerflix.nix {};
+  pgjwt = handleTest ./pgjwt.nix {};
+  pgmanage = handleTest ./pgmanage.nix {};
+  php-pcre = handleTest ./php-pcre.nix {};
+  plasma5 = handleTest ./plasma5.nix {};
+  plotinus = handleTest ./plotinus.nix {};
+  postgis = handleTest ./postgis.nix {};
+  postgresql = handleTest ./postgresql.nix {};
+  powerdns = handleTest ./powerdns.nix {};
+  predictable-interface-names = handleTest ./predictable-interface-names.nix {};
+  printing = handleTest ./printing.nix {};
+  prometheus = handleTest ./prometheus.nix {};
+  prometheus-exporters = handleTest ./prometheus-exporters.nix {};
+  prosody = handleTest ./prosody.nix {};
+  proxy = handleTest ./proxy.nix {};
+  quagga = handleTest ./quagga.nix {};
+  quake3 = handleTest ./quake3.nix {};
+  rabbitmq = handleTest ./rabbitmq.nix {};
+  radicale = handleTest ./radicale.nix {};
+  redmine = handleTest ./redmine.nix {};
+  rspamd = handleTest ./rspamd.nix {};
+  rsyslogd = handleTest ./rsyslogd.nix {};
+  runInMachine = handleTest ./run-in-machine.nix {};
+  rxe = handleTest ./rxe.nix {};
+  samba = handleTest ./samba.nix {};
+  sddm = handleTest ./sddm.nix {};
+  simple = handleTest ./simple.nix {};
+  slim = handleTest ./slim.nix {};
+  slurm = handleTest ./slurm.nix {};
+  smokeping = handleTest ./smokeping.nix {};
+  snapper = handleTest ./snapper.nix {};
+  solr = handleTest ./solr.nix {};
+  strongswan-swanctl = handleTest ./strongswan-swanctl.nix {};
+  sudo = handleTest ./sudo.nix {};
+  switchTest = handleTest ./switch-test.nix {};
+  systemd = handleTest ./systemd.nix {};
+  taskserver = handleTest ./taskserver.nix {};
+  tomcat = handleTest ./tomcat.nix {};
+  tor = handleTest ./tor.nix {};
+  transmission = handleTest ./transmission.nix {};
+  udisks2 = handleTest ./udisks2.nix {};
+  upnp = handleTest ./upnp.nix {};
+  vault = handleTest ./vault.nix {};
+  virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
+  wordpress = handleTest ./wordpress.nix {};
+  xautolock = handleTest ./xautolock.nix {};
+  xdg-desktop-portal = handleTest ./xdg-desktop-portal.nix {};
+  xfce = handleTest ./xfce.nix {};
+  xmonad = handleTest ./xmonad.nix {};
+  xrdp = handleTest ./xrdp.nix {};
+  xss-lock = handleTest ./xss-lock.nix {};
+  yabar = handleTest ./yabar.nix {};
+  zookeeper = handleTest ./zookeeper.nix {};
+}
diff --git a/nixos/tests/boot.nix b/nixos/tests/boot.nix
index 301d9d0f817f..c9bb1e77c6d0 100644
--- a/nixos/tests/boot.nix
+++ b/nixos/tests/boot.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/buildbot.nix b/nixos/tests/buildbot.nix
index 399fd39005e2..210ad8e91df7 100644
--- a/nixos/tests/buildbot.nix
+++ b/nixos/tests/buildbot.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 
 let
   # Test ensures buildbot master comes up correctly and workers can connect
diff --git a/nixos/tests/certmgr.nix b/nixos/tests/certmgr.nix
index 8354c46b85f7..fe67833808ce 100644
--- a/nixos/tests/certmgr.nix
+++ b/nixos/tests/certmgr.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 let
   mkSpec = { host, service ? null, action }: {
     inherit action;
diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix
index e5097609fb27..af5db2a3dbe1 100644
--- a/nixos/tests/chromium.nix
+++ b/nixos/tests/chromium.nix
@@ -1,5 +1,6 @@
 { system ? builtins.currentSystem
-, pkgs ? import ../.. { inherit system; }
+, config ? {}
+, pkgs ? import ../.. { inherit system config; }
 , channelMap ? {
     stable = pkgs.chromium;
     beta   = pkgs.chromiumBeta;
@@ -7,7 +8,7 @@
   }
 }:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 mapAttrs (channel: chromiumPkg: makeTest rec {
diff --git a/nixos/tests/cloud-init.nix b/nixos/tests/cloud-init.nix
index 303e74086460..516d29c9036b 100644
--- a/nixos/tests/cloud-init.nix
+++ b/nixos/tests/cloud-init.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/ec2.nix b/nixos/tests/ec2.nix
index 8271747ccc63..ed6bf7da988c 100644
--- a/nixos/tests/ec2.nix
+++ b/nixos/tests/ec2.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/elk.nix b/nixos/tests/elk.nix
index 15be72b80bba..d787ac973005 100644
--- a/nixos/tests/elk.nix
+++ b/nixos/tests/elk.nix
@@ -1,6 +1,12 @@
-{ system ? builtins.currentSystem, enableUnfree ? false }:
-with import ../lib/testing.nix { inherit system; };
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; },
+  enableUnfree ? false
+}:
+
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
+
 let
   esUrl = "http://localhost:9200";
 
diff --git a/nixos/tests/gitea.nix b/nixos/tests/gitea.nix
new file mode 100644
index 000000000000..354334991852
--- /dev/null
+++ b/nixos/tests/gitea.nix
@@ -0,0 +1,77 @@
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
+
+with import ../lib/testing.nix { inherit system pkgs; };
+with pkgs.lib;
+
+{
+  mysql = makeTest {
+    name = "gitea-mysql";
+    meta.maintainers = [ maintainers.aanderse ];
+
+    machine =
+      { config, pkgs, ... }:
+      { services.mysql.enable = true;
+        services.mysql.package = pkgs.mariadb;
+        services.mysql.ensureDatabases = [ "gitea" ];
+        services.mysql.ensureUsers = [
+          { name = "gitea";
+            ensurePermissions = { "gitea.*" = "ALL PRIVILEGES"; };
+          }
+        ];
+
+        services.gitea.enable = true;
+        services.gitea.database.type = "mysql";
+        services.gitea.database.socket = "/run/mysqld/mysqld.sock";
+      };
+
+    testScript = ''
+      startAll;
+
+      $machine->waitForUnit('gitea.service');
+      $machine->waitForOpenPort('3000');
+      $machine->succeed("curl --fail http://localhost:3000/");
+    '';
+  };
+
+  postgres = makeTest {
+    name = "gitea-postgres";
+    meta.maintainers = [ maintainers.aanderse ];
+
+    machine =
+      { config, pkgs, ... }:
+      {
+        services.gitea.enable = true;
+        services.gitea.database.type = "postgres";
+        services.gitea.database.password = "secret";
+      };
+
+    testScript = ''
+      startAll;
+
+      $machine->waitForUnit('gitea.service');
+      $machine->waitForOpenPort('3000');
+      $machine->succeed("curl --fail http://localhost:3000/");
+    '';
+  };
+
+  sqlite = makeTest {
+    name = "gitea-sqlite";
+    meta.maintainers = [ maintainers.aanderse ];
+
+    machine =
+      { config, pkgs, ... }:
+      { services.gitea.enable = true;
+      };
+
+    testScript = ''
+      startAll;
+
+      $machine->waitForUnit('gitea.service');
+      $machine->waitForOpenPort('3000');
+      $machine->succeed("curl --fail http://localhost:3000/");
+    '';
+  };
+}
diff --git a/nixos/tests/gitlab.nix b/nixos/tests/gitlab.nix
index 53675c375e31..661caa8aa832 100644
--- a/nixos/tests/gitlab.nix
+++ b/nixos/tests/gitlab.nix
@@ -27,6 +27,7 @@ import ./make-test.nix ({ pkgs, lib, ...} : with lib; {
         enable = true;
         databasePassword = "dbPassword";
         initialRootPassword = "notproduction";
+        smtp.enable = true;
         secrets = {
           secret = "secret";
           otp = "otpsecret";
diff --git a/nixos/tests/handbrake.nix b/nixos/tests/handbrake.nix
new file mode 100644
index 000000000000..ae87e1f69a7d
--- /dev/null
+++ b/nixos/tests/handbrake.nix
@@ -0,0 +1,25 @@
+import ./make-test.nix ({ pkgs, ... }:
+let
+  # Download Big Buck Bunny example, licensed under CC Attribution 3.0.
+  testMkv = pkgs.fetchurl {
+    url = "https://github.com/Matroska-Org/matroska-test-files/blob/cf0792be144ac470c4b8052cfe19bb691993e3a2/test_files/test1.mkv?raw=true";
+    sha256 = "1hfxbbgxwfkzv85pvpvx55a72qsd0hxjbm9hkl5r3590zw4s75h9";
+  };
+in {
+  name = "handbrake";
+
+  meta = {
+    maintainers = with pkgs.stdenv.lib.maintainers; [ danieldk ];
+  };
+
+  machine = { pkgs, ... }: {
+    environment.systemPackages = with pkgs; [ handbrake ];
+  };
+
+  testScript = ''
+    # Test MP4 and MKV transcoding. Since this is a short clip, transcoding typically
+    # only takes a few seconds.
+    $machine->succeed("HandBrakeCLI -i ${testMkv} -o test.mp4 -e x264 -q 20 -B 160");
+    $machine->succeed("HandBrakeCLI -i ${testMkv} -o test.mkv -e x264 -q 20 -B 160");
+  '';
+})
diff --git a/nixos/tests/hydra/create-trivial-project.sh b/nixos/tests/hydra/create-trivial-project.sh
index 3cca5665acc5..39122c9b473a 100755
--- a/nixos/tests/hydra/create-trivial-project.sh
+++ b/nixos/tests/hydra/create-trivial-project.sh
@@ -31,7 +31,8 @@ mycurl -X POST -d '@data.json' $URL/login -c hydra-cookie.txt
 cat >data.json <<EOF
 {
   "displayname":"Trivial",
-  "enabled":"1"
+  "enabled":"1",
+  "visible":"1"
 }
 EOF
 mycurl --silent -X PUT $URL/project/$PROJECT_NAME -d @data.json -b hydra-cookie.txt
diff --git a/nixos/tests/incron.nix b/nixos/tests/incron.nix
new file mode 100644
index 000000000000..e39bbb5f096b
--- /dev/null
+++ b/nixos/tests/incron.nix
@@ -0,0 +1,52 @@
+import ./make-test.nix ({ pkgs, lib, ... }:
+
+{
+  name = "incron";
+  meta.maintainers = [ lib.maintainers.aanderse ];
+
+  machine =
+    { ... }:
+    { services.incron.enable = true;
+      services.incron.extraPackages = [ pkgs.coreutils ];
+      services.incron.systab = ''
+        /test IN_CREATE,IN_MODIFY,IN_CLOSE_WRITE,IN_MOVED_FROM,IN_MOVED_TO echo "$@/$# $%" >> /root/incron.log
+      '';
+
+      # ensure the directory to be monitored exists before incron is started
+      system.activationScripts.incronTest = ''
+        mkdir /test
+      '';
+    };
+
+  testScript = ''
+    startAll;
+
+    $machine->waitForUnit("multi-user.target");
+    $machine->waitForUnit("incron.service");
+
+    $machine->succeed("test -d /test");
+    # create some activity for incron to monitor
+    $machine->succeed("touch /test/file");
+    $machine->succeed("echo foo >> /test/file");
+    $machine->succeed("mv /test/file /root");
+    $machine->succeed("mv /root/file /test");
+
+    $machine->sleep(1);
+
+    # touch /test/file
+    $machine->succeed("grep '/test/file IN_CREATE' /root/incron.log");
+
+    # echo foo >> /test/file
+    $machine->succeed("grep '/test/file IN_MODIFY' /root/incron.log");
+    $machine->succeed("grep '/test/file IN_CLOSE_WRITE' /root/incron.log");
+
+    # mv /test/file /root
+    $machine->succeed("grep '/test/file IN_MOVED_FROM' /root/incron.log");
+
+    # mv /root/file /test
+    $machine->succeed("grep '/test/file IN_MOVED_TO' /root/incron.log");
+
+    # ensure something unexpected is not present
+    $machine->fail("grep 'IN_OPEN' /root/incron.log");
+  '';
+})
diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 3f9fa0e6016c..e03fc459cb87 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/kafka.nix b/nixos/tests/kafka.nix
index c9fd74620efb..a833e01f9f5e 100644
--- a/nixos/tests/kafka.nix
+++ b/nixos/tests/kafka.nix
@@ -1,5 +1,9 @@
-{ system ? builtins.currentSystem }:
-with import ../lib/testing.nix { inherit system; };
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
+
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/keymap.nix b/nixos/tests/keymap.nix
index be880388314c..b19da251119b 100644
--- a/nixos/tests/keymap.nix
+++ b/nixos/tests/keymap.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 
 let
   readyFile  = "/tmp/readerReady";
diff --git a/nixos/tests/kubernetes/base.nix b/nixos/tests/kubernetes/base.nix
index e4bc5b326d34..b77da3414b34 100644
--- a/nixos/tests/kubernetes/base.nix
+++ b/nixos/tests/kubernetes/base.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../../lib/testing.nix { inherit system; };
+with import ../../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/make-test.nix b/nixos/tests/make-test.nix
index ee4ba310ad50..cee5da93454a 100644
--- a/nixos/tests/make-test.nix
+++ b/nixos/tests/make-test.nix
@@ -1,5 +1,9 @@
-f: { system ? builtins.currentSystem, ... } @ args:
+f: {
+  system ? builtins.currentSystem,
+  pkgs ? import ../.. { inherit system; config = {}; },
+  ...
+} @ args:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 
 makeTest (if pkgs.lib.isFunction f then f (args // { inherit pkgs; inherit (pkgs) lib; }) else f)
diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix
index d1d4fd41dda6..e689eadf1dd8 100644
--- a/nixos/tests/networking.nix
+++ b/nixos/tests/networking.nix
@@ -1,8 +1,10 @@
 { system ? builtins.currentSystem
+, config ? {}
+, pkgs ? import ../.. { inherit system config; }
 # bool: whether to use networkd in the tests
 , networkd }:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/nextcloud/default.nix b/nixos/tests/nextcloud/default.nix
index 66da6794b961..e4c7a70606cf 100644
--- a/nixos/tests/nextcloud/default.nix
+++ b/nixos/tests/nextcloud/default.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../../.. { inherit system config; }
+}:
 {
-  basic = import ./basic.nix { inherit system; };
-  with-postgresql-and-redis = import ./with-postgresql-and-redis.nix { inherit system; };
-  with-mysql-and-memcached = import ./with-mysql-and-memcached.nix { inherit system; };
+  basic = import ./basic.nix { inherit system pkgs; };
+  with-postgresql-and-redis = import ./with-postgresql-and-redis.nix { inherit system pkgs; };
+  with-mysql-and-memcached = import ./with-mysql-and-memcached.nix { inherit system pkgs; };
 }
diff --git a/nixos/tests/opensmtpd.nix b/nixos/tests/opensmtpd.nix
index 4d3479168f70..883ad7604941 100644
--- a/nixos/tests/opensmtpd.nix
+++ b/nixos/tests/opensmtpd.nix
@@ -120,4 +120,6 @@ import ./make-test.nix {
     $smtp2->waitUntilFails('smtpctl show queue | egrep .');
     $client->succeed('check-mail-landed >&2');
   '';
+
+  meta.timeout = 30;
 }
diff --git a/nixos/tests/postgresql.nix b/nixos/tests/postgresql.nix
index f1f09277f342..1d434b62a5cb 100644
--- a/nixos/tests/postgresql.nix
+++ b/nixos/tests/postgresql.nix
@@ -1,6 +1,11 @@
-{ system ? builtins.currentSystem }:
-with import ../lib/testing.nix { inherit system; };
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
+
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
+
 let
   postgresql-versions = pkgs.callPackages ../../pkgs/servers/sql/postgresql { };
   test-sql = pkgs.writeText "postgresql-test" ''
@@ -53,6 +58,7 @@ let
       # Check backup service
       $machine->succeed("systemctl start postgresqlBackup-postgres.service");
       $machine->succeed("zcat /var/backup/postgresql/postgres.sql.gz | grep '<test>ok</test>'");
+      $machine->succeed("stat -c '%a' /var/backup/postgresql/postgres.sql.gz | grep 600");
       $machine->shutdown;
     '';
 
diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix
index 0d73436c1c3f..8306abb8c42f 100644
--- a/nixos/tests/predictable-interface-names.nix
+++ b/nixos/tests/predictable-interface-names.nix
@@ -1,7 +1,10 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
 let
-  inherit (import ../lib/testing.nix { inherit system; }) makeTest pkgs;
+  inherit (import ../lib/testing.nix { inherit system pkgs; }) makeTest;
 in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: {
   name = pkgs.lib.optionalString (!predictable) "un" + "predictable"
        + pkgs.lib.optionalString withNetworkd "Networkd";
diff --git a/nixos/tests/rspamd.nix b/nixos/tests/rspamd.nix
index af765f37b91b..e16a9e6ffbc6 100644
--- a/nixos/tests/rspamd.nix
+++ b/nixos/tests/rspamd.nix
@@ -1,6 +1,11 @@
-{ system ? builtins.currentSystem }:
-with import ../lib/testing.nix { inherit system; };
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
+
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
+
 let
   initMachine = ''
     startAll
@@ -28,6 +33,8 @@ let
       ${checkSocket "/run/rspamd/rspamd.sock" "rspamd" "rspamd" "660" }
       sleep 10;
       $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'CONFDIR/worker-controller.inc' /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'CONFDIR/worker-normal.inc' /etc/rspamd/rspamd.conf"));
       $machine->log($machine->succeed("systemctl cat rspamd.service"));
       $machine->log($machine->succeed("curl http://localhost:11334/auth"));
       $machine->log($machine->succeed("curl http://127.0.0.1:11334/auth"));
@@ -56,6 +63,8 @@ in
       ${checkSocket "/run/rspamd.sock" "root" "root" "600" }
       ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" }
       $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'CONFDIR/worker-controller.inc' /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'CONFDIR/worker-normal.inc' /etc/rspamd/rspamd.conf"));
       $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat"));
       $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping"));
     '';
@@ -78,6 +87,15 @@ in
           owner = "root";
           group = "root";
         }];
+        workers.controller2 = {
+          type = "controller";
+          bindSockets = [ "0.0.0.0:11335" ];
+          extraConfig = ''
+            static_dir = "''${WWWDIR}";
+            secure_ip = null;
+            password = "verysecretpassword";
+          '';
+        };
       };
     };
 
@@ -87,8 +105,14 @@ in
       ${checkSocket "/run/rspamd.sock" "root" "root" "600" }
       ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" }
       $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'CONFDIR/worker-controller.inc' /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'CONFDIR/worker-normal.inc' /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'LOCAL_CONFDIR/override.d/worker-controller2.inc' /etc/rspamd/rspamd.conf"));
+      $machine->log($machine->succeed("grep 'verysecretpassword' /etc/rspamd/override.d/worker-controller2.inc"));
+      $machine->waitUntilSucceeds("journalctl -u rspamd | grep -i 'starting controller process' >&2");
       $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat"));
       $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping"));
+      $machine->log($machine->succeed("curl http://localhost:11335/ping"));
     '';
   };
   customLuaRules = makeTest {
@@ -110,16 +134,33 @@ in
       '';
       services.rspamd = {
         enable = true;
-        locals."groups.conf".text = ''
-          group "cows" {
-            symbol {
-              NO_MUH = {
-                weight = 1.0;
-                description = "Mails should not muh";
+        locals = {
+          "antivirus.conf" = mkIf false { text = ''
+              clamav {
+                action = "reject";
+                symbol = "CLAM_VIRUS";
+                type = "clamav";
+                log_clean = true;
+                servers = "/run/clamav/clamd.ctl";
+              }
+            '';};
+          "redis.conf" = {
+            enable = false;
+            text = ''
+              servers = "127.0.0.1";
+            '';
+          };
+          "groups.conf".text = ''
+            group "cows" {
+              symbol {
+                NO_MUH = {
+                  weight = 1.0;
+                  description = "Mails should not muh";
+                }
               }
             }
-          }
-        '';
+          '';
+        };
         localLuaRules = pkgs.writeText "rspamd.local.lua" ''
           local rspamd_logger = require "rspamd_logger"
           rspamd_config.NO_MUH = {
@@ -152,6 +193,10 @@ in
       $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf"));
       $machine->log($machine->succeed("cat /etc/rspamd/rspamd.local.lua"));
       $machine->log($machine->succeed("cat /etc/rspamd/local.d/groups.conf"));
+      # Verify that redis.conf was not written
+      $machine->fail("cat /etc/rspamd/local.d/redis.conf >&2");
+      # Verify that antivirus.conf was not written
+      $machine->fail("cat /etc/rspamd/local.d/antivirus.conf >&2");
       ${checkSocket "/run/rspamd/rspamd.sock" "rspamd" "rspamd" "660" }
       $machine->log($machine->succeed("curl --unix-socket /run/rspamd/rspamd.sock http://localhost/ping"));
       $machine->log($machine->succeed("rspamc -h 127.0.0.1:11334 stat"));
@@ -162,4 +207,48 @@ in
       $machine->log($machine->succeed("cat /etc/tests/muh.eml | rspamc -h 127.0.0.1:11334 symbols | grep NO_MUH"));
     '';
   };
+  postfixIntegration = makeTest {
+    name = "rspamd-postfix-integration";
+    machine = {
+      environment.systemPackages = with pkgs; [ msmtp ];
+      environment.etc."tests/gtube.eml".text = ''
+        From: Sheep1<bah@example.com>
+        To: Sheep2<tester@example.com>
+        Subject: Evil cows
+
+        I find cows to be evil don't you?
+
+        XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
+      '';
+      environment.etc."tests/example.eml".text = ''
+        From: Sheep1<bah@example.com>
+        To: Sheep2<tester@example.com>
+        Subject: Evil cows
+
+        I find cows to be evil don't you?
+      '';
+      users.users.tester.password = "test";
+      services.postfix = {
+        enable = true;
+        destination = ["example.com"];
+      };
+      services.rspamd = {
+        enable = true;
+        postfix.enable = true;
+      };
+    };
+    testScript = ''
+      ${initMachine}
+      $machine->waitForOpenPort(11334);
+      $machine->waitForOpenPort(25);
+      ${checkSocket "/run/rspamd/rspamd-milter.sock" "rspamd" "postfix" "660" }
+      $machine->log($machine->succeed("rspamc -h 127.0.0.1:11334 stat"));
+      $machine->log($machine->succeed("msmtp --host=localhost -t --read-envelope-from < /etc/tests/example.eml"));
+      $machine->log($machine->fail("msmtp --host=localhost -t --read-envelope-from < /etc/tests/gtube.eml"));
+
+      $machine->waitUntilFails('[ "$(postqueue -p)" != "Mail queue is empty" ]');
+      $machine->fail("journalctl -u postfix | grep -i error >&2");
+      $machine->fail("journalctl -u postfix | grep -i warning >&2");
+    '';
+  };
 }
diff --git a/nixos/tests/rsyslogd.nix b/nixos/tests/rsyslogd.nix
index 969d59e0f2c2..f17e61814c5e 100644
--- a/nixos/tests/rsyslogd.nix
+++ b/nixos/tests/rsyslogd.nix
@@ -1,7 +1,11 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
+
 {
   test1 = makeTest {
     name = "rsyslogd-test1";
diff --git a/nixos/tests/run-in-machine.nix b/nixos/tests/run-in-machine.nix
index bd90dc3080bd..116f5dc28a62 100644
--- a/nixos/tests/run-in-machine.nix
+++ b/nixos/tests/run-in-machine.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 
 let
   output = runInMachine {
diff --git a/nixos/tests/sddm.nix b/nixos/tests/sddm.nix
index 7b9fdc0b3441..678bcbeab20a 100644
--- a/nixos/tests/sddm.nix
+++ b/nixos/tests/sddm.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 
 let
   inherit (pkgs) lib;
diff --git a/nixos/tests/statsd.nix b/nixos/tests/statsd.nix
deleted file mode 100644
index 666961249ced..000000000000
--- a/nixos/tests/statsd.nix
+++ /dev/null
@@ -1,51 +0,0 @@
-import ./make-test.nix ({ pkgs, lib, ... }:
-
-with lib;
-
-{
-  name = "statsd";
-  meta = with pkgs.stdenv.lib.maintainers; {
-    maintainers = [ ma27 ];
-  };
-
-  machine = {
-    services.statsd.enable = true;
-    services.statsd.backends = [ "statsd-influxdb-backend" "console" ];
-    services.statsd.extraConfig = ''
-      influxdb: {
-        username: "root",
-        password: "root",
-        database: "statsd"
-      }
-    '';
-
-    services.influxdb.enable = true;
-
-    systemd.services.influx-init = {
-      description = "Setup Influx Test Base";
-      after = [ "influxdb.service" ];
-      before = [ "statsd.service" ];
-
-      script = ''
-        echo "CREATE DATABASE statsd" | ${pkgs.influxdb}/bin/influx
-      '';
-    };
-  };
-
-  testScript = ''
-    $machine->start();
-    $machine->waitForUnit("statsd.service");
-    $machine->waitForOpenPort(8126);
-
-    # check state of the `statsd` server
-    $machine->succeed('[ "health: up" = "$(echo health | nc 127.0.0.1 8126 -w 120 -N)" ];');
-
-    # confirm basic examples for metrics derived from docs:
-    # https://github.com/etsy/statsd/blob/v0.8.0/README.md#usage and
-    # https://github.com/etsy/statsd/blob/v0.8.0/docs/admin_interface.md
-    $machine->succeed("echo 'foo:1|c' | nc -u -w 0  127.0.0.1 8125");
-    $machine->succeed("echo counters | nc -w 120 127.0.0.1 8126 -N | grep foo");
-    $machine->succeed("echo 'delcounters foo' | nc -w 120 127.0.0.1 8126 -N");
-    $machine->fail("echo counters | nc -w 120 127.0.0.1 8126 -N | grep foo");
-  '';
-})
diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix
index ce84576edca1..385e2939fe3b 100644
--- a/nixos/tests/virtualbox.nix
+++ b/nixos/tests/virtualbox.nix
@@ -1,6 +1,11 @@
-{ system ? builtins.currentSystem, debug ? false, enableUnfree ? false }:
-
-with import ../lib/testing.nix { inherit system; };
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; },
+  debug ? false,
+  enableUnfree ? false
+}:
+
+with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
 let
diff --git a/nixos/tests/zfs.nix b/nixos/tests/zfs.nix
index 1434038e90c1..d7a08268e984 100644
--- a/nixos/tests/zfs.nix
+++ b/nixos/tests/zfs.nix
@@ -1,6 +1,9 @@
-{ system ? builtins.currentSystem }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
 
-with import ../lib/testing.nix { inherit system; };
+with import ../lib/testing.nix { inherit system pkgs; };
 
 let