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/x-windows.xml6
-rw-r--r--nixos/doc/manual/installation/installing.xml6
-rw-r--r--nixos/doc/manual/man-nixos-rebuild.xml40
-rw-r--r--nixos/doc/manual/release-notes/release-notes.xml1
-rw-r--r--nixos/doc/manual/release-notes/rl-1909.xml11
-rw-r--r--nixos/doc/manual/release-notes/rl-2003.xml80
-rw-r--r--nixos/doc/xmlformat.conf1
-rw-r--r--nixos/modules/config/fonts/fontconfig.nix4
-rw-r--r--nixos/modules/config/shells-environment.nix2
-rw-r--r--nixos/modules/config/system-environment.nix76
-rw-r--r--nixos/modules/config/system-path.nix3
-rw-r--r--nixos/modules/config/terminfo.nix2
-rw-r--r--nixos/modules/config/xdg/icons.nix27
-rw-r--r--nixos/modules/hardware/brightnessctl.nix1
-rw-r--r--nixos/modules/hardware/printers.nix6
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image.nix4
-rw-r--r--nixos/modules/module-list.nix7
-rw-r--r--nixos/modules/programs/environment.nix5
-rw-r--r--nixos/modules/programs/mtr.nix14
-rw-r--r--nixos/modules/programs/sway.nix2
-rw-r--r--nixos/modules/programs/x2goserver.nix2
-rw-r--r--nixos/modules/rename.nix14
-rw-r--r--nixos/modules/security/pam.nix9
-rw-r--r--nixos/modules/services/audio/roon-server.nix4
-rw-r--r--nixos/modules/services/audio/spotifyd.nix2
-rw-r--r--nixos/modules/services/cluster/kubernetes/flannel.nix4
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix20
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/default.nix2
-rw-r--r--nixos/modules/services/editors/emacs.nix8
-rw-r--r--nixos/modules/services/mail/mailcatcher.nix3
-rw-r--r--nixos/modules/services/mail/mailman.nix205
-rw-r--r--nixos/modules/services/mail/rss2email.nix5
-rw-r--r--nixos/modules/services/misc/dysnomia.nix1
-rw-r--r--nixos/modules/services/misc/gitea.nix1
-rw-r--r--nixos/modules/services/misc/gitlab.nix10
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters.nix3
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix92
-rw-r--r--nixos/modules/services/network-filesystems/ceph.nix2
-rw-r--r--nixos/modules/services/networking/jormungandr.nix6
-rw-r--r--nixos/modules/services/networking/minidlna.nix67
-rw-r--r--nixos/modules/services/networking/networkmanager.nix33
-rw-r--r--nixos/modules/services/networking/ntp/chrony.nix (renamed from nixos/modules/services/networking/chrony.nix)11
-rw-r--r--nixos/modules/services/networking/ntp/ntpd.nix (renamed from nixos/modules/services/networking/ntpd.nix)1
-rw-r--r--nixos/modules/services/networking/ntp/openntpd.nix (renamed from nixos/modules/services/networking/openntpd.nix)1
-rw-r--r--nixos/modules/services/networking/pdns-recursor.nix2
-rw-r--r--nixos/modules/services/networking/toxvpn.nix2
-rw-r--r--nixos/modules/services/printing/cupsd.nix10
-rw-r--r--nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix2
-rw-r--r--nixos/modules/services/web-apps/moodle.nix23
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix33
-rw-r--r--nixos/modules/services/web-apps/restya-board.nix3
-rw-r--r--nixos/modules/services/web-apps/selfoss.nix2
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix2
-rw-r--r--nixos/modules/services/web-apps/wordpress.nix22
-rw-r--r--nixos/modules/services/web-apps/zabbix.nix4
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix1
-rw-r--r--nixos/modules/services/web-servers/phpfpm/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/enlightenment.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/mate.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix16
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce4-14.nix22
-rw-r--r--nixos/modules/services/x11/desktop-managers/xterm.nix5
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix36
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix36
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix7
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/pantheon.nix14
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix4
-rw-r--r--nixos/modules/services/x11/extra-layouts.nix5
-rw-r--r--nixos/modules/services/x11/redshift.nix16
-rw-r--r--nixos/modules/system/activation/activation-script.nix2
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl19
-rw-r--r--nixos/modules/system/boot/kernel.nix2
-rw-r--r--nixos/modules/system/boot/systemd.nix5
-rw-r--r--nixos/modules/tasks/auto-upgrade.nix2
-rw-r--r--nixos/modules/tasks/network-interfaces-systemd.nix10
-rw-r--r--nixos/modules/virtualisation/cri-o.nix106
-rw-r--r--nixos/release.nix6
-rw-r--r--nixos/tests/all-tests.nix4
-rw-r--r--nixos/tests/glib-networking.nix17
-rw-r--r--nixos/tests/hardened.nix1
-rwxr-xr-xnixos/tests/hydra/create-trivial-project.sh2
-rw-r--r--nixos/tests/hydra/default.nix23
-rw-r--r--nixos/tests/libgdata.nix21
-rw-r--r--nixos/tests/login.nix1
-rw-r--r--nixos/tests/minidlna.nix39
-rw-r--r--nixos/tests/mumble.nix4
-rw-r--r--nixos/tests/os-prober.nix119
-rw-r--r--nixos/tests/plasma5.nix1
-rw-r--r--nixos/tests/prometheus-exporters.nix16
-rw-r--r--nixos/tests/wordpress.nix11
-rw-r--r--nixos/tests/xfce.nix4
-rw-r--r--nixos/tests/xfce4-14.nix4
-rw-r--r--nixos/tests/xmonad.nix2
97 files changed, 1225 insertions, 297 deletions
diff --git a/nixos/doc/manual/configuration/x-windows.xml b/nixos/doc/manual/configuration/x-windows.xml
index 7cdc5196e0d2..f6f659b02afa 100644
--- a/nixos/doc/manual/configuration/x-windows.xml
+++ b/nixos/doc/manual/configuration/x-windows.xml
@@ -280,6 +280,12 @@ xkb_symbols "media"
 <xref linkend="opt-services.xserver.displayManager.sessionCommands"/> = "setxkbmap -keycodes media";
 </programlisting>
   <para>
+    If you are manually starting the X server, you should set the argument
+    <literal>-xkbdir /etc/X11/xkb</literal>, otherwise X won't find your layout files.
+    For example with <command>xinit</command> run
+    <screen><prompt>$ </prompt>xinit -- -xkbdir /etc/X11/xkb</screen>
+  </para>
+  <para>
    To learn how to write layouts take a look at the XKB
   <link xlink:href="https://www.x.org/releases/current/doc/xorg-docs/input/XKB-Enhancing.html#Defining_New_Layouts">
    documentation
diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml
index 9cea2db610e0..f1e1568c0349 100644
--- a/nixos/doc/manual/installation/installing.xml
+++ b/nixos/doc/manual/installation/installing.xml
@@ -392,7 +392,11 @@
      <filename>hardware-configuration.nix</filename> is included from
      <filename>configuration.nix</filename> and will be overwritten by future
      invocations of <command>nixos-generate-config</command>; thus, you
-     generally should not modify it.)
+     generally should not modify it.) Additionally, you may want to look at 
+     <link xlink:href="https://github.com/NixOS/nixos-hardware">Hardware
+     configuration for known-hardware</link> at this point or after
+     installation.
+      
     </para>
     <note>
      <para>
diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml
index 4c20cfcdd7d2..a83c4fb965eb 100644
--- a/nixos/doc/manual/man-nixos-rebuild.xml
+++ b/nixos/doc/manual/man-nixos-rebuild.xml
@@ -7,10 +7,12 @@
   <refmiscinfo class="source">NixOS</refmiscinfo>
 <!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
  </refmeta>
+
  <refnamediv>
   <refname><command>nixos-rebuild</command>
   </refname><refpurpose>reconfigure a NixOS machine</refpurpose>
  </refnamediv>
+
  <refsynopsisdiv>
   <cmdsynopsis>
    <command>nixos-rebuild</command><group choice='req'>
@@ -74,6 +76,7 @@
    <arg>
     <option>--builders</option> <replaceable>builder-spec</replaceable>
    </arg>
+
    <sbr />
    <arg>
     <group choice='req'>
@@ -121,8 +124,10 @@
    </arg>
   </cmdsynopsis>
  </refsynopsisdiv>
+
  <refsection>
   <title>Description</title>
+
   <para>
    This command updates the system so that it corresponds to the configuration
    specified in <filename>/etc/nixos/configuration.nix</filename>. Thus, every
@@ -133,9 +138,11 @@
    (re)starts any system services if needed. Please note that user services need
    to be started manually as they aren't detected by the activation script at the moment.
   </para>
+
   <para>
    This command has one required argument, which specifies the desired
    operation. It must be one of the following:
+
    <variablelist>
     <varlistentry>
      <term>
@@ -152,6 +159,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>boot</option>
@@ -165,6 +173,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>test</option>
@@ -179,6 +188,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>build</option>
@@ -197,6 +207,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>dry-build</option>
@@ -208,6 +219,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>dry-activate</option>
@@ -222,6 +234,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>edit</option>
@@ -232,6 +245,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>build-vm</option>
@@ -249,12 +263,14 @@
 <prompt>$ </prompt>./result/bin/run-*-vm
 </screen>
       </para>
+
       <para>
        The VM is implemented using the <literal>qemu</literal> package. For
        best performance, you should load the <literal>kvm-intel</literal> or
        <literal>kvm-amd</literal> kernel modules to get hardware
        virtualisation.
       </para>
+
       <para>
        The VM mounts the Nix store of the host through the 9P file system. The
        host Nix store is read-only, so Nix commands that modify the Nix store
@@ -262,6 +278,7 @@
        <command>nixos-rebuild</command>; to change the VM’s configuration,
        you must halt the VM and re-run the commands above.
       </para>
+
       <para>
        The VM has its own <literal>ext3</literal> root file system, which is
        automatically created when the VM is first started, and is persistent
@@ -272,6 +289,7 @@
       </para>
      </listitem>
     </varlistentry>
+
     <varlistentry>
      <term>
       <option>build-vm-with-bootloader</option>
@@ -294,11 +312,13 @@
    </variablelist>
   </para>
  </refsection>
+
  <refsection>
   <title>Options</title>
   <para>
    This command accepts the following options:
   </para>
+
   <variablelist>
    <varlistentry>
     <term>
@@ -310,6 +330,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--install-bootloader</option>
@@ -321,6 +342,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--no-build-nix</option>
@@ -336,6 +358,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--fast</option>
@@ -349,6 +372,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--rollback</option>
@@ -363,6 +387,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--builders</option> <replaceable>builder-spec</replaceable>
@@ -382,6 +407,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--profile-name</option>
@@ -412,6 +438,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--build-host</option>
@@ -437,6 +464,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <option>--target-host</option>
@@ -449,6 +477,7 @@
       be accessible over ssh, and for the commands <option>switch</option>,
       <option>boot</option> and <option>test</option> you need root access.
      </para>
+
      <para>
       If <option>--build-host</option> is not explicitly specified,
       <option>--build-host</option> will implicitly be set to the same value as
@@ -457,6 +486,7 @@
       place remotely (and no build artifacts will be copied to the local
       machine).
      </para>
+
      <para>
       You can include a remote user name in the host name
       (<replaceable>user@host</replaceable>). You can also set ssh options by
@@ -465,6 +495,7 @@
     </listitem>
    </varlistentry>
   </variablelist>
+
   <para>
    In addition, <command>nixos-rebuild</command> accepts various Nix-related
    flags, including <option>--max-jobs</option> / <option>-j</option>,
@@ -473,8 +504,10 @@
    <option>-v</option>. See the Nix manual for details.
   </para>
  </refsection>
+
  <refsection>
   <title>Environment</title>
+
   <variablelist>
    <varlistentry>
     <term>
@@ -487,6 +520,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <envar>NIX_SSHOPTS</envar>
@@ -500,9 +534,12 @@
    </varlistentry>
   </variablelist>
  </refsection>
+
  <refsection>
   <title>Files</title>
+
   <variablelist>
+
    <varlistentry>
     <term>
      <filename>/run/current-system</filename>
@@ -513,6 +550,7 @@
      </para>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term>
      <filename>/nix/var/nix/profiles/system</filename>
@@ -524,8 +562,10 @@
      </para>
     </listitem>
    </varlistentry>
+
   </variablelist>
  </refsection>
+
  <refsection>
   <title>Bugs</title>
   <para>
diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml
index 02b591477214..444862c5739b 100644
--- a/nixos/doc/manual/release-notes/release-notes.xml
+++ b/nixos/doc/manual/release-notes/release-notes.xml
@@ -8,6 +8,7 @@
   This section lists the release notes for each stable version of NixOS and
   current unstable revision.
  </para>
+ <xi:include href="rl-2003.xml" />
  <xi:include href="rl-1909.xml" />
  <xi:include href="rl-1903.xml" />
  <xi:include href="rl-1809.xml" />
diff --git a/nixos/doc/manual/release-notes/rl-1909.xml b/nixos/doc/manual/release-notes/rl-1909.xml
index db4629443002..58ab7207f533 100644
--- a/nixos/doc/manual/release-notes/rl-1909.xml
+++ b/nixos/doc/manual/release-notes/rl-1909.xml
@@ -449,8 +449,9 @@
    </listitem>
    <listitem>
      <para>
-       <option>services.xserver.desktopManager.xterm</option> is now disabled by default.
-       It was not useful except for debugging purposes and was confusingly set as default in some circumstances.
+       <option>services.xserver.desktopManager.xterm</option> is now disabled by default if <literal>stateVersion</literal> is 19.09 or higher.
+       Previously the xterm desktopManager was enabled when xserver was enabled, but it isn't useful for all people so it didn't make sense to
+       have any desktopManager enabled default.
      </para>
    </listitem>
    <listitem>
@@ -477,6 +478,12 @@
      Prometheus 2 is now configured with <literal>services.prometheus</literal>.
     </para>
    </listitem>
+   <listitem>
+     <para>
+       Citrix Receiver (<literal>citrix_receiver</literal>) has been dropped in favor of Citrix Workspace
+       (<literal>citrix_workspace</literal>).
+     </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/doc/manual/release-notes/rl-2003.xml b/nixos/doc/manual/release-notes/rl-2003.xml
new file mode 100644
index 000000000000..c84bc8dbb379
--- /dev/null
+++ b/nixos/doc/manual/release-notes/rl-2003.xml
@@ -0,0 +1,80 @@
+<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-release-20.03">
+ <title>Release 20.03 (“Markhor”, 2020.03/??)</title>
+
+ <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-release-20.03-highlights">
+  <title>Highlights</title>
+
+  <para>
+   In addition to numerous new and upgraded packages, this release has the
+   following highlights:
+  </para>
+
+  <itemizedlist>
+   <listitem>
+    <para>
+     Support is planned until the end of October 2020, handing over to 20.09.
+    </para>
+   </listitem>
+  </itemizedlist>
+ </section>
+
+ <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-release-20.03-new-services">
+  <title>New Services</title>
+
+  <para>
+   The following new services were added since the last release:
+  </para>
+
+  <itemizedlist>
+   <listitem>
+    <para />
+   </listitem>
+  </itemizedlist>
+
+ </section>
+
+ <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-release-20.03-incompatibilities">
+  <title>Backward Incompatibilities</title>
+
+  <para>
+   When upgrading from a previous release, please be aware of the following
+   incompatible changes:
+  </para>
+
+  <itemizedlist>
+   <listitem>
+    <para />
+   </listitem>
+  </itemizedlist>
+ </section>
+
+ <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-release-20.03-notable-changes">
+  <title>Other Notable Changes</title>
+
+  <itemizedlist>
+   <listitem>
+    <para />
+   </listitem>
+  </itemizedlist>
+ </section>
+</section>
diff --git a/nixos/doc/xmlformat.conf b/nixos/doc/xmlformat.conf
index 4a565c8465bc..c3f39c7fd81b 100644
--- a/nixos/doc/xmlformat.conf
+++ b/nixos/doc/xmlformat.conf
@@ -37,7 +37,6 @@ para abstract
   entry-break  1
   exit-break   1
   normalize    yes
-  wrap-length  79
 
 title
   format       block
diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
index bcb86f11ead7..8f227c423266 100644
--- a/nixos/modules/config/fonts/fontconfig.nix
+++ b/nixos/modules/config/fonts/fontconfig.nix
@@ -51,8 +51,8 @@ let
                   then "fontconfig"
                   else "fontconfig_${version}";
       makeCache = fontconfig: pkgs.makeFontsCache { inherit fontconfig; fontDirectories = config.fonts.fonts; };
-      cache     = makeCache pkgs."${fcPackage}";
-      cache32   = makeCache pkgs.pkgsi686Linux."${fcPackage}";
+      cache     = makeCache pkgs.${fcPackage};
+      cache32   = makeCache pkgs.pkgsi686Linux.${fcPackage};
     in
     pkgs.writeText "fc-00-nixos-cache.conf" ''
       <?xml version='1.0'?>
diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix
index 9dfc1add8299..d939cbb393ee 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -157,6 +157,8 @@ in
     # terminal instead of logging out of X11).
     environment.variables = config.environment.sessionVariables;
 
+    environment.profileRelativeEnvVars = config.environment.profileRelativeSessionVariables;
+
     environment.shellAliases = mapAttrs (name: mkDefault) {
       ls = "ls --color=tty";
       ll = "ls -l";
diff --git a/nixos/modules/config/system-environment.nix b/nixos/modules/config/system-environment.nix
index 6011e354ece4..792d1dbb38f6 100644
--- a/nixos/modules/config/system-environment.nix
+++ b/nixos/modules/config/system-environment.nix
@@ -8,6 +8,11 @@ let
 
   cfg = config.environment;
 
+  pamProfiles =
+    map
+      (replaceStrings ["$HOME" "$USER"] ["@{HOME}" "@{PAM_USER}"])
+      cfg.profiles;
+
 in
 
 {
@@ -18,25 +23,76 @@ in
       default = {};
       description = ''
         A set of environment variables used in the global environment.
-        These variables will be set by PAM.
-        The value of each variable can be either a string or a list of
-        strings.  The latter is concatenated, interspersed with colon
-        characters.
+        These variables will be set by PAM early in the login process.
+
+        The value of each session variable can be either a string or a
+        list of strings. The latter is concatenated, interspersed with
+        colon characters.
+
+        Note, due to limitations in the PAM format values may not
+        contain the <literal>"</literal> character.
+
+        Also, these variables are merged into
+        <xref linkend="opt-environment.variables"/> and it is
+        therefore not possible to use PAM style variables such as
+        <code>@{HOME}</code>.
       '';
       type = with types; attrsOf (either str (listOf str));
       apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
     };
 
+    environment.profileRelativeSessionVariables = mkOption {
+      type = types.attrsOf (types.listOf types.str);
+      example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; };
+      description = ''
+        Attribute set of environment variable used in the global
+        environment. These variables will be set by PAM early in the
+        login process.
+
+        Variable substitution is available as described in
+        <citerefentry>
+          <refentrytitle>pam_env.conf</refentrytitle>
+          <manvolnum>5</manvolnum>
+        </citerefentry>.
+
+        Each attribute maps to a list of relative paths. Each relative
+        path is appended to the each profile of
+        <option>environment.profiles</option> to form the content of
+        the corresponding environment variable.
+
+        Also, these variables are merged into
+        <xref linkend="opt-environment.profileRelativeEnvVars"/> and it is
+        therefore not possible to use PAM style variables such as
+        <code>@{HOME}</code>.
+      '';
+    };
+
   };
 
   config = {
 
-    system.build.pamEnvironment = pkgs.writeText "pam-environment"
-       ''
-         ${concatStringsSep "\n" (
-           (mapAttrsToList (n: v: ''${n}="${concatStringsSep ":" v}"'')
-             (zipAttrsWith (const concatLists) ([ (mapAttrs (n: v: [ v ]) cfg.sessionVariables) ]))))}
-       '';
+    system.build.pamEnvironment =
+      let
+        suffixedVariables =
+          flip mapAttrs cfg.profileRelativeSessionVariables (envVar: suffixes:
+            flip concatMap pamProfiles (profile:
+              map (suffix: "${profile}${suffix}") suffixes
+            )
+          );
+
+        pamVariable = n: v:
+          ''${n}   DEFAULT="${concatStringsSep ":" (toList v)}"'';
+
+        pamVariables =
+          concatStringsSep "\n"
+          (mapAttrsToList pamVariable
+          (zipAttrsWith (n: concatLists)
+            [
+              (mapAttrs (n: toList) cfg.sessionVariables)
+              suffixedVariables
+            ]));
+      in
+        pkgs.writeText "pam-environment" "${pamVariables}\n";
 
   };
 
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index fae2fc740082..aba9bc0945b1 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -135,6 +135,9 @@ in
       # outputs TODO: note that the tools will often not be linked by default
       postBuild =
         ''
+          # Remove wrapped binaries, they shouldn't be accessible via PATH.
+          find $out/bin -maxdepth 1 -name ".*-wrapped" -type l -delete
+
           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/config/terminfo.nix b/nixos/modules/config/terminfo.nix
index b86ce2dbf057..1396640af672 100644
--- a/nixos/modules/config/terminfo.nix
+++ b/nixos/modules/config/terminfo.nix
@@ -12,7 +12,7 @@
       source = "${config.system.path}/share/terminfo";
     };
 
-    environment.profileRelativeEnvVars = {
+    environment.profileRelativeSessionVariables = {
       TERMINFO_DIRS = [ "/share/terminfo" ];
     };
 
diff --git a/nixos/modules/config/xdg/icons.nix b/nixos/modules/config/xdg/icons.nix
index 8268a3771a0e..4677ce090b0b 100644
--- a/nixos/modules/config/xdg/icons.nix
+++ b/nixos/modules/config/xdg/icons.nix
@@ -7,21 +7,32 @@ with lib;
       type = types.bool;
       default = true;
       description = ''
-        Whether to install files to support the 
+        Whether to install files to support the
         <link xlink:href="https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html">XDG Icon Theme specification</link>.
       '';
     };
   };
 
   config = mkIf config.xdg.icons.enable {
-    environment.pathsToLink = [ 
-      "/share/icons" 
-      "/share/pixmaps" 
+    environment.pathsToLink = [
+      "/share/icons"
+      "/share/pixmaps"
+    ];
+
+    # libXcursor looks for cursors in XCURSOR_PATH
+    # it mostly follows the spec for icons
+    # See: https://www.x.org/releases/current/doc/man/man3/Xcursor.3.xhtml Themes
+
+    # These are preferred so they come first in the list
+    environment.sessionVariables.XCURSOR_PATH = [
+      "$HOME/.icons"
+      "$HOME/.local/share/icons"
+    ];
+
+    environment.profileRelativeSessionVariables.XCURSOR_PATH = [
+      "/share/icons"
+      "/share/pixmaps"
     ];
-    
-    environment.profileRelativeEnvVars = {
-      XCURSOR_PATH = [ "/share/icons" ];
-    };
   };
 
 }
diff --git a/nixos/modules/hardware/brightnessctl.nix b/nixos/modules/hardware/brightnessctl.nix
index 341e4b791c23..2d54398d10df 100644
--- a/nixos/modules/hardware/brightnessctl.nix
+++ b/nixos/modules/hardware/brightnessctl.nix
@@ -25,6 +25,7 @@ in
 
   config = mkIf cfg.enable {
     services.udev.packages = with pkgs; [ brightnessctl ];
+    environment.systemPackages = with pkgs; [ brightnessctl ];
   };
 
 }
diff --git a/nixos/modules/hardware/printers.nix b/nixos/modules/hardware/printers.nix
index 12ee5516d4ed..56b91933477d 100644
--- a/nixos/modules/hardware/printers.nix
+++ b/nixos/modules/hardware/printers.nix
@@ -94,8 +94,8 @@ in {
             ppdOptions = mkOption {
               type = types.attrsOf types.str;
               example = {
-                "PageSize" = "A4";
-                "Duplex" = "DuplexNoTumble";
+                PageSize = "A4";
+                Duplex = "DuplexNoTumble";
               };
               default = {};
               description = ''
@@ -110,7 +110,7 @@ in {
   };
 
   config = mkIf (cfg.ensurePrinters != [] && config.services.printing.enable) {
-    systemd.services."ensure-printers" = let
+    systemd.services.ensure-printers = let
       cupsUnit = if config.services.printing.startWhenNeeded then "cups.socket" else "cups.service";
     in {
       description = "Ensure NixOS-configured CUPS printers";
diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix
index 0a0150441554..a2a8e8ef7522 100644
--- a/nixos/modules/installer/cd-dvd/sd-image.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image.nix
@@ -174,8 +174,10 @@ in
     boot.postBootCommands = ''
       # On the first boot do some maintenance tasks
       if [ -f /nix-path-registration ]; then
+        set -euo pipefail
+        set -x
         # Figure out device names for the boot device and root filesystem.
-        rootPart=$(readlink -f /dev/disk/by-label/NIXOS_SD)
+        rootPart=$(${pkgs.utillinux}/bin/findmnt -n -o SOURCE /)
         bootDevice=$(lsblk -npo PKNAME $rootPart)
 
         # Resize the root partition and the filesystem to fit the disk
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 5b7f391ed5a5..775cc05aa0a9 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -567,7 +567,6 @@
   ./services/networking/bird.nix
   ./services/networking/bitlbee.nix
   ./services/networking/charybdis.nix
-  ./services/networking/chrony.nix
   ./services/networking/cjdns.nix
   ./services/networking/cntlm.nix
   ./services/networking/connman.nix
@@ -650,14 +649,15 @@
   ./services/networking/nntp-proxy.nix
   ./services/networking/nsd.nix
   ./services/networking/ntopng.nix
-  ./services/networking/ntpd.nix
+  ./services/networking/ntp/chrony.nix
+  ./services/networking/ntp/ntpd.nix
+  ./services/networking/ntp/openntpd.nix
   ./services/networking/nullidentdmod.nix
   ./services/networking/nylon.nix
   ./services/networking/ocserv.nix
   ./services/networking/ofono.nix
   ./services/networking/oidentd.nix
   ./services/networking/openfire.nix
-  ./services/networking/openntpd.nix
   ./services/networking/openvpn.nix
   ./services/networking/ostinato.nix
   ./services/networking/owamp.nix
@@ -938,6 +938,7 @@
   ./virtualisation/anbox.nix
   ./virtualisation/container-config.nix
   ./virtualisation/containers.nix
+  ./virtualisation/cri-o.nix
   ./virtualisation/docker.nix
   ./virtualisation/docker-containers.nix
   ./virtualisation/ecs-agent.nix
diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix
index 66eb83482664..fcffb2134980 100644
--- a/nixos/modules/programs/environment.nix
+++ b/nixos/modules/programs/environment.nix
@@ -20,8 +20,9 @@ in
       { NIXPKGS_CONFIG = "/etc/nix/nixpkgs-config.nix";
         PAGER = mkDefault "less -R";
         EDITOR = mkDefault "nano";
-        XCURSOR_PATH = [ "$HOME/.icons" ];
         XDG_CONFIG_DIRS = [ "/etc/xdg" ]; # needs to be before profile-relative paths to allow changes through environment.etc
+        GTK_DATA_PREFIX = "${config.system.path}"; # needed for gtk2 apps to find themes
+        GTK_EXE_PREFIX = "${config.system.path}";
       };
 
     environment.profiles = mkAfter
@@ -30,7 +31,7 @@ in
       ];
 
     # TODO: move most of these elsewhere
-    environment.profileRelativeEnvVars =
+    environment.profileRelativeSessionVariables =
       { PATH = [ "/bin" ];
         INFOPATH = [ "/info" "/share/info" ];
         KDEDIRS = [ "" ];
diff --git a/nixos/modules/programs/mtr.nix b/nixos/modules/programs/mtr.nix
index 1fdec4c04f68..75b710c1584f 100644
--- a/nixos/modules/programs/mtr.nix
+++ b/nixos/modules/programs/mtr.nix
@@ -4,6 +4,7 @@ with lib;
 
 let
   cfg = config.programs.mtr;
+
 in {
   options = {
     programs.mtr = {
@@ -15,13 +16,22 @@ in {
           setcap wrapper for it.
         '';
       };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.mtr;
+        description = ''
+          The package to use.
+        '';
+      };
     };
   };
 
   config = mkIf cfg.enable {
-    environment.systemPackages = with pkgs; [ mtr ];
+    environment.systemPackages = with pkgs; [ cfg.package ];
+
     security.wrappers.mtr-packet = {
-      source = "${pkgs.mtr}/bin/mtr-packet";
+      source = "${cfg.package}/bin/mtr-packet";
       capabilities = "cap_net_raw+p";
     };
   };
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index b4f03151cdc1..f92d09a7ef44 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -55,7 +55,7 @@ in {
     extraPackages = mkOption {
       type = with types; listOf package;
       default = with pkgs; [
-        swaylock swayidle
+        swaylock swayidle swaybg
         xwayland rxvt_unicode dmenu
       ];
       defaultText = literalExample ''
diff --git a/nixos/modules/programs/x2goserver.nix b/nixos/modules/programs/x2goserver.nix
index d9e7b6e4a5c0..77a1a0da7993 100644
--- a/nixos/modules/programs/x2goserver.nix
+++ b/nixos/modules/programs/x2goserver.nix
@@ -6,7 +6,7 @@ let
   cfg = config.programs.x2goserver;
 
   defaults = {
-    superenicer = { "enable" = cfg.superenicer.enable; };
+    superenicer = { enable = cfg.superenicer.enable; };
   };
   confText = generators.toINI {} (recursiveUpdate defaults cfg.settings);
   x2goServerConf = pkgs.writeText "x2goserver.conf" confText;
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index d1303f90ad8d..0c7c45a4708b 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -273,20 +273,6 @@ with lib;
     (mkRenamedOptionModule [ "networking" "extraResolvconfConf" ] [ "networking" "resolvconf" "extraConfig" ])
     (mkRenamedOptionModule [ "networking" "resolvconfOptions" ] [ "networking" "resolvconf" "extraOptions" ])
 
-    # Redshift
-    (mkChangedOptionModule [ "services" "redshift" "latitude" ] [ "location" "latitude" ]
-      (config:
-        let value = getAttrFromPath [ "services" "redshift" "latitude" ] config;
-        in if value == null then
-          throw "services.redshift.latitude is set to null, you can remove this"
-          else builtins.fromJSON value))
-    (mkChangedOptionModule [ "services" "redshift" "longitude" ] [ "location" "longitude" ]
-      (config:
-        let value = getAttrFromPath [ "services" "redshift" "longitude" ] config;
-        in if value == null then
-          throw "services.redshift.longitude is set to null, you can remove this"
-          else builtins.fromJSON value))
-
     # Redis
     (mkRemovedOptionModule [ "services" "redis" "user" ] "The redis module now is hardcoded to the redis user.")
     (mkRemovedOptionModule [ "services" "redis" "dbpath" ] "The redis module now uses /var/lib/redis as data directory.")
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 9c7ddc2f4eea..a3eb12b06940 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -415,7 +415,7 @@ let
 
           # Session management.
           ${optionalString cfg.setEnvironment ''
-            session required pam_env.so envfile=${config.system.build.pamEnvironment}
+            session required pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
           ''}
           session required pam_unix.so
           ${optionalString cfg.setLoginUid
@@ -742,13 +742,6 @@ in
     environment.etc =
       mapAttrsToList (n: v: makePAMService v) config.security.pam.services;
 
-    systemd.tmpfiles.rules = optionals
-      (any (s: s.updateWtmp) (attrValues config.security.pam.services))
-      [
-        "f /var/log/wtmp"
-        "f /var/log/lastlog"
-      ];
-
     security.pam.services =
       { other.text =
           ''
diff --git a/nixos/modules/services/audio/roon-server.nix b/nixos/modules/services/audio/roon-server.nix
index d4b0b098b78e..4eda3c5708da 100644
--- a/nixos/modules/services/audio/roon-server.nix
+++ b/nixos/modules/services/audio/roon-server.nix
@@ -61,8 +61,8 @@ in {
     };
 
     
-    users.groups."${cfg.group}" = {};
-    users.users."${cfg.user}" =
+    users.groups.${cfg.group} = {};
+    users.users.${cfg.user} =
       if cfg.user == "roon-server" then {
         isSystemUser = true;
         description = "Roon Server user";
diff --git a/nixos/modules/services/audio/spotifyd.nix b/nixos/modules/services/audio/spotifyd.nix
index e3556b2559c2..4b74e7532795 100644
--- a/nixos/modules/services/audio/spotifyd.nix
+++ b/nixos/modules/services/audio/spotifyd.nix
@@ -28,7 +28,7 @@ in
       after = [ "network-online.target" "sound.target" ];
       description = "spotifyd, a Spotify playing daemon";
       serviceConfig = {
-        ExecStart = "${pkgs.spotifyd}/bin/spotifyd --no-daemon --cache_path /var/cache/spotifyd --config ${spotifydConf}";
+        ExecStart = "${pkgs.spotifyd}/bin/spotifyd --no-daemon --cache-path /var/cache/spotifyd --config-path ${spotifydConf}";
         Restart = "always";
         RestartSec = 12;
         DynamicUser = true;
diff --git a/nixos/modules/services/cluster/kubernetes/flannel.nix b/nixos/modules/services/cluster/kubernetes/flannel.nix
index 74d10d684375..d799e638fc94 100644
--- a/nixos/modules/services/cluster/kubernetes/flannel.nix
+++ b/nixos/modules/services/cluster/kubernetes/flannel.nix
@@ -47,7 +47,7 @@ in
       }];
     };
 
-    systemd.services."mk-docker-opts" = {
+    systemd.services.mk-docker-opts = {
       description = "Pre-Docker Actions";
       path = with pkgs; [ gawk gnugrep ];
       script = ''
@@ -57,7 +57,7 @@ in
       serviceConfig.Type = "oneshot";
     };
 
-    systemd.paths."flannel-subnet-env" = {
+    systemd.paths.flannel-subnet-env = {
       wantedBy = [ "flannel.service" ];
       pathConfig = {
         PathModified = "/run/flannel/subnet.env";
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index 500acb485620..2da10a9a5e2a 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -275,6 +275,7 @@ in
               ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createdb -O hydra hydra
               touch ${baseDir}/.db-created
             fi
+            echo "create extension if not exists pg_trgm" | ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} -- ${config.services.postgresql.package}/bin/psql hydra
           ''}
 
           if [ ! -e ${cfg.gcRootsDir} ]; then
@@ -379,6 +380,23 @@ in
           };
       };
 
+    systemd.services.hydra-notify =
+      { wantedBy = [ "multi-user.target" ];
+        requires = [ "hydra-init.service" ];
+        after = [ "hydra-init.service" ];
+        restartTriggers = [ hydraConf ];
+        environment = env // {
+          PGPASSFILE = "${baseDir}/pgpass-queue-runner";
+        };
+        serviceConfig =
+          { ExecStart = "@${cfg.package}/bin/hydra-notify hydra-notify";
+            # FIXME: run this under a less privileged user?
+            User = "hydra-queue-runner";
+            Restart = "always";
+            RestartSec = 5;
+          };
+      };
+
     # If there is less than a certain amount of free disk space, stop
     # the queue/evaluator to prevent builds from failing or aborting.
     systemd.services.hydra-check-space =
@@ -416,6 +434,8 @@ in
         hydra-users hydra-queue-runner hydra
         hydra-users hydra-www hydra
         hydra-users root hydra
+        # The postgres user is used to create the pg_trgm extension for the hydra database
+        hydra-users postgres postgres
       '';
 
     services.postgresql.authentication = optionalString haveLocalDB
diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix
index ec6a36413fe7..0ec906713885 100644
--- a/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -193,7 +193,7 @@ in {
               then ""
               else
                 let pluginCmds = lib.attrsets.mapAttrsToList
-                      (n: v: "cp ${v} ${cfg.home}/plugins/${n}.hpi")
+                      (n: v: "cp ${v} ${cfg.home}/plugins/${n}.jpi")
                       cfg.plugins;
                 in ''
                   rm -r ${cfg.home}/plugins || true
diff --git a/nixos/modules/services/editors/emacs.nix b/nixos/modules/services/editors/emacs.nix
index ba7ec967919e..d791b387665f 100644
--- a/nixos/modules/services/editors/emacs.nix
+++ b/nixos/modules/services/editors/emacs.nix
@@ -95,13 +95,7 @@ in {
 
     environment.systemPackages = [ cfg.package editorScript desktopApplicationFile ];
 
-    environment.variables = {
-      # This is required so that GTK applications launched from Emacs
-      # get properly themed:
-      GTK_DATA_PREFIX = "${config.system.path}";
-    } // (if cfg.defaultEditor then {
-        EDITOR = mkOverride 900 "${editorScript}/bin/emacseditor";
-      } else {});
+    environment.variables.EDITOR = mkIf cfg.defaultEditor (mkOverride 900 "${editorScript}/bin/emacseditor");
   };
 
   meta.doc = ./emacs.xml;
diff --git a/nixos/modules/services/mail/mailcatcher.nix b/nixos/modules/services/mail/mailcatcher.nix
index fa8d41e918d3..f5b4508b335c 100644
--- a/nixos/modules/services/mail/mailcatcher.nix
+++ b/nixos/modules/services/mail/mailcatcher.nix
@@ -3,7 +3,7 @@
 let
   cfg = config.services.mailcatcher;
 
-  inherit (lib) mkEnableOption mkIf mkOption types;
+  inherit (lib) mkEnableOption mkIf mkOption types optionalString;
 in
 {
   # interface
@@ -54,6 +54,7 @@ in
         DynamicUser = true;
         Restart = "always";
         ExecStart = "${pkgs.mailcatcher}/bin/mailcatcher --foreground --no-quit --http-ip ${cfg.http.ip} --http-port ${toString cfg.http.port} --smtp-ip ${cfg.smtp.ip} --smtp-port ${toString cfg.smtp.port}";
+        AmbientCapabilities = optionalString (cfg.http.port < 1024 || cfg.smtp.port < 1024) "cap_net_bind_service";
       };
     };
   };
diff --git a/nixos/modules/services/mail/mailman.nix b/nixos/modules/services/mail/mailman.nix
index 11dd5cb48db0..e917209f3d1f 100644
--- a/nixos/modules/services/mail/mailman.nix
+++ b/nixos/modules/services/mail/mailman.nix
@@ -6,16 +6,35 @@ let
 
   cfg = config.services.mailman;
 
-  pythonEnv = pkgs.python3.withPackages (ps: [ps.mailman]);
+  mailmanPyEnv = pkgs.python3.withPackages (ps: with ps; [mailman mailman-hyperkitty]);
 
   mailmanExe = with pkgs; stdenv.mkDerivation {
     name = "mailman-" + python3Packages.mailman.version;
+    buildInputs = [makeWrapper];
     unpackPhase = ":";
     installPhase = ''
       mkdir -p $out/bin
-      sed >"$out/bin/mailman" <"${pythonEnv}/bin/mailman" \
-        -e "2 iexport MAILMAN_CONFIG_FILE=/etc/mailman.cfg"
-      chmod +x $out/bin/mailman
+      makeWrapper ${mailmanPyEnv}/bin/mailman $out/bin/mailman \
+        --set MAILMAN_CONFIG_FILE /etc/mailman.cfg
+   '';
+  };
+
+  mailmanWeb = pkgs.python3Packages.mailman-web.override {
+    serverEMail = cfg.siteOwner;
+    archiverKey = cfg.hyperkittyApiKey;
+    allowedHosts = cfg.webHosts;
+  };
+
+  mailmanWebPyEnv = pkgs.python3.withPackages (x: with x; [mailman-web]);
+
+  mailmanWebExe = with pkgs; stdenv.mkDerivation {
+    inherit (mailmanWeb) name;
+    buildInputs = [makeWrapper];
+    unpackPhase = ":";
+    installPhase = ''
+      mkdir -p $out/bin
+      makeWrapper ${mailmanWebPyEnv}/bin/django-admin $out/bin/mailman-web \
+        --set DJANGO_SETTINGS_MODULE settings
     '';
   };
 
@@ -28,11 +47,30 @@ let
     bin_dir: ${pkgs.python3Packages.mailman}/bin
     var_dir: /var/lib/mailman
     queue_dir: $var_dir/queue
+    template_dir: $var_dir/templates
     log_dir: $var_dir/log
     lock_dir: $var_dir/lock
     etc_dir: /etc
     ext_dir: $etc_dir/mailman.d
     pid_file: /run/mailman/master.pid
+  '' + optionalString (cfg.hyperkittyApiKey != null) ''
+    [archiver.hyperkitty]
+    class: mailman_hyperkitty.Archiver
+    enable: yes
+    configuration: ${pkgs.writeText "mailman-hyperkitty.cfg" mailmanHyperkittyCfg}
+  '';
+
+  mailmanHyperkittyCfg = ''
+    [general]
+    # This is your HyperKitty installation, preferably on the localhost. This
+    # address will be used by Mailman to forward incoming emails to HyperKitty
+    # for archiving. It does not need to be publicly available, in fact it's
+    # better if it is not.
+    base_url: ${cfg.hyperkittyBaseUrl}
+
+    # Shared API key, must be the identical to the value in HyperKitty's
+    # settings.
+    api_key: ${cfg.hyperkittyApiKey}
   '';
 
 in {
@@ -51,7 +89,7 @@ in {
 
       siteOwner = mkOption {
         type = types.str;
-        default = "postmaster";
+        default = "postmaster@example.org";
         description = ''
           Certain messages that must be delivered to a human, but which can't
           be delivered to a list owner (e.g. a bounce from a list owner), will
@@ -59,6 +97,48 @@ in {
         '';
       };
 
+      webRoot = mkOption {
+        type = types.path;
+        default = "${mailmanWeb}/${pkgs.python3.sitePackages}";
+        defaultText = "pkgs.python3Packages.mailman-web";
+        description = ''
+          The web root for the Hyperkity + Postorius apps provided by Mailman.
+          This variable can be set, of course, but it mainly exists so that site
+          admins can refer to it in their own hand-written httpd configuration files.
+        '';
+      };
+
+      webHosts = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          The list of hostnames and/or IP addresses from which the Mailman Web
+          UI will accept requests. By default, "localhost" and "127.0.0.1" are
+          enabled. All additional names under which your web server accepts
+          requests for the UI must be listed here or incoming requests will be
+          rejected.
+        '';
+      };
+
+      hyperkittyBaseUrl = mkOption {
+        type = types.str;
+        default = "http://localhost/hyperkitty/";
+        description = ''
+          Where can Mailman connect to Hyperkitty's internal API, preferably on
+          localhost?
+        '';
+      };
+
+      hyperkittyApiKey = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          The shared secret used to authenticate Mailman's internal
+          communication with Hyperkitty. Must be set to enable support for the
+          Hyperkitty archiver. Note that this secret is going to be visible to
+          all local users in the Nix store.
+        '';
+      };
 
     };
   };
@@ -71,25 +151,22 @@ in {
       { assertion = cfg.enable -> config.services.postfix.enable;
         message = "Mailman requires Postfix";
       }
-      { assertion = config.services.postfix.recipientDelimiter == "+";
-        message = "Postfix's recipientDelimiter must be set to '+'.";
-      }
     ];
 
     users.users.mailman = { description = "GNU Mailman"; isSystemUser = true; };
 
     environment = {
-      systemPackages = [ mailmanExe ];
+      systemPackages = [ mailmanExe mailmanWebExe pkgs.sassc ];
       etc."mailman.cfg".text = mailmanCfg;
     };
 
     services.postfix = {
       relayDomains = [ "hash:/var/lib/mailman/data/postfix_domains" ];
+      recipientDelimiter = "+";         # bake recipient addresses in mail envelopes via VERP
       config = {
         transport_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
         local_recipient_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
-        # Mailman uses recipient delimiters, so we don't need special handling.
-        owner_request_special = "no";
+        owner_request_special = "no";   # Mailman handles -owner addresses on its own
       };
     };
 
@@ -109,6 +186,112 @@ in {
       };
     };
 
+    systemd.services.mailman-web = {
+      description = "Init Postorius DB";
+      before = [ "httpd.service" ];
+      requiredBy = [ "httpd.service" ];
+      script = ''
+        ${mailmanWebExe}/bin/mailman-web migrate
+        rm -rf static
+        ${mailmanWebExe}/bin/mailman-web collectstatic
+        ${mailmanWebExe}/bin/mailman-web compress
+      '';
+      serviceConfig = {
+        User = config.services.httpd.user;
+        Type = "oneshot";
+        StateDirectory = "mailman-web";
+        StateDirectoryMode = "0700";
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
+    systemd.services.mailman-daily = {
+      description = "Trigger daily Mailman events";
+      startAt = "daily";
+      serviceConfig = {
+        ExecStart = "${mailmanExe}/bin/mailman digests --send";
+        User = "mailman";
+      };
+    };
+
+    systemd.services.hyperkitty = {
+      enable = cfg.hyperkittyApiKey != null;
+      description = "GNU Hyperkitty QCluster Process";
+      after = [ "network.target" ];
+      wantedBy = [ "mailman.service" "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = "${mailmanWebExe}/bin/mailman-web qcluster";
+        User = config.services.httpd.user;
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
+    systemd.services.hyperkitty-minutely = {
+      enable = cfg.hyperkittyApiKey != null;
+      description = "Trigger minutely Hyperkitty events";
+      startAt = "minutely";
+      serviceConfig = {
+        ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs minutely";
+        User = config.services.httpd.user;
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
+    systemd.services.hyperkitty-quarter-hourly = {
+      enable = cfg.hyperkittyApiKey != null;
+      description = "Trigger quarter-hourly Hyperkitty events";
+      startAt = "*:00/15";
+      serviceConfig = {
+        ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs quarter_hourly";
+        User = config.services.httpd.user;
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
+    systemd.services.hyperkitty-hourly = {
+      enable = cfg.hyperkittyApiKey != null;
+      description = "Trigger hourly Hyperkitty events";
+      startAt = "hourly";
+      serviceConfig = {
+        ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs hourly";
+        User = config.services.httpd.user;
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
+    systemd.services.hyperkitty-daily = {
+      enable = cfg.hyperkittyApiKey != null;
+      description = "Trigger daily Hyperkitty events";
+      startAt = "daily";
+      serviceConfig = {
+        ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs daily";
+        User = config.services.httpd.user;
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
+    systemd.services.hyperkitty-weekly = {
+      enable = cfg.hyperkittyApiKey != null;
+      description = "Trigger weekly Hyperkitty events";
+      startAt = "weekly";
+      serviceConfig = {
+        ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs weekly";
+        User = config.services.httpd.user;
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
+    systemd.services.hyperkitty-yearly = {
+      enable = cfg.hyperkittyApiKey != null;
+      description = "Trigger yearly Hyperkitty events";
+      startAt = "yearly";
+      serviceConfig = {
+        ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs yearly";
+        User = config.services.httpd.user;
+        WorkingDirectory = "/var/lib/mailman-web";
+      };
+    };
+
   };
 
 }
diff --git a/nixos/modules/services/mail/rss2email.nix b/nixos/modules/services/mail/rss2email.nix
index df454abc8267..c1e5964c4536 100644
--- a/nixos/modules/services/mail/rss2email.nix
+++ b/nixos/modules/services/mail/rss2email.nix
@@ -43,9 +43,8 @@ in {
           <literal>[DEFAULT]</literal> block along with the
           <literal>to</literal> parameter.
 
-          See
-          <literal>https://github.com/rss2email/rss2email/blob/master/r2e.1</literal>
-          for more information on which parameters are accepted.
+          See <literal>man r2e</literal> for more information on which
+          parameters are accepted.
         '';
       };
 
diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix
index 9402d5cd801c..33a6fb152641 100644
--- a/nixos/modules/services/misc/dysnomia.nix
+++ b/nixos/modules/services/misc/dysnomia.nix
@@ -151,6 +151,7 @@ in
       enableSubversionRepository = config.services.svnserve.enable;
       enableTomcatWebApplication = config.services.tomcat.enable;
       enableMongoDatabase = config.services.mongodb.enable;
+      enableInfluxDatabase = config.services.influxdb.enable;
     });
 
     dysnomia.properties = {
diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix
index 59c1c104b9b9..4992b13c9d4a 100644
--- a/nixos/modules/services/misc/gitea.nix
+++ b/nixos/modules/services/misc/gitea.nix
@@ -322,6 +322,7 @@ in
       "d '${cfg.stateDir}/conf' - ${cfg.user} gitea - -"
       "d '${cfg.stateDir}/custom' - ${cfg.user} gitea - -"
       "d '${cfg.stateDir}/custom/conf' - ${cfg.user} gitea - -"
+      "d '${cfg.stateDir}/log' - ${cfg.user} gitea - -"
       "d '${cfg.repositoryRoot}' - ${cfg.user} gitea - -"
       "Z '${cfg.stateDir}' - ${cfg.user} gitea - -"
 
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index caef4ad4ea80..1e1eb0fd9a11 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -1,7 +1,5 @@
 { config, lib, pkgs, utils, ... }:
 
-# TODO: support non-postgresql
-
 with lib;
 
 let
@@ -675,6 +673,10 @@ in {
         openssh
         nodejs
         gnupg
+
+        # Needed for GitLab project imports
+        gnutar
+        gzip
       ];
       serviceConfig = {
         Type = "simple";
@@ -806,8 +808,8 @@ in {
           export otp="$(<'${cfg.secrets.otpFile}')"
           export jws="$(<'${cfg.secrets.jwsFile}')"
           ${pkgs.jq}/bin/jq -n '{production: {secret_key_base: $ENV.secret,
-                                              otp_key_base: $ENV.db,
-                                              db_key_base: $ENV.otp,
+                                              otp_key_base: $ENV.otp,
+                                              db_key_base: $ENV.db,
                                               openid_connect_signing_key: $ENV.jws}}' \
                             > '${cfg.statePath}/config/secrets.yml'
         )
diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index b69310c34ff5..84486aa98a40 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -34,6 +34,7 @@ let
     "node"
     "postfix"
     "postgres"
+    "rspamd"
     "snmp"
     "surfboard"
     "tor"
@@ -193,6 +194,8 @@ in
     services.prometheus.exporters.minio.minioAddress  = mkDefault "http://localhost:9000";
     services.prometheus.exporters.minio.minioAccessKey = mkDefault config.services.minio.accessKey;
     services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey;
+  })] ++ [(mkIf config.services.rspamd.enable {
+    services.prometheus.exporters.rspamd.url = mkDefault "http://localhost:11334/stat";
   })] ++ (mapAttrsToList (name: conf:
     mkExporterConf {
       inherit name;
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix b/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix
new file mode 100644
index 000000000000..1f02ae207249
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix
@@ -0,0 +1,92 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.rspamd;
+
+  prettyJSON = conf:
+    pkgs.runCommand "rspamd-exporter-config.yml" { } ''
+      echo '${builtins.toJSON conf}' | ${pkgs.buildPackages.jq}/bin/jq '.' > $out
+    '';
+
+  generateConfig = extraLabels: (map (path: {
+    name = "rspamd_${replaceStrings [ "." " " ] [ "_" "_" ] path}";
+    path = "$.${path}";
+    labels = extraLabels;
+  }) [
+    "actions.'add header'"
+    "actions.'no action'"
+    "actions.'rewrite subject'"
+    "actions.'soft reject'"
+    "actions.greylist"
+    "actions.reject"
+    "bytes_allocated"
+    "chunks_allocated"
+    "chunks_freed"
+    "chunks_oversized"
+    "connections"
+    "control_connections"
+    "ham_count"
+    "learned"
+    "pools_allocated"
+    "pools_freed"
+    "read_only"
+    "scanned"
+    "shared_chunks_allocated"
+    "spam_count"
+    "total_learns"
+  ]) ++ [{
+    name = "rspamd_statfiles";
+    type = "object";
+    path = "$.statfiles[*]";
+    labels = recursiveUpdate {
+      symbol = "$.symbol";
+      type = "$.type";
+    } extraLabels;
+    values = {
+      revision = "$.revision";
+      size = "$.size";
+      total = "$.total";
+      used = "$.used";
+      languages = "$.languages";
+      users = "$.users";
+    };
+  }];
+in
+{
+  port = 7980;
+  extraOpts = {
+    listenAddress = {}; # not used
+
+    url = mkOption {
+      type = types.str;
+      description = ''
+        URL to the rspamd metrics endpoint.
+        Defaults to http://localhost:11334/stat when
+        <option>services.rspamd.enable</option> is true.
+      '';
+    };
+
+    extraLabels = mkOption {
+      type = types.attrsOf types.str;
+      default = {
+        host = config.networking.hostName;
+      };
+      defaultText = "{ host = config.networking.hostName; }";
+      example = literalExample ''
+        {
+          host = config.networking.hostName;
+          custom_label = "some_value";
+        }
+      '';
+      description = "Set of labels added to each metric.";
+    };
+  };
+  serviceOpts.serviceConfig.ExecStart = ''
+    ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \
+      --port ${toString cfg.port} \
+      ${cfg.url} ${prettyJSON (generateConfig cfg.extraLabels)} \
+      ${concatStringsSep " \\\n  " cfg.extraFlags}
+  '';
+}
diff --git a/nixos/modules/services/network-filesystems/ceph.nix b/nixos/modules/services/network-filesystems/ceph.nix
index 3dc5b8feef65..656a2d21b868 100644
--- a/nixos/modules/services/network-filesystems/ceph.nix
+++ b/nixos/modules/services/network-filesystems/ceph.nix
@@ -390,7 +390,7 @@ in
 
     systemd.targets = let
       targets = [
-        { "ceph" = { description = "Ceph target allowing to start/stop all ceph service instances at once";
+        { ceph = { description = "Ceph target allowing to start/stop all ceph service instances at once";
                      wantedBy = [ "multi-user.target" ]; }; }
       ] ++ optional cfg.mon.enable (makeTarget "mon")
         ++ optional cfg.mds.enable (makeTarget "mds")
diff --git a/nixos/modules/services/networking/jormungandr.nix b/nixos/modules/services/networking/jormungandr.nix
index 85e804d6cf25..152cceb4bf91 100644
--- a/nixos/modules/services/networking/jormungandr.nix
+++ b/nixos/modules/services/networking/jormungandr.nix
@@ -14,8 +14,10 @@ let
     storage = dataDir;
     p2p = {
       public_address = "/ip4/127.0.0.1/tcp/8299";
-      messages = "high";
-      blocks = "high";
+      topics_of_interest = {
+        messages = "high";
+        blocks = "high";
+      };
     };
     rest = {
       listen = "127.0.0.1:8607";
diff --git a/nixos/modules/services/networking/minidlna.nix b/nixos/modules/services/networking/minidlna.nix
index 0947471adbc9..3ddea3c9757b 100644
--- a/nixos/modules/services/networking/minidlna.nix
+++ b/nixos/modules/services/networking/minidlna.nix
@@ -36,6 +36,37 @@ in
         '';
     };
 
+    services.minidlna.friendlyName = mkOption {
+      type = types.str;
+      default = "${config.networking.hostName} MiniDLNA";
+      defaultText = "$HOSTNAME MiniDLNA";
+      example = "rpi3";
+      description =
+        ''
+          Name that the DLNA server presents to clients.
+        '';
+    };
+
+    services.minidlna.rootContainer = mkOption {
+      type = types.str;
+      default = ".";
+      example = "B";
+      description =
+        ''
+          Use a different container as the root of the directory tree presented
+          to clients. The possible values are:
+          - "." - standard container
+          - "B" - "Browse Directory"
+          - "M" - "Music"
+          - "P" - "Pictures"
+          - "V" - "Video"
+          - Or, you can specify the ObjectID of your desired root container
+            (eg. 1$F for Music/Playlists)
+          If you specify "B" and the client device is audio-only then
+          "Music/Folders" will be used as root.
+         '';
+    };
+
     services.minidlna.loglevel = mkOption {
       type = types.str;
       default = "warn";
@@ -66,7 +97,37 @@ in
 
     services.minidlna.config = mkOption {
       type = types.lines;
-      description = "The contents of MiniDLNA's configuration file.";
+      description =
+      ''
+        The contents of MiniDLNA's configuration file.
+        When the service is activated, a basic template is generated
+        from the current options opened here.
+      '';
+    };
+
+    services.minidlna.extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      example = ''
+        # Not exhaustive example
+        # Support for streaming .jpg and .mp3 files to a TiVo supporting HMO.
+        enable_tivo=no
+        # SSDP notify interval, in seconds.
+        notify_interval=10
+        # maximum number of simultaneous connections
+        # note: many clients open several simultaneous connections while
+        # streaming
+        max_connections=50
+        # set this to yes to allow symlinks that point outside user-defined
+        # media_dirs.
+        wide_links=yes
+      '';
+      description =
+      ''
+        Extra minidlna options not yet opened for configuration here
+        (strict_dlna, model_number, model_name, etc...).  This is appended
+        to the current service already provided.
+      '';
     };
   };
 
@@ -75,13 +136,15 @@ in
     services.minidlna.config =
       ''
         port=${toString port}
-        friendly_name=${config.networking.hostName} MiniDLNA
+        friendly_name=${cfg.friendlyName}
         db_dir=/var/cache/minidlna
         log_level=${cfg.loglevel}
         inotify=yes
+        root_container=${cfg.rootContainer}
         ${concatMapStrings (dir: ''
           media_dir=${dir}
         '') cfg.mediaDirs}
+        ${cfg.extraConfig}
       '';
 
     users.users.minidlna = {
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 2061c02fffbd..887c89ddf3ab 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -8,6 +8,8 @@ let
   dynamicHostsEnabled =
     cfg.dynamicHosts.enable && cfg.dynamicHosts.hostsDirs != {};
 
+  delegateWireless = config.networking.wireless.enable == true && cfg.unmanaged != [];
+
   # /var/lib/misc is for dnsmasq.leases.
   stateDirs = "/var/lib/NetworkManager /var/lib/dhclient /var/lib/misc";
 
@@ -25,6 +27,7 @@ let
 
     [logging]
     level=${cfg.logLevel}
+    audit=${lib.boolToString config.security.audit.enable}
 
     [connection]
     ipv6.ip6-privacy=2
@@ -177,10 +180,11 @@ in {
       basePackages = mkOption {
         type = types.attrsOf types.package;
         default = { inherit (pkgs)
-                            networkmanager modemmanager wpa_supplicant crda
+                            networkmanager modemmanager crda
                             networkmanager-openvpn networkmanager-vpnc
                             networkmanager-openconnect networkmanager-fortisslvpn
-                            networkmanager-l2tp networkmanager-iodine; };
+                            networkmanager-l2tp networkmanager-iodine; }
+                  // optionalAttrs (!delegateWireless) { inherit (pkgs) wpa_supplicant; };
         internal = true;
       };
 
@@ -377,8 +381,11 @@ in {
   config = mkIf cfg.enable {
 
     assertions = [
-      { assertion = config.networking.wireless.enable == false;
-        message = "You can not use networking.networkmanager with networking.wireless";
+      { assertion = config.networking.wireless.enable == true -> cfg.unmanaged != [];
+        message = ''
+          You can not use networking.networkmanager with networking.wireless.
+          Except if you mark some interfaces as <literal>unmanaged</literal> by NetworkManager.
+        '';
       }
       { assertion = !dynamicHostsEnabled || (dynamicHostsEnabled && cfg.dns == "dnsmasq");
         message = ''
@@ -491,20 +498,20 @@ in {
       path = [ pkgs.iproute pkgs.utillinux pkgs.coreutils ];
     };
 
-    # Turn off NixOS' network management
-    networking = {
+    # Turn off NixOS' network management when networking is managed entirely by NetworkManager
+    networking = (mkIf (!delegateWireless) {
       useDHCP = false;
-      # use mkDefault to trigger the assertion about the conflict above
+      # Use mkDefault to trigger the assertion about the conflict above
       wireless.enable = mkDefault false;
-    };
+    }) // (mkIf cfg.enableStrongSwan {
+      networkmanager.packages = [ pkgs.networkmanager_strongswan ];
+    });
 
     security.polkit.extraConfig = polkitConf;
 
-    networking.networkmanager.packages =
-      mkIf cfg.enableStrongSwan [ pkgs.networkmanager_strongswan ];
-
-    services.dbus.packages =
-      optional cfg.enableStrongSwan pkgs.strongswanNM ++ cfg.packages;
+    services.dbus.packages = cfg.packages
+      ++ optional cfg.enableStrongSwan pkgs.strongswanNM
+      ++ optional (cfg.dns == "dnsmasq") pkgs.dnsmasq;
 
     services.udev.packages = cfg.packages;
   };
diff --git a/nixos/modules/services/networking/chrony.nix b/nixos/modules/services/networking/ntp/chrony.nix
index 77f702577000..c74476c7a155 100644
--- a/nixos/modules/services/networking/chrony.nix
+++ b/nixos/modules/services/networking/ntp/chrony.nix
@@ -9,11 +9,11 @@ let
   keyFile = "${stateDir}/chrony.keys";
 
   configFile = pkgs.writeText "chrony.conf" ''
-    ${concatMapStringsSep "\n" (server: "server " + server) cfg.servers}
+    ${concatMapStringsSep "\n" (server: "server " + server + " iburst") cfg.servers}
 
     ${optionalString
       (cfg.initstepslew.enabled && (cfg.servers != []))
-      "initstepslew ${toString cfg.initstepslew.threshold} ${concatStringsSep " " cfg.initstepslew.servers}"
+      "initstepslew ${toString cfg.initstepslew.threshold} ${concatStringsSep " " cfg.servers}"
     }
 
     driftfile ${stateDir}/chrony.drift
@@ -24,7 +24,7 @@ let
     ${cfg.extraConfig}
   '';
 
-  chronyFlags = "-m -u chrony -f ${configFile} ${toString cfg.extraFlags}";
+  chronyFlags = "-n -m -u chrony -f ${configFile} ${toString cfg.extraFlags}";
 in
 {
   options = {
@@ -48,7 +48,6 @@ in
         default = {
           enabled = true;
           threshold = 1000; # by default, same threshold as 'ntpd -g' (1000s)
-          servers = cfg.servers;
         };
         description = ''
           Allow chronyd to make a rapid measurement of the system clock error at
@@ -76,6 +75,8 @@ in
   };
 
   config = mkIf cfg.enable {
+    meta.maintainers = with lib.maintainers; [ thoughtpolice ];
+
     environment.systemPackages = [ pkgs.chrony ];
 
     users.groups = singleton
@@ -115,7 +116,7 @@ in
 
         unitConfig.ConditionCapability = "CAP_SYS_TIME";
         serviceConfig =
-          { Type = "forking";
+          { Type = "simple";
             ExecStart = "${pkgs.chrony}/bin/chronyd ${chronyFlags}";
 
             ProtectHome = "yes";
diff --git a/nixos/modules/services/networking/ntpd.nix b/nixos/modules/services/networking/ntp/ntpd.nix
index 588d1c6edb07..1197c84f0459 100644
--- a/nixos/modules/services/networking/ntpd.nix
+++ b/nixos/modules/services/networking/ntp/ntpd.nix
@@ -96,6 +96,7 @@ in
   ###### implementation
 
   config = mkIf config.services.ntp.enable {
+    meta.maintainers = with lib.maintainers; [ thoughtpolice ];
 
     # Make tools such as ntpq available in the system path.
     environment.systemPackages = [ pkgs.ntp ];
diff --git a/nixos/modules/services/networking/openntpd.nix b/nixos/modules/services/networking/ntp/openntpd.nix
index f3920aa80646..471d15b1687b 100644
--- a/nixos/modules/services/networking/openntpd.nix
+++ b/nixos/modules/services/networking/ntp/openntpd.nix
@@ -52,6 +52,7 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
+    meta.maintainers = with lib.maintainers; [ thoughtpolice ];
     services.timesyncd.enable = mkForce false;
 
     # Add ntpctl to the environment for status checking
diff --git a/nixos/modules/services/networking/pdns-recursor.nix b/nixos/modules/services/networking/pdns-recursor.nix
index ec69cc838da9..ebfdd9f35b72 100644
--- a/nixos/modules/services/networking/pdns-recursor.nix
+++ b/nixos/modules/services/networking/pdns-recursor.nix
@@ -168,7 +168,7 @@ in {
       disable-syslog = true;
     };
 
-    users.users."${username}" = {
+    users.users.${username} = {
       home = dataDir;
       createHome = true;
       uid = config.ids.uids.pdns-recursor;
diff --git a/nixos/modules/services/networking/toxvpn.nix b/nixos/modules/services/networking/toxvpn.nix
index 7daacba185fe..9e97faeebc1e 100644
--- a/nixos/modules/services/networking/toxvpn.nix
+++ b/nixos/modules/services/networking/toxvpn.nix
@@ -23,7 +23,7 @@ with lib;
         type        = types.listOf types.str;
         default     = [];
         example     = ''[ "toxid1" "toxid2" ]'';
-        description = "peers to automacally connect to on startup";
+        description = "peers to automatically connect to on startup";
       };
     };
   };
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index 7f1e793b980e..3fcae611dc79 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -291,6 +291,16 @@ in
 
     services.dbus.packages = [ cups.out ] ++ optional polkitEnabled cups-pk-helper;
 
+    # Allow asswordless printer admin for members of wheel group
+    security.polkit.extraConfig = mkIf polkitEnabled ''
+      polkit.addRule(function(action, subject) {
+          if (action.id == "org.opensuse.cupspkhelper.mechanism.all-edit" &&
+              subject.isInGroup("wheel")){
+              return polkit.Result.YES;
+          }
+      });
+    '';
+
     # Cups uses libusb to talk to printers, and does not use the
     # linux kernel driver. If the driver is not in a black list, it
     # gets loaded, and then cups cannot access the printers.
diff --git a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
index 195ee76ff4e3..d9ad7e9e3d39 100644
--- a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
+++ b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
@@ -165,7 +165,7 @@ in {
 
   config = mkIf cfg.enable {
     services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
-      "${poolName}" = {
+      ${poolName} = {
         user = "icingaweb2";
         phpOptions = ''
           extension = ${pkgs.phpPackages.imagick}/lib/php/extensions/imagick.so
diff --git a/nixos/modules/services/web-apps/moodle.nix b/nixos/modules/services/web-apps/moodle.nix
index f2516c67c6b3..211bc17ee192 100644
--- a/nixos/modules/services/web-apps/moodle.nix
+++ b/nixos/modules/services/web-apps/moodle.nix
@@ -18,7 +18,7 @@ let
   global $CFG;
   $CFG = new stdClass();
 
-  $CFG->dbtype    = '${ { "mysql" = "mariadb"; "pgsql" = "pgsql"; }.${cfg.database.type} }';
+  $CFG->dbtype    = '${ { mysql = "mariadb"; pgsql = "pgsql"; }.${cfg.database.type} }';
   $CFG->dblibrary = 'native';
   $CFG->dbhost    = '${cfg.database.host}';
   $CFG->dbname    = '${cfg.database.name}';
@@ -45,6 +45,8 @@ let
   $CFG->aspellpath = '${pkgs.aspell}/bin/aspell';
   $CFG->pathtodot = '${pkgs.graphviz}/bin/dot';
 
+  ${cfg.extraConfig}
+
   require_once('${cfg.package}/share/moodle/lib/setup.php');
 
   // There is no php closing tag in this file,
@@ -92,8 +94,8 @@ in
         type = types.int;
         description = "Database host port.";
         default = {
-          "mysql" = 3306;
-          "pgsql" = 5432;
+          mysql = 3306;
+          pgsql = 5432;
         }.${cfg.database.type};
         defaultText = "3306";
       };
@@ -172,6 +174,19 @@ in
         for details on configuration directives.
       '';
     };
+
+    extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        Any additional text to be appended to the config.php
+        configuration file. This is a PHP script. For configuration
+        details, see <link xlink:href="https://docs.moodle.org/37/en/Configuration_file"/>.
+      '';
+      example = ''
+        $CFG->disableupdatenotifications = true;
+      '';
+    };
   };
 
   # implementation
@@ -294,7 +309,7 @@ in
 
     systemd.services.httpd.after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
 
-    users.users."${user}".group = group;
+    users.users.${user}.group = group;
 
   };
 }
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index 5f5469e48507..db5dc915c89f 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -120,16 +120,24 @@ in {
       '';
     };
 
-    poolConfig = mkOption {
-      type = types.lines;
-      default = ''
-        pm = dynamic
-        pm.max_children = 32
-        pm.start_servers = 2
-        pm.min_spare_servers = 2
-        pm.max_spare_servers = 4
-        pm.max_requests = 500
+    poolSettings = mkOption {
+      type = with types; attrsOf (oneOf [ str int bool ]);
+      default = {
+        "pm" = "dynamic";
+        "pm.max_children" = "32";
+        "pm.start_servers" = "2";
+        "pm.min_spare_servers" = "2";
+        "pm.max_spare_servers" = "4";
+        "pm.max_requests" = "500";
+      };
+      description = ''
+        Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
       '';
+    };
+
+    poolConfig = mkOption {
+      type = types.nullOr types.lines;
+      default = null;
       description = ''
         Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
       '';
@@ -287,6 +295,11 @@ in {
           message = "Please specify exactly one of adminpass or adminpassFile";
         }
       ];
+
+      warnings = optional (cfg.poolConfig != null) ''
+        Using config.services.nextcloud.poolConfig is deprecated and will become unsupported in a future release.
+        Please migrate your configuration to config.services.nextcloud.poolSettings.
+      '';
     }
 
     { systemd.timers.nextcloud-cron = {
@@ -423,7 +436,7 @@ in {
           settings = mapAttrs (name: mkDefault) {
             "listen.owner" = "nginx";
             "listen.group" = "nginx";
-          };
+          } // cfg.poolSettings;
           extraConfig = cfg.poolConfig;
         };
       };
diff --git a/nixos/modules/services/web-apps/restya-board.nix b/nixos/modules/services/web-apps/restya-board.nix
index 11272ed591b8..1e7882488ac6 100644
--- a/nixos/modules/services/web-apps/restya-board.nix
+++ b/nixos/modules/services/web-apps/restya-board.nix
@@ -179,7 +179,7 @@ in
   config = mkIf cfg.enable {
 
     services.phpfpm.pools = {
-      "${poolName}" = {
+      ${poolName} = {
         inherit (cfg) user group;
 
         phpOptions = ''
@@ -216,7 +216,6 @@ in
         index index.html index.php;
 
         gzip on;
-        gzip_disable "msie6";
 
         gzip_comp_level 6;
         gzip_min_length  1100;
diff --git a/nixos/modules/services/web-apps/selfoss.nix b/nixos/modules/services/web-apps/selfoss.nix
index d693c401565f..d5a660ebf289 100644
--- a/nixos/modules/services/web-apps/selfoss.nix
+++ b/nixos/modules/services/web-apps/selfoss.nix
@@ -115,7 +115,7 @@ in
 
   config = mkIf cfg.enable {
     services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
-      "${poolName}" = {
+      ${poolName} = {
         user = "nginx";
         settings = mapAttrs (name: mkDefault) {
           "listen.owner" = "nginx";
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index 4daf3ff9f991..abe4748591e9 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -520,7 +520,7 @@ let
     ];
 
     services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
-      "${poolName}" = {
+      ${poolName} = {
         inherit (cfg) user;
         settings = mapAttrs (name: mkDefault) {
           "listen.owner" = "nginx";
diff --git a/nixos/modules/services/web-apps/wordpress.nix b/nixos/modules/services/web-apps/wordpress.nix
index 884754370587..e311dd917dd0 100644
--- a/nixos/modules/services/web-apps/wordpress.nix
+++ b/nixos/modules/services/web-apps/wordpress.nix
@@ -61,6 +61,19 @@ let
     ?>
   '';
 
+  secretsVars = [ "AUTH_KEY" "SECURE_AUTH_KEY" "LOOGGED_IN_KEY" "NONCE_KEY" "AUTH_SALT" "SECURE_AUTH_SALT" "LOGGED_IN_SALT" "NONCE_SALT" ];
+  secretsScript = hostStateDir: ''
+    if ! test -e "${hostStateDir}/secret-keys.php"; then
+      umask 0177
+      echo "<?php" >> "${hostStateDir}/secret-keys.php"
+      ${concatMapStringsSep "\n" (var: ''
+        echo "define('${var}', '`tr -dc a-zA-Z0-9 </dev/urandom | head -c 64`');" >> "${hostStateDir}/secret-keys.php"
+      '') secretsVars}
+      echo "?>" >> "${hostStateDir}/secret-keys.php"
+      chmod 440 "${hostStateDir}/secret-keys.php"
+    fi
+  '';
+
   siteOpts = { lib, name, ... }:
     {
       options = {
@@ -340,14 +353,7 @@ in
           wantedBy = [ "multi-user.target" ];
           before = [ "phpfpm-wordpress-${hostName}.service" ];
           after = optional cfg.database.createLocally "mysql.service";
-          script = ''
-            if ! test -e "${stateDir hostName}/secret-keys.php"; then
-              echo "<?php" >> "${stateDir hostName}/secret-keys.php"
-              ${pkgs.curl}/bin/curl -s https://api.wordpress.org/secret-key/1.1/salt/ >> "${stateDir hostName}/secret-keys.php"
-              echo "?>" >> "${stateDir hostName}/secret-keys.php"
-              chmod 440 "${stateDir hostName}/secret-keys.php"
-            fi
-          '';
+          script = secretsScript (stateDir hostName);
 
           serviceConfig = {
             Type = "oneshot";
diff --git a/nixos/modules/services/web-apps/zabbix.nix b/nixos/modules/services/web-apps/zabbix.nix
index dac243b20e97..09538726b7cd 100644
--- a/nixos/modules/services/web-apps/zabbix.nix
+++ b/nixos/modules/services/web-apps/zabbix.nix
@@ -179,7 +179,7 @@ in
       '' + optionalString (cfg.database.type == "oracle") ''
         extension=${pkgs.phpPackages.oci8}/lib/php/extensions/oci8.so
       '';
-      phpEnv.ZABBIX_CONFIG = zabbixConfig;
+      phpEnv.ZABBIX_CONFIG = "${zabbixConfig}";
       settings = {
         "listen.owner" = config.services.httpd.user;
         "listen.group" = config.services.httpd.group;
@@ -197,7 +197,7 @@ in
             <Directory "${cfg.package}/share/zabbix">
               <FilesMatch "\.php$">
                 <If "-f %{REQUEST_FILENAME}">
-                  SetHandler "proxy:unix:${fpm.listen}|fcgi://localhost/"
+                  SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
                 </If>
               </FilesMatch>
               AllowOverride all
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index b94b338fd4a6..e597f34700ae 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -94,7 +94,6 @@ let
 
       ${optionalString (cfg.recommendedGzipSettings) ''
         gzip on;
-        gzip_disable "msie6";
         gzip_proxied any;
         gzip_comp_level 5;
         gzip_types
diff --git a/nixos/modules/services/web-servers/phpfpm/default.nix b/nixos/modules/services/web-servers/phpfpm/default.nix
index e95e71e0d997..4ab7e3f0c0a9 100644
--- a/nixos/modules/services/web-servers/phpfpm/default.nix
+++ b/nixos/modules/services/web-servers/phpfpm/default.nix
@@ -36,7 +36,7 @@ let
 
   poolOpts = { name, ... }:
     let
-      poolOpts = cfg.pools."${name}";
+      poolOpts = cfg.pools.${name};
     in
     {
       options = {
diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 9914b6687090..3745069f6eaf 100644
--- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix
+++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -48,10 +48,6 @@ in
     services.xserver.desktopManager.session = [
     { name = "Enlightenment";
       start = ''
-        # Set GTK_DATA_PREFIX so that GTK can find the themes
-        export GTK_DATA_PREFIX=${config.system.path}
-        # find theme engines
-        export GTK_PATH=${config.system.path}/lib/gtk-3.0:${config.system.path}/lib/gtk-2.0
         export XDG_MENU_PREFIX=e-
 
         export GST_PLUGIN_PATH="${GST_PLUGIN_PATH}"
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index a21d22261ba3..30c5250221c1 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -240,14 +240,16 @@ in
 
       services.avahi.enable = mkDefault true;
 
+      xdg.portal.extraPortals = [ pkgs.gnome3.gnome-shell ];
+
       services.geoclue2.enable = mkDefault true;
       services.geoclue2.enableDemoAgent = false; # GNOME has its own geoclue agent
 
-      services.geoclue2.appConfig."gnome-datetime-panel" = {
+      services.geoclue2.appConfig.gnome-datetime-panel = {
         isAllowed = true;
         isSystem = true;
       };
-      services.geoclue2.appConfig."gnome-color-panel" = {
+      services.geoclue2.appConfig.gnome-color-panel = {
         isAllowed = true;
         isSystem = true;
       };
diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix
index d7a871c9c704..4563583e0704 100644
--- a/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -48,12 +48,6 @@ in
       name = "mate";
       bgSupport = true;
       start = ''
-        # Set GTK_DATA_PREFIX so that GTK can find the themes
-        export GTK_DATA_PREFIX=${config.system.path}
-
-        # Find theme engines
-        export GTK_PATH=${config.system.path}/lib/gtk-3.0:${config.system.path}/lib/gtk-2.0
-
         export XDG_MENU_PREFIX=mate-
 
         # Let caja find extensions
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index e313a194c345..d80ea9a53e80 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -79,8 +79,7 @@ in
         Using Pantheon without LightDM as a displayManager will break screenlocking from the UI.
       '';
 
-    services.xserver.displayManager.lightdm.enable = mkDefault true;
-    services.xserver.displayManager.lightdm.greeters.gtk.enable = mkDefault true;
+    services.xserver.displayManager.lightdm.greeters.pantheon.enable = mkDefault true;
 
     # If not set manually Pantheon session cannot be started
     # Known issue of https://github.com/NixOS/nixpkgs/pull/43992
@@ -98,10 +97,6 @@ in
               export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
             fi
           '') cfg.sessionPath}
-
-          # Settings from elementary-default-settings
-          export GTK_CSD=1
-          export GTK_MODULES=$GTK_MODULES:pantheon-filechooser-module
       fi
     '';
 
@@ -166,9 +161,14 @@ in
                               networkmanager-iodine networkmanager-l2tp; };
 
     # Override GSettings schemas
-    environment.variables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
+    environment.sessionVariables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
+
+    environment.sessionVariables.GNOME_SESSION_DEBUG = optionalString cfg.debug "1";
 
-    environment.variables.GNOME_SESSION_DEBUG = optionalString cfg.debug "1";
+    # Settings from elementary-default-settings
+    environment.sessionVariables.GTK_CSD = "1";
+    environment.sessionVariables.GTK_MODULES = "pantheon-filechooser-module";
+    environment.etc."gtk-3.0/settings.ini".source = "${pkgs.pantheon.elementary-default-settings}/etc/gtk-3.0/settings.ini";
 
     environment.pathsToLink = [
       # FIXME: modules should link subdirs of `/share` rather than relying on this
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index e3249aef50c7..6965c6d26467 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -107,12 +107,6 @@ in
       start = ''
         ${cfg.extraSessionCommands}
 
-        # Set GTK_PATH so that GTK can find the theme engines.
-        export GTK_PATH="${config.system.path}/lib/gtk-2.0:${config.system.path}/lib/gtk-3.0"
-
-        # Set GTK_DATA_PREFIX so that GTK can find the Xfce themes.
-        export GTK_DATA_PREFIX=${config.system.path}
-
         ${pkgs.runtimeShell} ${pkgs.xfce.xinitrc} &
         waitPID=$!
       '';
diff --git a/nixos/modules/services/x11/desktop-managers/xfce4-14.nix b/nixos/modules/services/x11/desktop-managers/xfce4-14.nix
index 57d1268d655a..130e865a1fb4 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce4-14.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce4-14.nix
@@ -53,6 +53,7 @@ in
       glib # for gsettings
       gtk3.out # gtk-update-icon-cache
 
+      gnome3.gnome-themes-extra
       gnome3.adwaita-icon-theme
       hicolor-icon-theme
       tango-icon-theme
@@ -69,16 +70,17 @@ in
 
       exo
       garcon
-      gtk-xfce-engine
       libxfce4ui
       xfconf
 
       mousepad
+      parole
       ristretto
       xfce4-appfinder
       xfce4-screenshooter
       xfce4-session
       xfce4-settings
+      xfce4-taskmanager
       xfce4-terminal
 
       # TODO: resync patch for plugins
@@ -86,12 +88,16 @@ in
       thunar
     ] # TODO: NetworkManager doesn't belong here
       ++ optional config.networking.networkmanager.enable networkmanagerapplet
-      ++ optional config.hardware.pulseaudio.enable xfce4-pulseaudio-plugin
       ++ optional config.powerManagement.enable xfce4-power-manager
-      ++ optional cfg.enableXfwm xfwm4
-      ++ optionals (!cfg.noDesktop) [
-        xfce4-panel
+      ++ optionals config.hardware.pulseaudio.enable [
+        pavucontrol
+        xfce4-pulseaudio-plugin
+      ] ++ optionals cfg.enableXfwm [
+        xfwm4
+        xfwm4-themes
+      ] ++ optionals (!cfg.noDesktop) [
         xfce4-notifyd
+        xfce4-panel
         xfdesktop
       ];
 
@@ -114,12 +120,6 @@ in
       name = "xfce4-14";
       bgSupport = true;
       start = ''
-        # Set GTK_PATH so that GTK can find the theme engines.
-        export GTK_PATH="${config.system.path}/lib/gtk-2.0:${config.system.path}/lib/gtk-3.0"
-
-        # Set GTK_DATA_PREFIX so that GTK can find the Xfce themes.
-        export GTK_DATA_PREFIX=${config.system.path}
-
         ${pkgs.runtimeShell} ${pkgs.xfce4-14.xinitrc} &
         waitPID=$!
       '';
diff --git a/nixos/modules/services/x11/desktop-managers/xterm.nix b/nixos/modules/services/x11/desktop-managers/xterm.nix
index 93987bd1dfc5..f76db278a927 100644
--- a/nixos/modules/services/x11/desktop-managers/xterm.nix
+++ b/nixos/modules/services/x11/desktop-managers/xterm.nix
@@ -5,6 +5,7 @@ with lib;
 let
 
   cfg = config.services.xserver.desktopManager.xterm;
+  xSessionEnabled = config.services.xserver.enable;
 
 in
 
@@ -13,8 +14,8 @@ in
 
     services.xserver.desktopManager.xterm.enable = mkOption {
       type = types.bool;
-      default = false;
-      defaultText = "config.services.xserver.enable";
+      default = (versionOlder config.system.stateVersion "19.09") && xSessionEnabled;
+      defaultText = if versionOlder config.system.stateVersion "19.09" then "config.services.xserver.enable" else "false";
       description = "Enable a xterm terminal as a desktop manager.";
     };
 
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 3f1669d08516..0a5d52e319ec 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -142,8 +142,6 @@ in
           GDM_X_SERVER_EXTRA_ARGS = toString
             (filter (arg: arg != "-terminate") cfg.xserverArgs);
           XDG_DATA_DIRS = "${cfg.session.desktops}/share/";
-          # Find the mouse
-          XCURSOR_PATH = "~/.icons:${pkgs.gnome3.adwaita-icon-theme}/share/icons";
         } // optionalAttrs (xSessionWrapper != null) {
           # Make GDM use this wrapper before running the session, which runs the
           # configured setupCommands. This relies on a patched GDM which supports
@@ -262,7 +260,7 @@ in
         password required       pam_deny.so
 
         session  required       pam_succeed_if.so audit quiet_success user = gdm
-        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  required       pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
         session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
         session  optional       pam_keyinit.so force revoke
         session  optional       pam_permit.so
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix
index de128809ce30..129df139c61a 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix
@@ -10,32 +10,6 @@ let
   icons = cfg.iconTheme.package;
   cursors = cfg.cursorTheme.package;
 
-  # We need a few things in the environment for the greeter to run with
-  # fonts/icons.
-  wrappedEnsoGreeter = pkgs.runCommand "lightdm-enso-os-greeter" {
-      buildInputs = [ pkgs.makeWrapper ];
-      preferLocalBuild = true;
-    } ''
-      # This wrapper ensures that we actually get themes
-      makeWrapper ${pkgs.lightdm-enso-os-greeter}/bin/pantheon-greeter \
-        $out/greeter \
-        --prefix PATH : "${pkgs.glibc.bin}/bin" \
-        --set GDK_PIXBUF_MODULE_FILE "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \
-        --set GTK_PATH "${theme}:${pkgs.gtk3.out}" \
-        --set GTK_EXE_PREFIX "${theme}" \
-        --set GTK_DATA_PREFIX "${theme}" \
-        --set XDG_DATA_DIRS "${theme}/share:${icons}/share:${cursors}/share" \
-        --set XDG_CONFIG_HOME "${theme}/share"
-
-      cat - > $out/lightdm-enso-os-greeter.desktop << EOF
-      [Desktop Entry]
-      Name=LightDM Greeter
-      Comment=This runs the LightDM Greeter
-      Exec=$out/greeter
-      Type=Application
-      EOF
-    '';
-
   ensoGreeterConf = pkgs.writeText "lightdm-enso-os-greeter.conf" ''
     [greeter]
     default-wallpaper=${ldmcfg.background}
@@ -144,10 +118,16 @@ in {
   config = mkIf (ldmcfg.enable && cfg.enable) {
     environment.etc."lightdm/greeter.conf".source = ensoGreeterConf;
 
+    environment.systemPackages = [
+      cursors
+      icons
+      theme
+    ];
+
     services.xserver.displayManager.lightdm = {
       greeter = mkDefault {
-        package = wrappedEnsoGreeter;
-        name = "lightdm-enso-os-greeter";
+        package = pkgs.lightdm-enso-os-greeter.xgreeters;
+        name = "pantheon-greeter";
       };
 
       greeters = {
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
index 5b280b024233..de932e6e840a 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -15,34 +15,6 @@ let
   icons = cfg.iconTheme.package;
   cursors = cfg.cursorTheme.package;
 
-  # The default greeter provided with this expression is the GTK greeter.
-  # Again, we need a few things in the environment for the greeter to run with
-  # fonts/icons.
-  wrappedGtkGreeter = pkgs.runCommand "lightdm-gtk-greeter" {
-      buildInputs = [ pkgs.makeWrapper ];
-      preferLocalBuild = true;
-    } ''
-      # This wrapper ensures that we actually get themes
-      makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
-        $out/greeter \
-        --prefix PATH : "${lib.getBin pkgs.stdenv.cc.libc}/bin" \
-        --set GDK_PIXBUF_MODULE_FILE "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \
-        --set GTK_PATH "${theme}:${pkgs.gtk3.out}" \
-        --set GTK_EXE_PREFIX "${theme}" \
-        --set GTK_DATA_PREFIX "${theme}" \
-        --set XDG_DATA_DIRS "${theme}/share:${icons}/share" \
-        --set XDG_CONFIG_HOME "${theme}/share" \
-        --set XCURSOR_PATH "${cursors}/share/icons"
-
-      cat - > $out/lightdm-gtk-greeter.desktop << EOF
-      [Desktop Entry]
-      Name=LightDM Greeter
-      Comment=This runs the LightDM Greeter
-      Exec=$out/greeter
-      Type=Application
-      EOF
-    '';
-
   gtkGreeterConf = writeText "lightdm-gtk-greeter.conf"
     ''
     [greeter]
@@ -185,10 +157,16 @@ in
   config = mkIf (ldmcfg.enable && cfg.enable) {
 
     services.xserver.displayManager.lightdm.greeter = mkDefault {
-      package = wrappedGtkGreeter;
+      package = pkgs.lightdm_gtk_greeter.xgreeters;
       name = "lightdm-gtk-greeter";
     };
 
+    environment.systemPackages = [
+      cursors
+      icons
+      theme
+    ];
+
     environment.etc."lightdm/lightdm-gtk-greeter.conf".source = gtkGreeterConf;
 
   };
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
index ba8151a60f20..fa9445af32e7 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
@@ -8,11 +8,6 @@ let
   ldmcfg = dmcfg.lightdm;
   cfg = ldmcfg.greeters.mini;
 
-  xgreeters = pkgs.linkFarm "lightdm-mini-greeter-xgreeters" [{
-    path = "${pkgs.lightdm-mini-greeter}/share/xgreeters/lightdm-mini-greeter.desktop";
-    name = "lightdm-mini-greeter.desktop";
-  }];
-
   miniGreeterConf = pkgs.writeText "lightdm-mini-greeter.conf"
     ''
     [greeter]
@@ -90,7 +85,7 @@ in
     services.xserver.displayManager.lightdm.greeters.gtk.enable = false;
 
     services.xserver.displayManager.lightdm.greeter = mkDefault {
-      package = xgreeters;
+      package = pkgs.lightdm-mini-greeter.xgreeters;
       name = "lightdm-mini-greeter";
     };
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/pantheon.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/pantheon.nix
index bfba174144a1..29cb6ccbc06b 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/pantheon.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/pantheon.nix
@@ -8,11 +8,6 @@ let
   ldmcfg = dmcfg.lightdm;
   cfg = ldmcfg.greeters.pantheon;
 
-  xgreeters = pkgs.linkFarm "pantheon-greeter-xgreeters" [{
-    path = "${pkgs.pantheon.elementary-greeter}/share/xgreeters/io.elementary.greeter.desktop";
-    name = "io.elementary.greeter.desktop";
-  }];
-
 in
 {
   options = {
@@ -33,17 +28,10 @@ in
 
   config = mkIf (ldmcfg.enable && cfg.enable) {
 
-    warnings = [
-      ''
-        The Pantheon greeter is suboptimal in NixOS and can possibly put you in
-        a situation where you cannot start a session when switching desktopManagers.
-      ''
-    ];
-
     services.xserver.displayManager.lightdm.greeters.gtk.enable = false;
 
     services.xserver.displayManager.lightdm.greeter = mkDefault {
-      package = xgreeters;
+      package = pkgs.pantheon.elementary-greeter.xgreeters;
       name = "io.elementary.greeter";
     };
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index c26a5b615353..f105cb496e68 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -249,7 +249,7 @@ in
         password required       pam_deny.so
 
         session  required       pam_succeed_if.so audit quiet_success user = lightdm
-        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  required       pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
         session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
         session  optional       pam_keyinit.so force revoke
         session  optional       pam_permit.so
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index c6cb281c2cc2..8847acb0c604 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -219,8 +219,6 @@ in
         # Load themes from system environment
         QT_PLUGIN_PATH = "/run/current-system/sw/" + pkgs.qt5.qtbase.qtPluginPrefix;
         QML2_IMPORT_PATH = "/run/current-system/sw/" + pkgs.qt5.qtbase.qtQmlPrefix;
-
-        XDG_DATA_DIRS = "/run/current-system/sw/share";
       };
 
       execCmd = "exec /run/current-system/sw/bin/sddm";
@@ -242,7 +240,7 @@ in
         password required       pam_deny.so
 
         session  required       pam_succeed_if.so audit quiet_success user = sddm
-        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  required       pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
         session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
         session  optional       pam_keyinit.so force revoke
         session  optional       pam_permit.so
diff --git a/nixos/modules/services/x11/extra-layouts.nix b/nixos/modules/services/x11/extra-layouts.nix
index 5523dd2bf023..1af98a1318bb 100644
--- a/nixos/modules/services/x11/extra-layouts.nix
+++ b/nixos/modules/services/x11/extra-layouts.nix
@@ -158,7 +158,10 @@ in
 
     });
 
-    services.xserver.xkbDir = "${pkgs.xkb_patched}/etc/X11/xkb";
+    services.xserver = {
+      xkbDir = "${pkgs.xkb_patched}/etc/X11/xkb";
+      exportConfiguration = config.services.xserver.displayManager.startx.enable;
+    };
 
   };
 
diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix
index 6ddb4c83764a..21b0b33553ac 100644
--- a/nixos/modules/services/x11/redshift.nix
+++ b/nixos/modules/services/x11/redshift.nix
@@ -9,6 +9,22 @@ let
 
 in {
 
+  imports = [
+    (mkChangedOptionModule [ "services" "redshift" "latitude" ] [ "location" "latitude" ]
+      (config:
+        let value = getAttrFromPath [ "services" "redshift" "latitude" ] config;
+        in if value == null then
+          throw "services.redshift.latitude is set to null, you can remove this"
+          else builtins.fromJSON value))
+    (mkChangedOptionModule [ "services" "redshift" "longitude" ] [ "location" "longitude" ]
+      (config:
+        let value = getAttrFromPath [ "services" "redshift" "longitude" ] config;
+        in if value == null then
+          throw "services.redshift.longitude is set to null, you can remove this"
+          else builtins.fromJSON value))
+    (mkRenamedOptionModule [ "services" "redshift" "provider" ] [ "location" "provider" ])
+  ];
+
   options.services.redshift = {
     enable = mkOption {
       type = types.bool;
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index 74c150a848d1..ddfd1af4a319 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -218,7 +218,7 @@ in
 
     systemd.user = {
       services.nixos-activation = {
-        description = "Run user specific NixOS activation";
+        description = "Run user-specific NixOS activation";
         script = config.system.userActivationScripts.script;
         unitConfig.ConditionUser = "!@system";
         serviceConfig.Type = "oneshot";
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 8ff00fa11dc7..641cf9faadc9 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -10,6 +10,9 @@ use Cwd 'abs_path';
 
 my $out = "@out@";
 
+# FIXME: maybe we should use /proc/1/exe to get the current systemd.
+my $curSystemd = abs_path("/run/current-system/sw/bin");
+
 # To be robust against interruption, record what units need to be started etc.
 my $startListFile = "/run/systemd/start-list";
 my $restartListFile = "/run/systemd/restart-list";
@@ -267,7 +270,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
 sub pathToUnitName {
     my ($path) = @_;
     # Use current version of systemctl binary before daemon is reexeced.
-    open my $cmd, "-|", "/run/current-system/sw/bin/systemd-escape", "--suffix=mount", "-p", $path
+    open my $cmd, "-|", "$curSystemd/systemd-escape", "--suffix=mount", "-p", $path
         or die "Unable to escape $path!\n";
     my $escaped = join "", <$cmd>;
     chomp $escaped;
@@ -370,7 +373,7 @@ if (scalar (keys %unitsToStop) > 0) {
     print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n"
         if scalar @unitsToStopFiltered;
     # Use current version of systemctl binary before daemon is reexeced.
-    system("/run/current-system/sw/bin/systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors?
+    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors?
 }
 
 print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
@@ -382,10 +385,12 @@ my $res = 0;
 print STDERR "activating the configuration...\n";
 system("$out/activate", "$out") == 0 or $res = 2;
 
-# Restart systemd if necessary.
+# Restart systemd if necessary. Note that this is done using the
+# current version of systemd, just in case the new one has trouble
+# communicating with the running pid 1.
 if ($restartSystemd) {
     print STDERR "restarting systemd...\n";
-    system("@systemd@/bin/systemctl", "daemon-reexec") == 0 or $res = 2;
+    system("$curSystemd/systemctl", "daemon-reexec") == 0 or $res = 2;
 }
 
 # Forget about previously failed services.
@@ -401,8 +406,10 @@ while (my $f = <$listActiveUsers>) {
     my ($uid, $name) = ($+{uid}, $+{user});
     print STDERR "reloading user units for $name...\n";
 
-    system("@su@", "-s", "@shell@", "-l", $name, "-c", "XDG_RUNTIME_DIR=/run/user/$uid @systemd@/bin/systemctl --user daemon-reload");
-    system("@su@", "-s", "@shell@", "-l", $name, "-c", "XDG_RUNTIME_DIR=/run/user/$uid @systemd@/bin/systemctl --user start nixos-activation.service");
+    system("@su@", "-s", "@shell@", "-l", $name, "-c",
+           "export XDG_RUNTIME_DIR=/run/user/$uid; " .
+           "$curSystemd/systemctl --user daemon-reexec; " .
+           "@systemd@/bin/systemctl --user start nixos-activation.service");
 }
 
 close $listActiveUsers;
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index 50dbf2f83651..8a309f3bc5fe 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -108,7 +108,7 @@ in
     boot.extraModulePackages = mkOption {
       type = types.listOf types.package;
       default = [];
-      example = literalExample "[ pkgs.linuxPackages.nvidia_x11 ]";
+      example = literalExample "[ config.boot.kernelPackages.nvidia_x11 ]";
       description = "A list of additional packages supplying kernel modules.";
     };
 
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 2287a82418fe..5cf437bfbcbe 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -858,7 +858,12 @@ in
       "sysctl.d/50-coredump.conf".source = "${systemd}/example/sysctl.d/50-coredump.conf";
       "sysctl.d/50-default.conf".source = "${systemd}/example/sysctl.d/50-default.conf";
 
+      "tmpfiles.d/journal-nocow.conf".source = "${systemd}/example/tmpfiles.d/journal-nocow.conf";
+      "tmpfiles.d/static-nodes-permissions.conf".source = "${systemd}/example/tmpfiles.d/static-nodes-permissions.conf";
       "tmpfiles.d/systemd.conf".source = "${systemd}/example/tmpfiles.d/systemd.conf";
+      "tmpfiles.d/systemd-nspawn.conf".source = "${systemd}/example/tmpfiles.d/system-nspawn.conf";
+      "tmpfiles.d/systemd-tmp.conf".source = "${systemd}/example/tmpfiles.d/system-tmp.conf";
+      "tmpfiles.d/var.conf".source = "${systemd}/example/tmpfiles.d/var.conf";
       "tmpfiles.d/x11.conf".source = "${systemd}/example/tmpfiles.d/x11.conf";
 
       "tmpfiles.d/nixos.conf".text = ''
diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix
index 18753ae0c1ae..7fe066991918 100644
--- a/nixos/modules/tasks/auto-upgrade.nix
+++ b/nixos/modules/tasks/auto-upgrade.nix
@@ -88,7 +88,7 @@ let cfg = config.system.autoUpgrade; in
           HOME = "/root";
         } // config.networking.proxy.envVars;
 
-      path = [ pkgs.coreutils pkgs.gnutar pkgs.xz.bin pkgs.gitMinimal config.nix.package.out ];
+      path = with pkgs; [ coreutils gnutar xz.bin gzip gitMinimal config.nix.package.out ];
 
       script = let
           nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild";
diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix
index f5a593211efc..34e270667151 100644
--- a/nixos/modules/tasks/network-interfaces-systemd.nix
+++ b/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -72,7 +72,15 @@ in
           };
       in mkMerge [ {
         enable = true;
-        networks."99-main" = genericNetwork mkDefault;
+        networks."99-main" = (genericNetwork mkDefault) // {
+          # We keep the "broken" behaviour of applying this to all interfaces.
+          # In general we want to get rid of this workaround but there hasn't
+          # been any work on that.
+          # See the following issues for details:
+          # - https://github.com/NixOS/nixpkgs/issues/18962
+          # - https://github.com/NixOS/nixpkgs/issues/61629
+          matchConfig = mkDefault { Name = "*"; };
+        };
       }
       (mkMerge (forEach interfaces (i: {
         netdevs = mkIf i.virtual ({
diff --git a/nixos/modules/virtualisation/cri-o.nix b/nixos/modules/virtualisation/cri-o.nix
new file mode 100644
index 000000000000..14a435f6c8bb
--- /dev/null
+++ b/nixos/modules/virtualisation/cri-o.nix
@@ -0,0 +1,106 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.virtualisation.cri-o;
+in
+{
+  options.virtualisation.cri-o = {
+    enable = mkEnableOption "Container Runtime Interface for OCI (CRI-O)";
+
+    storageDriver = mkOption {
+      type = types.enum ["btrfs" "overlay" "vfs"];
+      default = "overlay";
+      description = "Storage driver to be used";
+    };
+
+    logLevel = mkOption {
+      type = types.enum ["trace" "debug" "info" "warn" "error" "fatal"];
+      default = "info";
+      description = "Log level to be used";
+    };
+
+    pauseImage = mkOption {
+      type = types.str;
+      default = "k8s.gcr.io/pause:3.1";
+      description = "Pause image for pod sandboxes to be used";
+    };
+
+    pauseCommand = mkOption {
+      type = types.str;
+      default = "/pause";
+      description = "Pause command to be executed";
+    };
+
+    registries = mkOption {
+      type = types.listOf types.str;
+      default = [ "docker.io" "quay.io" ];
+      description = "Registries to be configured for unqualified image pull";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = with pkgs;
+      [ cri-o cri-tools conmon cni-plugins iptables runc utillinux ];
+    environment.etc."crictl.yaml".text = ''
+      runtime-endpoint: unix:///var/run/crio/crio.sock
+    '';
+    environment.etc."crio/crio.conf".text = ''
+      [crio]
+      storage_driver = "${cfg.storageDriver}"
+
+      [crio.image]
+      pause_image = "${cfg.pauseImage}"
+      pause_command = "${cfg.pauseCommand}"
+      registries = [
+        ${concatMapStringsSep ", " (x: "\"" + x + "\"") cfg.registries}
+      ]
+
+      [crio.runtime]
+      conmon = "${pkgs.conmon}/bin/conmon"
+      log_level = "${cfg.logLevel}"
+      manage_network_ns_lifecycle = true
+    '';
+    environment.etc."containers/policy.json".text = ''
+      {"default": [{"type": "insecureAcceptAnything"}]}
+    '';
+    environment.etc."cni/net.d/20-cri-o-bridge.conf".text = ''
+      {
+        "cniVersion": "0.3.1",
+        "name": "crio-bridge",
+        "type": "bridge",
+        "bridge": "cni0",
+        "isGateway": true,
+        "ipMasq": true,
+        "ipam": {
+          "type": "host-local",
+          "subnet": "10.88.0.0/16",
+          "routes": [
+              { "dst": "0.0.0.0/0" }
+          ]
+        }
+      }
+    '';
+
+    systemd.services.crio = {
+      description = "Container Runtime Interface for OCI (CRI-O)";
+      documentation = [ "https://github.com/cri-o/cri-o" ];
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      path = [ pkgs.utillinux pkgs.runc pkgs.iptables ];
+      serviceConfig = {
+        Type = "notify";
+        ExecStart = "${pkgs.cri-o}/bin/crio";
+        ExecReload = "/bin/kill -s HUP $MAINPID";
+        TasksMax = "infinity";
+        LimitNOFILE = "1048576";
+        LimitNPROC = "1048576";
+        LimitCORE = "infinity";
+        OOMScoreAdjust = "-999";
+        TimeoutStartSec = "0";
+        Restart = "on-abnormal";
+      };
+    };
+  };
+}
diff --git a/nixos/release.nix b/nixos/release.nix
index c7c609658909..a4b6b6bb91a8 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -292,6 +292,12 @@ in rec {
         services.xserver.desktopManager.xfce.enable = true;
       });
 
+    gnome3 = makeClosure ({ ... }:
+      { services.xserver.enable = true;
+        services.xserver.displayManager.gdm.enable = true;
+        services.xserver.desktopManager.gnome3.enable = true;
+      });
+
     # Linux/Apache/PostgreSQL/PHP stack.
     lapp = makeClosure ({ pkgs, ... }:
       { services.httpd.enable = true;
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 5eb8111aa6d3..5643da99e557 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -95,6 +95,7 @@ in
   gitlab = handleTest ./gitlab.nix {};
   gitolite = handleTest ./gitolite.nix {};
   gjs = handleTest ./gjs.nix {};
+  glib-networking = handleTest ./glib-networking.nix {};
   glusterfs = handleTest ./glusterfs.nix {};
   gnome3-xorg = handleTest ./gnome3-xorg.nix {};
   gnome3 = handleTest ./gnome3.nix {};
@@ -144,6 +145,7 @@ in
   latestKernel.login = handleTest ./login.nix { latestKernel = true; };
   ldap = handleTest ./ldap.nix {};
   leaps = handleTest ./leaps.nix {};
+  libgdata = handleTest ./libgdata.nix {};
   libxmlb = handleTest ./libxmlb.nix {};
   lidarr = handleTest ./lidarr.nix {};
   lightdm = handleTest ./lightdm.nix {};
@@ -160,6 +162,7 @@ in
   metabase = handleTest ./metabase.nix {};
   miniflux = handleTest ./miniflux.nix {};
   minio = handleTest ./minio.nix {};
+  minidlna = handleTest ./minidlna.nix {};
   misc = handleTest ./misc.nix {};
   mongodb = handleTest ./mongodb.nix {};
   moodle = handleTest ./moodle.nix {};
@@ -202,6 +205,7 @@ in
   # openstack-image-userdata doesn't work in a sandbox as the simulated openstack instance needs network access
   #openstack-image-userdata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).userdata or {};
   openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {};
+  os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
   osquery = handleTest ./osquery.nix {};
   osrm-backend = handleTest ./osrm-backend.nix {};
   ostree = handleTest ./ostree.nix {};
diff --git a/nixos/tests/glib-networking.nix b/nixos/tests/glib-networking.nix
new file mode 100644
index 000000000000..c0bbb2b3554b
--- /dev/null
+++ b/nixos/tests/glib-networking.nix
@@ -0,0 +1,17 @@
+# run installed tests
+import ./make-test.nix ({ pkgs, ... }:
+
+{
+  name = "glib-networking";
+  meta = {
+    maintainers = pkgs.glib-networking.meta.maintainers;
+  };
+
+  machine = { pkgs, ... }: {
+    environment.systemPackages = with pkgs; [ gnome-desktop-testing ];
+  };
+
+  testScript = ''
+    $machine->succeed("gnome-desktop-testing-runner -d '${pkgs.glib-networking.installedTests}/share'");
+  '';
+})
diff --git a/nixos/tests/hardened.nix b/nixos/tests/hardened.nix
index 90f9793b370c..cbf76f9e5587 100644
--- a/nixos/tests/hardened.nix
+++ b/nixos/tests/hardened.nix
@@ -10,6 +10,7 @@ import ./make-test.nix ({ pkgs, ...} : {
     { users.users.alice = { isNormalUser = true; extraGroups = [ "proc" ]; };
       users.users.sybil = { isNormalUser = true; group = "wheel"; };
       imports = [ ../modules/profiles/hardened.nix ];
+      environment.memoryAllocator.provider = "graphene-hardened";
       nix.useSandbox = false;
       virtualisation.emptyDiskImages = [ 4096 ];
       boot.initrd.postDeviceCommands = ''
diff --git a/nixos/tests/hydra/create-trivial-project.sh b/nixos/tests/hydra/create-trivial-project.sh
index 39122c9b473a..5aae2d5bf90d 100755
--- a/nixos/tests/hydra/create-trivial-project.sh
+++ b/nixos/tests/hydra/create-trivial-project.sh
@@ -44,6 +44,8 @@ cat >data.json <<EOF
   "enabled": "1",
   "visible": "1",
   "keepnr": "1",
+  "enableemail": true,
+  "emailoverride": "hydra@localhost",
   "nixexprinput": "trivial",
   "nixexprpath": "trivial.nix",
   "inputs": {
diff --git a/nixos/tests/hydra/default.nix b/nixos/tests/hydra/default.nix
index f99b367ac9b7..6ca05a2c7797 100644
--- a/nixos/tests/hydra/default.nix
+++ b/nixos/tests/hydra/default.nix
@@ -8,8 +8,10 @@ let
   trivialJob = pkgs.writeTextDir "trivial.nix" ''
    { trivial = builtins.derivation {
        name = "trivial";
-       system = "x86_64-linux";
+       system = "${system}";
        builder = "/bin/sh";
+       allowSubstitutes = false;
+       preferLocalBuild = true;
        args = ["-c" "echo success > $out; exit 0"];
      };
    }
@@ -53,11 +55,16 @@ let
               notificationSender = "example@example.com";
 
               package = pkgs.hydra.override { inherit nix; };
+
+              extraConfig = ''
+                email_notification = 1
+              '';
             };
+            services.postfix.enable = true;
             nix = {
               buildMachines = [{
                 hostName = "localhost";
-                systems = [ "x86_64-linux" ];
+                systems = [ system ];
               }];
 
               binaryCaches = [];
@@ -68,12 +75,12 @@ let
           # let the system boot up
           $machine->waitForUnit("multi-user.target");
           # test whether the database is running
-          $machine->succeed("systemctl status postgresql.service");
+          $machine->waitForUnit("postgresql.service");
           # test whether the actual hydra daemons are running
-          $machine->succeed("systemctl status hydra-queue-runner.service");
-          $machine->succeed("systemctl status hydra-init.service");
-          $machine->succeed("systemctl status hydra-evaluator.service");
-          $machine->succeed("systemctl status hydra-send-stats.service");
+          $machine->waitForUnit("hydra-init.service");
+          $machine->requireActiveUnit("hydra-queue-runner.service");
+          $machine->requireActiveUnit("hydra-evaluator.service");
+          $machine->requireActiveUnit("hydra-notify.service");
 
           $machine->succeed("hydra-create-user admin --role admin --password admin");
 
@@ -84,6 +91,8 @@ let
           $machine->succeed("create-trivial-project.sh");
 
           $machine->waitUntilSucceeds('curl -L -s http://localhost:3000/build/1 -H "Accept: application/json" |  jq .buildstatus | xargs test 0 -eq');
+
+          $machine->waitUntilSucceeds('journalctl -eu hydra-notify.service -o cat | grep -q "sending mail notification to hydra@localhost"');
         '';
       })));
 
diff --git a/nixos/tests/libgdata.nix b/nixos/tests/libgdata.nix
new file mode 100644
index 000000000000..10a3ca97dd22
--- /dev/null
+++ b/nixos/tests/libgdata.nix
@@ -0,0 +1,21 @@
+# run installed tests
+import ./make-test.nix ({ pkgs, ... }:
+
+{
+  name = "libgdata";
+
+  meta = {
+    maintainers = pkgs.libgdata.meta.maintainers;
+  };
+
+  machine = { pkgs, ... }: {
+    environment.systemPackages = with pkgs; [ gnome-desktop-testing ];
+    # # GLib-GIO-DEBUG: _g_io_module_get_default: Found default implementation dummy (GDummyTlsBackend) for ‘gio-tls-backend’
+    # Bail out! libgdata:ERROR:../gdata/tests/common.c:134:gdata_test_init: assertion failed (child_error == NULL): TLS support is not available (g-tls-error-quark, 0)
+    services.gnome3.glib-networking.enable = true;
+  };
+
+  testScript = ''
+    $machine->succeed("gnome-desktop-testing-runner -d '${pkgs.libgdata.installedTests}/share'");
+  '';
+})
diff --git a/nixos/tests/login.nix b/nixos/tests/login.nix
index 9844ad492e88..2a7c063d3033 100644
--- a/nixos/tests/login.nix
+++ b/nixos/tests/login.nix
@@ -9,6 +9,7 @@ import ./make-test.nix ({ pkgs, latestKernel ? false, ... }:
   machine =
     { pkgs, lib, ... }:
     { boot.kernelPackages = lib.mkIf latestKernel pkgs.linuxPackages_latest;
+      sound.enable = true; # needed for the factl test, /dev/snd/* exists without them but udev doesn't care then
     };
 
   testScript =
diff --git a/nixos/tests/minidlna.nix b/nixos/tests/minidlna.nix
new file mode 100644
index 000000000000..7bf1bed69d06
--- /dev/null
+++ b/nixos/tests/minidlna.nix
@@ -0,0 +1,39 @@
+import ./make-test.nix ({ pkgs, ... }: {
+  name = "minidlna";
+
+  nodes = {
+    server =
+      { ... }:
+      {
+        imports = [ ../modules/profiles/minimal.nix ];
+        networking.firewall.allowedTCPPorts = [ 8200 ];
+        services.minidlna = {
+          enable = true;
+          loglevel = "error";
+          mediaDirs = [
+           "PV,/tmp/stuff"
+          ];
+          friendlyName = "rpi3";
+          rootContainer = "B";
+          extraConfig =
+          ''
+            album_art_names=Cover.jpg/cover.jpg/AlbumArtSmall.jpg/albumartsmall.jpg
+            album_art_names=AlbumArt.jpg/albumart.jpg/Album.jpg/album.jpg
+            album_art_names=Folder.jpg/folder.jpg/Thumb.jpg/thumb.jpg
+            notify_interval=60
+          '';
+        };
+      };
+      client = { ... }: { };
+  };
+
+  testScript =
+  ''
+    startAll;
+    $server->succeed("mkdir -p /tmp/stuff && chown minidlna: /tmp/stuff");
+    $server->waitForUnit("minidlna");
+    $server->waitForOpenPort("8200");
+    $server->succeed("curl --fail http://localhost:8200/");
+    $client->succeed("curl --fail http://server:8200/");
+  '';
+})
diff --git a/nixos/tests/mumble.nix b/nixos/tests/mumble.nix
index dadd16fd9a0c..652d49a24b1c 100644
--- a/nixos/tests/mumble.nix
+++ b/nixos/tests/mumble.nix
@@ -63,8 +63,8 @@ in
     $client2->sendChars("y");
 
     # Find clients in logs
-    $server->waitUntilSucceeds("grep -q 'client1' /var/log/murmur/murmurd.log");
-    $server->waitUntilSucceeds("grep -q 'client2' /var/log/murmur/murmurd.log");
+    $server->waitUntilSucceeds("journalctl -eu murmur -o cat | grep -q client1");
+    $server->waitUntilSucceeds("journalctl -eu murmur -o cat | grep -q client2");
 
     $server->sleep(5); # wait to get screenshot
     $client1->screenshot("screen1");
diff --git a/nixos/tests/os-prober.nix b/nixos/tests/os-prober.nix
new file mode 100644
index 000000000000..9cd9f4ecd150
--- /dev/null
+++ b/nixos/tests/os-prober.nix
@@ -0,0 +1,119 @@
+import ./make-test.nix ({pkgs, lib, ...}:
+let
+  # A filesystem image with a (presumably) bootable debian
+  debianImage = pkgs.vmTools.diskImageFuns.debian9i386 {
+    # os-prober cannot detect systems installed on disks without a partition table
+    # so we create the disk ourselves
+    createRootFS = with pkgs; ''
+      ${parted}/bin/parted --script /dev/vda mklabel msdos
+      ${parted}/sbin/parted --script /dev/vda -- mkpart primary ext2 1M -1s
+      mkdir /mnt
+      ${e2fsprogs}/bin/mkfs.ext4 /dev/vda1
+      ${utillinux}/bin/mount -t ext4 /dev/vda1 /mnt
+
+      if test -e /mnt/.debug; then
+        exec ${bash}/bin/sh
+      fi
+      touch /mnt/.debug
+
+      mkdir /mnt/proc /mnt/dev /mnt/sys
+    '';
+    extraPackages = [
+      # /etc/os-release
+      "base-files"
+      # make the disk bootable-looking
+      "grub2" "linux-image-686"
+    ];
+    # install grub
+    postInstall = ''
+      ln -sf /proc/self/mounts > /etc/mtab
+      PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
+        grub-install /dev/vda --force
+      PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
+        update-grub
+    '';
+  };
+
+  # options to add the disk to the test vm
+  QEMU_OPTS = "-drive index=2,file=${debianImage}/disk-image.qcow2,read-only,if=virtio";
+
+  # a part of the configuration of the test vm
+  simpleConfig = {
+    boot.loader.grub = {
+      enable = true;
+      useOSProber = true;
+      device = "/dev/vda";
+      # vda is a filesystem without partition table
+      forceInstall = true;
+    };
+    nix.binaryCaches = lib.mkForce [ ];
+    nix.extraOptions = ''
+      hashed-mirrors =
+      connect-timeout = 1
+    '';
+    services.udisks2.enable = lib.mkForce false;
+  };
+  # /etc/nixos/configuration.nix for the vm
+  configFile = pkgs.writeText "configuration.nix"  ''
+    {config, pkgs, ...}: ({
+    imports = 
+          [ ./hardware-configuration.nix
+            <nixpkgs/nixos/modules/testing/test-instrumentation.nix>
+          ];
+    } // (builtins.fromJSON (builtins.readFile ${
+      pkgs.writeText "simpleConfig.json" (builtins.toJSON simpleConfig)
+    })))
+  '';
+in {
+  name = "os-prober";
+
+  machine = { config, pkgs, ... }: (simpleConfig // {
+      imports = [ ../modules/profiles/installation-device.nix
+                  ../modules/profiles/base.nix ];
+      virtualisation.memorySize = 1024;
+      # The test cannot access the network, so any packages
+      # nixos-rebuild needs must be included in the VM.
+      system.extraDependencies = with pkgs;
+        [ sudo
+          libxml2.bin
+          libxslt.bin
+          desktop-file-utils
+          docbook5
+          docbook_xsl_ns
+          unionfs-fuse
+          ntp
+          nixos-artwork.wallpapers.simple-dark-gray-bottom
+          perlPackages.XMLLibXML
+          perlPackages.ListCompare
+          shared-mime-info
+          texinfo
+          xorg.lndir
+          grub2
+
+          # add curl so that rather than seeing the test attempt to download
+          # curl's tarball, we see what it's trying to download
+          curl
+        ];
+  });
+
+  testScript = ''
+    # hack to add the secondary disk
+    $machine->{startCommand} = "QEMU_OPTS=\"\$QEMU_OPTS \"${lib.escapeShellArg QEMU_OPTS} ".$machine->{startCommand};
+
+    $machine->start;
+    $machine->succeed("udevadm settle");
+    $machine->waitForUnit("multi-user.target");
+
+    # check that os-prober works standalone
+    $machine->succeed("${pkgs.os-prober}/bin/os-prober | grep /dev/vdb1");
+
+    # rebuild and test that debian is available in the grub menu
+    $machine->succeed("nixos-generate-config");
+    $machine->copyFileFromHost(
+        "${configFile}",
+        "/etc/nixos/configuration.nix");
+    $machine->succeed("nixos-rebuild boot >&2");
+
+    $machine->succeed("egrep 'menuentry.*debian' /boot/grub/grub.cfg");
+  '';
+})
diff --git a/nixos/tests/plasma5.nix b/nixos/tests/plasma5.nix
index 788c8719c8d2..88d4ff334369 100644
--- a/nixos/tests/plasma5.nix
+++ b/nixos/tests/plasma5.nix
@@ -30,6 +30,7 @@ import ./make-test.nix ({ pkgs, ...} :
       enable = true;
       user = "alice";
     };
+    hardware.pulseaudio.enable = true; # needed for the factl test, /dev/snd/* exists without them but udev doesn't care then
     virtualisation.memorySize = 1024;
     environment.systemPackages = [ sddm_theme ];
   };
diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix
index 02d83f82f338..9826b56b74d7 100644
--- a/nixos/tests/prometheus-exporters.nix
+++ b/nixos/tests/prometheus-exporters.nix
@@ -297,6 +297,22 @@ let
       '';
     };
 
+    rspamd = {
+      exporterConfig = {
+        enable = true;
+      };
+      metricProvider = {
+        services.rspamd.enable = true;
+      };
+      exporterTest = ''
+        waitForUnit("rspamd.service");
+        waitForUnit("prometheus-rspamd-exporter.service");
+        waitForOpenPort(11334);
+        waitForOpenPort(7980);
+        waitUntilSucceeds("curl -sSf localhost:7980/metrics | grep -q 'rspamd_scanned{host=\"rspamd\"} 0'");
+      '';
+    };
+
     snmp = {
       exporterConfig = {
         enable = true;
diff --git a/nixos/tests/wordpress.nix b/nixos/tests/wordpress.nix
index 774ef6293b51..c6acfa6c1f3d 100644
--- a/nixos/tests/wordpress.nix
+++ b/nixos/tests/wordpress.nix
@@ -20,12 +20,6 @@ import ./make-test.nix ({ pkgs, ... }:
       };
 
       networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
-
-      # required for wordpress-init.service to succeed
-      systemd.tmpfiles.rules = [
-        "F /var/lib/wordpress/site1.local/secret-keys.php 0440 wordpress wwwrun - -"
-        "F /var/lib/wordpress/site2.local/secret-keys.php 0440 wordpress wwwrun - -"
-      ];
     };
 
   testScript = ''
@@ -37,6 +31,11 @@ import ./make-test.nix ({ pkgs, ... }:
 
     $machine->succeed("curl -L site1.local | grep 'Welcome to the famous'");
     $machine->succeed("curl -L site2.local | grep 'Welcome to the famous'");
+
+    $machine->succeed("systemctl --no-pager show wordpress-init-site1.local.service | grep 'ExecStart=.*status=0'");
+    $machine->succeed("systemctl --no-pager show wordpress-init-site2.local.service | grep 'ExecStart=.*status=0'");
+    $machine->succeed("grep -E '^define.*NONCE_SALT.{64,};\$' /var/lib/wordpress/site1.local/secret-keys.php");
+    $machine->succeed("grep -E '^define.*NONCE_SALT.{64,};\$' /var/lib/wordpress/site2.local/secret-keys.php");
   '';
 
 })
diff --git a/nixos/tests/xfce.nix b/nixos/tests/xfce.nix
index 12d8a050d47b..6cb4fae2021f 100644
--- a/nixos/tests/xfce.nix
+++ b/nixos/tests/xfce.nix
@@ -17,6 +17,10 @@ import ./make-test.nix ({ pkgs, ...} : {
       services.xserver.desktopManager.xfce.enable = true;
 
       environment.systemPackages = [ pkgs.xorg.xmessage ];
+
+      hardware.pulseaudio.enable = true; # needed for the factl test, /dev/snd/* exists without them but udev doesn't care then
+
+      virtualisation.memorySize = 1024;
     };
 
   testScript =
diff --git a/nixos/tests/xfce4-14.nix b/nixos/tests/xfce4-14.nix
index d9b10aabaa1f..94378f0c8d34 100644
--- a/nixos/tests/xfce4-14.nix
+++ b/nixos/tests/xfce4-14.nix
@@ -12,6 +12,10 @@ import ./make-test.nix ({ pkgs, ...} : {
       services.xserver.displayManager.auto.user = "alice";
 
       services.xserver.desktopManager.xfce4-14.enable = true;
+
+      hardware.pulseaudio.enable = true; # needed for the factl test, /dev/snd/* exists without them but udev doesn't care then
+  
+      virtualisation.memorySize = 1024;
     };
 
   testScript =
diff --git a/nixos/tests/xmonad.nix b/nixos/tests/xmonad.nix
index 4d3bc28cd349..79c15ccffecd 100644
--- a/nixos/tests/xmonad.nix
+++ b/nixos/tests/xmonad.nix
@@ -26,7 +26,7 @@ import ./make-test.nix ({ pkgs, ...} : {
     $machine->waitForFile("/home/alice/.Xauthority");
     $machine->succeed("xauth merge ~alice/.Xauthority");
     $machine->sendKeys("alt-ctrl-x");
-    $machine->waitForWindow(qr/machine.*alice/);
+    $machine->waitForWindow(qr/alice.*machine/);
     $machine->sleep(1);
     $machine->screenshot("terminal");
     $machine->waitUntilSucceeds("xmonad --restart");