summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/Makefile7
-rw-r--r--nixos/doc/manual/configuration/config-file.xml5
-rw-r--r--nixos/doc/manual/configuration/declarative-packages.xml9
-rw-r--r--nixos/doc/manual/configuration/kubernetes.xml127
-rw-r--r--nixos/doc/manual/configuration/matrix.xml134
-rw-r--r--nixos/doc/manual/configuration/modularity.xml16
-rw-r--r--nixos/doc/manual/configuration/profiles.xml6
-rw-r--r--nixos/doc/manual/configuration/profiles/all-hardware.xml9
-rw-r--r--nixos/doc/manual/configuration/profiles/base.xml12
-rw-r--r--nixos/doc/manual/configuration/profiles/clone-config.xml10
-rw-r--r--nixos/doc/manual/configuration/profiles/demo.xml10
-rw-r--r--nixos/doc/manual/configuration/profiles/docker-container.xml11
-rw-r--r--nixos/doc/manual/configuration/profiles/graphical.xml5
-rw-r--r--nixos/doc/manual/configuration/profiles/hardened.xml8
-rw-r--r--nixos/doc/manual/configuration/profiles/headless.xml7
-rw-r--r--nixos/doc/manual/configuration/profiles/installation-device.xml21
-rw-r--r--nixos/doc/manual/configuration/profiles/minimal.xml6
-rw-r--r--nixos/doc/manual/configuration/profiles/qemu-guest.xml2
-rw-r--r--nixos/doc/manual/configuration/wireless.xml10
-rw-r--r--nixos/doc/manual/configuration/x-windows.xml30
-rw-r--r--nixos/doc/manual/installation/installing-virtualbox-guest.xml8
-rw-r--r--nixos/doc/manual/man-nixos-generate-config.xml6
-rw-r--r--nixos/doc/manual/man-nixos-rebuild.xml72
-rw-r--r--nixos/doc/manual/release-notes/rl-1809.xml3
-rw-r--r--nixos/doc/manual/release-notes/rl-1903.xml657
-rw-r--r--nixos/doc/manual/release-notes/rl-1909.xml62
-rw-r--r--nixos/modules/config/ldap.nix89
-rw-r--r--nixos/modules/config/no-x-libs.nix2
-rw-r--r--nixos/modules/hardware/all-firmware.nix10
-rw-r--r--nixos/modules/hardware/logitech.nix28
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix14
-rw-r--r--nixos/modules/module-list.nix9
-rw-r--r--nixos/modules/programs/browserpass.nix33
-rw-r--r--nixos/modules/programs/gnupg.nix15
-rw-r--r--nixos/modules/programs/waybar.nix20
-rw-r--r--nixos/modules/programs/zsh/oh-my-zsh.xml6
-rw-r--r--nixos/modules/programs/zsh/zsh.nix37
-rw-r--r--nixos/modules/rename.nix74
-rw-r--r--nixos/modules/security/duosec.nix2
-rw-r--r--nixos/modules/security/pam.nix60
-rw-r--r--nixos/modules/security/systemd-confinement.nix199
-rw-r--r--nixos/modules/services/continuous-integration/buildbot/master.nix6
-rw-r--r--nixos/modules/services/continuous-integration/buildbot/worker.nix6
-rw-r--r--nixos/modules/services/databases/mysql.nix82
-rw-r--r--nixos/modules/services/databases/openldap.nix94
-rw-r--r--nixos/modules/services/databases/postgresql.nix1
-rw-r--r--nixos/modules/services/desktops/gsignond.nix2
-rw-r--r--nixos/modules/services/desktops/pantheon/contractor.nix2
-rw-r--r--nixos/modules/services/desktops/pantheon/files.nix2
-rw-r--r--nixos/modules/services/mail/davmail.nix32
-rw-r--r--nixos/modules/services/mail/mailcatcher.nix60
-rw-r--r--nixos/modules/services/misc/docker-registry.nix23
-rw-r--r--nixos/modules/services/misc/gitlab.nix40
-rw-r--r--nixos/modules/services/misc/plex.nix2
-rw-r--r--nixos/modules/services/networking/firewall.nix13
-rw-r--r--nixos/modules/services/networking/quicktun.nix118
-rw-r--r--nixos/modules/services/scheduling/cron.nix4
-rw-r--r--nixos/modules/services/search/elasticsearch-curator.nix2
-rw-r--r--nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix599
-rw-r--r--nixos/modules/services/web-apps/matomo-doc.xml33
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix6
-rw-r--r--nixos/modules/services/web-apps/nextcloud.xml84
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix5
-rw-r--r--nixos/modules/services/web-servers/meguca.nix20
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix17
-rw-r--r--nixos/modules/services/web-servers/nginx/location-options.nix9
-rw-r--r--nixos/modules/services/web-servers/unit/default.nix125
-rw-r--r--nixos/modules/services/x11/colord.nix19
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix3
-rw-r--r--nixos/modules/services/x11/window-managers/dwm.nix2
-rw-r--r--nixos/modules/services/x11/xserver.nix7
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix35
-rw-r--r--nixos/modules/system/boot/systemd-lib.nix9
-rw-r--r--nixos/modules/tasks/filesystems.nix7
-rw-r--r--nixos/modules/virtualisation/anbox.nix144
-rw-r--r--nixos/modules/virtualisation/containers.nix14
-rw-r--r--nixos/modules/virtualisation/docker-containers.nix233
-rw-r--r--nixos/modules/virtualisation/openstack-config.nix1
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix1
-rw-r--r--nixos/release-combined.nix1
-rw-r--r--nixos/release-small.nix1
-rw-r--r--nixos/tests/all-tests.nix8
-rw-r--r--nixos/tests/buildbot.nix205
-rw-r--r--nixos/tests/common/letsencrypt/default.nix2
-rw-r--r--nixos/tests/common/webroot/news-rss.xml26
-rw-r--r--nixos/tests/docker-containers.nix29
-rw-r--r--nixos/tests/docker-tools.nix4
-rw-r--r--nixos/tests/home-assistant.nix6
-rw-r--r--nixos/tests/kafka.nix1
-rw-r--r--nixos/tests/kernel-testing.nix17
-rw-r--r--nixos/tests/ldap.nix9
-rw-r--r--nixos/tests/mailcatcher.nix26
-rw-r--r--nixos/tests/minio.nix29
-rw-r--r--nixos/tests/mysql.nix28
-rw-r--r--nixos/tests/openldap.nix14
-rw-r--r--nixos/tests/pdns-recursor.nix12
-rw-r--r--nixos/tests/predictable-interface-names.nix3
-rw-r--r--nixos/tests/slurm.nix3
-rw-r--r--nixos/tests/systemd-confinement.nix168
-rw-r--r--nixos/tests/wireguard/default.nix97
-rw-r--r--nixos/tests/wireguard/snakeoil-keys.nix11
101 files changed, 2909 insertions, 1504 deletions
diff --git a/nixos/doc/manual/Makefile b/nixos/doc/manual/Makefile
index b251a1f5e2c..9ff599a0090 100644
--- a/nixos/doc/manual/Makefile
+++ b/nixos/doc/manual/Makefile
@@ -6,13 +6,14 @@ debug: generated manual-combined.xml
 
 manual-combined.xml: generated *.xml **/*.xml
 	rm -f ./manual-combined.xml
-	nix-shell --packages xmloscopy \
+	nix-shell --pure -Q --packages xmloscopy \
 		--run "xmloscopy --docbook5 ./manual.xml ./manual-combined.xml"
 
 .PHONY: format
 format:
-	find ../../ -iname '*.xml' -type f -print0 | xargs -0 -I{} -n1 \
-		xmlformat --config-file "../xmlformat.conf" -i {}
+	nix-shell --pure -Q --packages xmlformat \
+		--run "find ../../ -iname '*.xml' -type f -print0 | xargs -0 -I{} -n1 \
+		xmlformat --config-file '../xmlformat.conf' -i {}"
 
 .PHONY: fix-misc-xml
 fix-misc-xml:
diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml
index c77cfe137ba..eadafb94b8f 100644
--- a/nixos/doc/manual/configuration/config-file.xml
+++ b/nixos/doc/manual/configuration/config-file.xml
@@ -200,8 +200,9 @@ swapDevices = [ { device = "/dev/disk/by-label/swap"; } ];
 <xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql_10;
 </programlisting>
       The latter option definition changes the default PostgreSQL package used
-      by NixOS’s PostgreSQL service to 10.x. For more information on packages,
-      including how to add new ones, see <xref linkend="sec-custom-packages"/>.
+      by NixOS’s PostgreSQL service to 10.x. For more information on
+      packages, including how to add new ones, see
+      <xref linkend="sec-custom-packages"/>.
      </para>
     </listitem>
    </varlistentry>
diff --git a/nixos/doc/manual/configuration/declarative-packages.xml b/nixos/doc/manual/configuration/declarative-packages.xml
index be9884fe9dc..c9acbefea60 100644
--- a/nixos/doc/manual/configuration/declarative-packages.xml
+++ b/nixos/doc/manual/configuration/declarative-packages.xml
@@ -27,8 +27,13 @@ nixos.firefox   firefox-23.0   Mozilla Firefox - the browser, reloaded
 <replaceable>...</replaceable>
 </screen>
   The first column in the output is the <emphasis>attribute name</emphasis>,
-  such as <literal>nixos.thunderbird</literal>. (The <literal>nixos</literal>
-  prefix allows distinguishing between different channels that you might have.)
+  such as <literal>nixos.thunderbird</literal>.
+ </para>
+ <para>
+  Note: the <literal>nixos</literal> prefix tells us that we want to get the
+  package from the <literal>nixos</literal> channel and works only in CLI tools.
+
+  In declarative configuration use <literal>pkgs</literal> prefix (variable).
  </para>
 
  <para>
diff --git a/nixos/doc/manual/configuration/kubernetes.xml b/nixos/doc/manual/configuration/kubernetes.xml
index ddc026c0c01..54a100e4479 100644
--- a/nixos/doc/manual/configuration/kubernetes.xml
+++ b/nixos/doc/manual/configuration/kubernetes.xml
@@ -4,15 +4,13 @@
          version="5.0"
          xml:id="sec-kubernetes">
  <title>Kubernetes</title>
-
  <para>
-   The NixOS Kubernetes module is a collective term for a handful of
-   individual submodules implementing the Kubernetes cluster components.
+  The NixOS Kubernetes module is a collective term for a handful of individual
+  submodules implementing the Kubernetes cluster components.
  </para>
-
  <para>
-   There are generally two ways of enabling Kubernetes on NixOS.
-   One way is to enable and configure cluster components appropriately by hand:
+  There are generally two ways of enabling Kubernetes on NixOS. One way is to
+  enable and configure cluster components appropriately by hand:
 <programlisting>
 services.kubernetes = {
   apiserver.enable = true;
@@ -33,95 +31,82 @@ services.kubernetes = {
 <programlisting>
 <xref linkend="opt-services.kubernetes.roles"/> = [ "node" ];
 </programlisting>
-  Assigning both the master and node roles is usable if you want a single
-  node Kubernetes cluster for dev or testing purposes:
+  Assigning both the master and node roles is usable if you want a single node
+  Kubernetes cluster for dev or testing purposes:
 <programlisting>
 <xref linkend="opt-services.kubernetes.roles"/> = [ "master" "node" ];
 </programlisting>
   Note: Assigning either role will also default both
   <xref linkend="opt-services.kubernetes.flannel.enable"/> and
-  <xref linkend="opt-services.kubernetes.easyCerts"/> to true.
-  This sets up flannel as CNI and activates automatic PKI bootstrapping.
+  <xref linkend="opt-services.kubernetes.easyCerts"/> to true. This sets up
+  flannel as CNI and activates automatic PKI bootstrapping.
  </para>
-
  <para>
-   As of kubernetes 1.10.X it has been deprecated to open
-   non-tls-enabled ports on kubernetes components. Thus, from NixOS 19.03 all
-   plain HTTP ports have been disabled by default.
-   While opening insecure ports is still possible, it is recommended not to
-   bind these to other interfaces than loopback.
-
-   To re-enable the insecure port on the apiserver, see options:
-   <xref linkend="opt-services.kubernetes.apiserver.insecurePort"/>
-   and
-   <xref linkend="opt-services.kubernetes.apiserver.insecureBindAddress"/>
+  As of kubernetes 1.10.X it has been deprecated to open non-tls-enabled ports
+  on kubernetes components. Thus, from NixOS 19.03 all plain HTTP ports have
+  been disabled by default. While opening insecure ports is still possible, it
+  is recommended not to bind these to other interfaces than loopback. To
+  re-enable the insecure port on the apiserver, see options:
+  <xref linkend="opt-services.kubernetes.apiserver.insecurePort"/> and
+  <xref linkend="opt-services.kubernetes.apiserver.insecureBindAddress"/>
  </para>
-
  <note>
   <para>
    As of NixOS 19.03, it is mandatory to configure:
-   <xref linkend="opt-services.kubernetes.masterAddress"/>.
-   The masterAddress must be resolveable and routeable by all cluster nodes.
-   In single node clusters, this can be set to <literal>localhost</literal>.
+   <xref linkend="opt-services.kubernetes.masterAddress"/>. The masterAddress
+   must be resolveable and routeable by all cluster nodes. In single node
+   clusters, this can be set to <literal>localhost</literal>.
   </para>
  </note>
-
  <para>
-   Role-based access control (RBAC) authorization mode is enabled by default.
-   This means that anonymous requests to the apiserver secure port will
-   expectedly cause a permission denied error. All cluster components must
-   therefore be configured with x509 certificates for two-way tls communication.
-   The x509 certificate subject section determines the roles and permissions
-   granted by the apiserver to perform clusterwide or namespaced operations.
-   See also:
-   <link
+  Role-based access control (RBAC) authorization mode is enabled by default.
+  This means that anonymous requests to the apiserver secure port will
+  expectedly cause a permission denied error. All cluster components must
+  therefore be configured with x509 certificates for two-way tls communication.
+  The x509 certificate subject section determines the roles and permissions
+  granted by the apiserver to perform clusterwide or namespaced operations. See
+  also:
+  <link
      xlink:href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/">
-     Using RBAC Authorization</link>.
+  Using RBAC Authorization</link>.
  </para>
-
-  <para>
-   The NixOS kubernetes module provides an option for automatic certificate
-   bootstrapping and configuration,
-    <xref linkend="opt-services.kubernetes.easyCerts"/>.
-   The PKI bootstrapping process involves setting up a certificate authority
-   (CA) daemon (cfssl) on the kubernetes master node. cfssl generates a CA-cert
-   for the cluster, and uses the CA-cert for signing subordinate certs issued to
-   each of the cluster components. Subsequently, the certmgr daemon monitors
-   active certificates and renews them when needed. For single node Kubernetes
-   clusters, setting <xref linkend="opt-services.kubernetes.easyCerts"/> = true
-   is sufficient and no further action is required. For joining extra node
-   machines to an existing cluster on the other hand, establishing initial trust
-   is mandatory.
+ <para>
+  The NixOS kubernetes module provides an option for automatic certificate
+  bootstrapping and configuration,
+  <xref linkend="opt-services.kubernetes.easyCerts"/>. The PKI bootstrapping
+  process involves setting up a certificate authority (CA) daemon (cfssl) on
+  the kubernetes master node. cfssl generates a CA-cert for the cluster, and
+  uses the CA-cert for signing subordinate certs issued to each of the cluster
+  components. Subsequently, the certmgr daemon monitors active certificates and
+  renews them when needed. For single node Kubernetes clusters, setting
+  <xref linkend="opt-services.kubernetes.easyCerts"/> = true is sufficient and
+  no further action is required. For joining extra node machines to an existing
+  cluster on the other hand, establishing initial trust is mandatory.
  </para>
-
  <para>
-   To add new nodes to the cluster:
-   On any (non-master) cluster node where
-   <xref linkend="opt-services.kubernetes.easyCerts"/> is enabled, the helper
-   script <literal>nixos-kubernetes-node-join</literal> is available on PATH.
-   Given a token on stdin, it will copy the token to the kubernetes
-   secrets directory and restart the certmgr service. As requested
-   certificates are issued, the script will restart kubernetes cluster
-   components as needed for them to pick up new keypairs.
+  To add new nodes to the cluster: On any (non-master) cluster node where
+  <xref linkend="opt-services.kubernetes.easyCerts"/> is enabled, the helper
+  script <literal>nixos-kubernetes-node-join</literal> is available on PATH.
+  Given a token on stdin, it will copy the token to the kubernetes secrets
+  directory and restart the certmgr service. As requested certificates are
+  issued, the script will restart kubernetes cluster components as needed for
+  them to pick up new keypairs.
  </para>
-
  <note>
   <para>
    Multi-master (HA) clusters are not supported by the easyCerts module.
   </para>
  </note>
-
  <para>
-   In order to interact with an RBAC-enabled cluster as an administrator, one
-   needs to have cluster-admin privileges. By default, when easyCerts is
-   enabled, a cluster-admin kubeconfig file is generated and linked into
-   <literal>/etc/kubernetes/cluster-admin.kubeconfig</literal> as determined by
-   <xref linkend="opt-services.kubernetes.pki.etcClusterAdminKubeconfig"/>.
-   <literal>export KUBECONFIG=/etc/kubernetes/cluster-admin.kubeconfig</literal>
-   will make kubectl use this kubeconfig to access and authenticate the cluster.
-   The cluster-admin kubeconfig references an auto-generated keypair owned by
-   root. Thus, only root on the kubernetes master may obtain cluster-admin
-   rights by means of this file.
+  In order to interact with an RBAC-enabled cluster as an administrator, one
+  needs to have cluster-admin privileges. By default, when easyCerts is
+  enabled, a cluster-admin kubeconfig file is generated and linked into
+  <literal>/etc/kubernetes/cluster-admin.kubeconfig</literal> as determined by
+  <xref linkend="opt-services.kubernetes.pki.etcClusterAdminKubeconfig"/>.
+  <literal>export KUBECONFIG=/etc/kubernetes/cluster-admin.kubeconfig</literal>
+  will make kubectl use this kubeconfig to access and authenticate the cluster.
+  The cluster-admin kubeconfig references an auto-generated keypair owned by
+  root. Thus, only root on the kubernetes master may obtain cluster-admin
+  rights by means of this file.
  </para>
-
 </chapter>
diff --git a/nixos/doc/manual/configuration/matrix.xml b/nixos/doc/manual/configuration/matrix.xml
index a9a5d6de1f1..66965460a15 100644
--- a/nixos/doc/manual/configuration/matrix.xml
+++ b/nixos/doc/manual/configuration/matrix.xml
@@ -5,31 +5,34 @@
          xml:id="module-services-matrix">
  <title>Matrix</title>
  <para>
-  <link xlink:href="https://matrix.org/">Matrix</link>
-  is an open standard for interoperable, decentralised, real-time communication over IP.
-  It can be used to power Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication -
-  or anywhere you need a standard HTTP API for publishing and subscribing to data whilst tracking the conversation history.
+  <link xlink:href="https://matrix.org/">Matrix</link> is an open standard for
+  interoperable, decentralised, real-time communication over IP. It can be used
+  to power Instant Messaging, VoIP/WebRTC signalling, Internet of Things
+  communication - or anywhere you need a standard HTTP API for publishing and
+  subscribing to data whilst tracking the conversation history.
  </para>
  <para>
-  This chapter will show you how to set up your own, self-hosted Matrix homeserver using the Synapse reference homeserver,
-  and how to serve your own copy of the Riot web client.
-  See the <link xlink:href="https://matrix.org/docs/projects/try-matrix-now.html">Try Matrix Now!</link>
-  overview page for links to Riot Apps for Android and iOS, desktop clients,
-  as well as bridges to other networks and other projects around Matrix.
+  This chapter will show you how to set up your own, self-hosted Matrix
+  homeserver using the Synapse reference homeserver, and how to serve your own
+  copy of the Riot web client. See the
+  <link xlink:href="https://matrix.org/docs/projects/try-matrix-now.html">Try
+  Matrix Now!</link> overview page for links to Riot Apps for Android and iOS,
+  desktop clients, as well as bridges to other networks and other projects
+  around Matrix.
  </para>
-
  <section xml:id="module-services-matrix-synapse">
   <title>Synapse Homeserver</title>
+
   <para>
-   <link xlink:href="https://github.com/matrix-org/synapse">Synapse</link>
-   is the reference homeserver implementation of Matrix from the core development team at matrix.org.
-   The following configuration example will set up a synapse server for the <literal>example.org</literal>
-   domain, served from the host <literal>myhostname.example.org</literal>.
-   For more information, please refer to the
+   <link xlink:href="https://github.com/matrix-org/synapse">Synapse</link> is
+   the reference homeserver implementation of Matrix from the core development
+   team at matrix.org. The following configuration example will set up a
+   synapse server for the <literal>example.org</literal> domain, served from
+   the host <literal>myhostname.example.org</literal>. For more information,
+   please refer to the
    <link xlink:href="https://github.com/matrix-org/synapse#synapse-installation">
-    installation instructions of Synapse
-   </link>.
-   <programlisting>
+   installation instructions of Synapse </link>.
+<programlisting>
     let
       fqdn =
         let
@@ -116,28 +119,29 @@
     };
    </programlisting>
   </para>
+
   <para>
-   If the <code>A</code> and <code>AAAA</code> DNS records on <literal>example.org</literal>
-   do not point on the same host as the records for <code>myhostname.example.org</code>,
-   you can easily move the <code>/.well-known</code> virtualHost section of the code
-   to the host that is serving <literal>example.org</literal>,
-   while the rest stays on <literal>myhostname.example.org</literal>
-   with no other changes required.
-   This pattern also allows to seamlessly move the homeserver from <literal>myhostname.example.org</literal>
-   to <literal>myotherhost.example.org</literal> by only changing the <code>/.well-known</code> redirection target.
+   If the <code>A</code> and <code>AAAA</code> DNS records on
+   <literal>example.org</literal> do not point on the same host as the records
+   for <code>myhostname.example.org</code>, you can easily move the
+   <code>/.well-known</code> virtualHost section of the code to the host that
+   is serving <literal>example.org</literal>, while the rest stays on
+   <literal>myhostname.example.org</literal> with no other changes required.
+   This pattern also allows to seamlessly move the homeserver from
+   <literal>myhostname.example.org</literal> to
+   <literal>myotherhost.example.org</literal> by only changing the
+   <code>/.well-known</code> redirection target.
   </para>
 
   <para>
-   If you want to run a server with public registration by anybody,
-   you can then enable
-   <option>services.matrix-synapse.enable_registration = true;</option>.
-   Otherwise, or you can generate a registration secret with <command>pwgen -s 64 1</command>
-   and set it with
-   <option>services.matrix-synapse.registration_shared_secret</option>.
-   To create a new user or admin,
-   run the following after you have set the secret and have rebuilt NixOS:
-
-   <programlisting>
+   If you want to run a server with public registration by anybody, you can
+   then enable <option>services.matrix-synapse.enable_registration =
+   true;</option>. Otherwise, or you can generate a registration secret with
+   <command>pwgen -s 64 1</command> and set it with
+   <option>services.matrix-synapse.registration_shared_secret</option>. To
+   create a new user or admin, run the following after you have set the secret
+   and have rebuilt NixOS:
+<programlisting>
     $ nix run nixpkgs.matrix-synapse
     $ register_new_matrix_user -k &lt;your-registration-shared-secret&gt; http://localhost:8008
     New user localpart: &lt;your-username&gt;
@@ -147,31 +151,32 @@
     Success!
    </programlisting>
    In the example, this would create a user with the Matrix Identifier
-   <literal>@your-username:example.org</literal>.
-   Note that the registration secret ends up in the nix store and therefore is world-readable
-   by any user on your machine, so it makes sense to only temporarily activate the
-   <option>registration_shared_secret</option> option until a better solution for NixOS is in place.
+   <literal>@your-username:example.org</literal>. Note that the registration
+   secret ends up in the nix store and therefore is world-readable by any user
+   on your machine, so it makes sense to only temporarily activate the
+   <option>registration_shared_secret</option> option until a better solution
+   for NixOS is in place.
   </para>
  </section>
-
  <section xml:id="module-services-matrix-riot-web">
   <title>Riot Web Client</title>
-  <para>
-   <link xlink:href="https://github.com/vector-im/riot-web/">Riot Web</link>
-   is the reference web client for Matrix and developed by the core team at matrix.org.
-   The following snippet can be optionally added to the code before to complete the synapse
-   installation with a web client served at
-   <code>https://riot.myhostname.example.org</code> and <code>https://riot.example.org</code>.
-   Alternatively, you can use the hosted copy at
-   <link xlink:href="https://riot.im/app">https://riot.im/app</link>,
-   or use other web clients or native client applications.
-   Due to the <literal>/.well-known</literal> urls set up done above,
-   many clients should fill in the required connection details automatically
-   when you enter your Matrix Identifier.
-   See <link xlink:href="https://matrix.org/docs/projects/try-matrix-now.html">Try Matrix Now!</link>
-   for a list of existing clients and their supported featureset.
 
-   <programlisting>
+  <para>
+   <link xlink:href="https://github.com/vector-im/riot-web/">Riot Web</link> is
+   the reference web client for Matrix and developed by the core team at
+   matrix.org. The following snippet can be optionally added to the code before
+   to complete the synapse installation with a web client served at
+   <code>https://riot.myhostname.example.org</code> and
+   <code>https://riot.example.org</code>. Alternatively, you can use the hosted
+   copy at <link xlink:href="https://riot.im/app">https://riot.im/app</link>,
+   or use other web clients or native client applications. Due to the
+   <literal>/.well-known</literal> urls set up done above, many clients should
+   fill in the required connection details automatically when you enter your
+   Matrix Identifier. See
+   <link xlink:href="https://matrix.org/docs/projects/try-matrix-now.html">Try
+   Matrix Now!</link> for a list of existing clients and their supported
+   featureset.
+<programlisting>
      services.nginx.virtualHosts."riot.${fqdn}" = {
        enableACME = true;
        forceSSL = true;
@@ -183,15 +188,16 @@
      };
    </programlisting>
   </para>
+
   <para>
-   Note that the Riot developers do not recommend running Riot and your Matrix homeserver
-   on the same fully-qualified domain name for security reasons.
-   In the example, this means that you should not reuse the <literal>myhostname.example.org</literal>
-   virtualHost to also serve Riot, but instead serve it on a different subdomain,
-   like <literal>riot.example.org</literal> in the example.
-   See the
-   <link xlink:href="https://github.com/vector-im/riot-web#important-security-note">Riot Important Security Notes</link>
-   for more information on this subject.
+   Note that the Riot developers do not recommend running Riot and your Matrix
+   homeserver on the same fully-qualified domain name for security reasons. In
+   the example, this means that you should not reuse the
+   <literal>myhostname.example.org</literal> virtualHost to also serve Riot,
+   but instead serve it on a different subdomain, like
+   <literal>riot.example.org</literal> in the example. See the
+   <link xlink:href="https://github.com/vector-im/riot-web#important-security-note">Riot
+   Important Security Notes</link> for more information on this subject.
   </para>
  </section>
 </chapter>
diff --git a/nixos/doc/manual/configuration/modularity.xml b/nixos/doc/manual/configuration/modularity.xml
index 5ff5bc22c85..724abd31ca4 100644
--- a/nixos/doc/manual/configuration/modularity.xml
+++ b/nixos/doc/manual/configuration/modularity.xml
@@ -112,9 +112,8 @@ true
 $ nixos-option <xref linkend="opt-boot.kernelModules"/>
 [ "tun" "ipv6" "loop" <replaceable>...</replaceable> ]
 </screen>
-  Interactive exploration of the configuration is possible using
-  <command>nix repl</command>, a read-eval-print loop for Nix expressions.
-  A typical use:
+  Interactive exploration of the configuration is possible using <command>nix
+  repl</command>, a read-eval-print loop for Nix expressions. A typical use:
 <screen>
 $ nix repl '&lt;nixpkgs/nixos>'
 
@@ -127,11 +126,10 @@ nix-repl> map (x: x.hostName) config.<xref linkend="opt-services.httpd.virtualHo
  </para>
 
  <para>
-   While abstracting your configuration, you may find it useful to generate
-   modules using code, instead of writing files. The example
-   below would have the same effect as importing a file which sets those
-   options.
-   <screen>
+  While abstracting your configuration, you may find it useful to generate
+  modules using code, instead of writing files. The example below would have
+  the same effect as importing a file which sets those options.
+<screen>
      { config, pkgs, ... }:
 
      let netConfig = { hostName }: {
@@ -143,5 +141,5 @@ nix-repl> map (x: x.hostName) config.<xref linkend="opt-services.httpd.virtualHo
 
     { imports = [ (netConfig "nixos.localdomain") ]; }
   </screen>
-</para>
+ </para>
 </section>
diff --git a/nixos/doc/manual/configuration/profiles.xml b/nixos/doc/manual/configuration/profiles.xml
index 92c0f6202f2..c0a8f55785f 100644
--- a/nixos/doc/manual/configuration/profiles.xml
+++ b/nixos/doc/manual/configuration/profiles.xml
@@ -12,14 +12,14 @@
   That is to say, expected usage is to add them to the imports list of your
   <filename>/etc/configuration.nix</filename> as such:
  </para>
- <programlisting>
+<programlisting>
   imports = [
    &lt;nixpkgs/nixos/modules/profiles/profile-name.nix&gt;
   ];
  </programlisting>
  <para>
-  Even if some of these profiles seem only useful in the context of
-  install media, many are actually intended to be used in real installs.
+  Even if some of these profiles seem only useful in the context of install
+  media, many are actually intended to be used in real installs.
  </para>
  <para>
   What follows is a brief explanation on the purpose and use-case for each
diff --git a/nixos/doc/manual/configuration/profiles/all-hardware.xml b/nixos/doc/manual/configuration/profiles/all-hardware.xml
index 17297519947..2936f71069d 100644
--- a/nixos/doc/manual/configuration/profiles/all-hardware.xml
+++ b/nixos/doc/manual/configuration/profiles/all-hardware.xml
@@ -1,15 +1,16 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-all-hardware">
  <title>All Hardware</title>
+
  <para>
-  Enables all hardware supported by NixOS: i.e., all firmware is
-  included, and all devices from which one may boot are enabled in the initrd.
-  Its primary use is in the NixOS installation CDs.
+  Enables all hardware supported by NixOS: i.e., all firmware is included, and
+  all devices from which one may boot are enabled in the initrd. Its primary
+  use is in the NixOS installation CDs.
  </para>
+
  <para>
   The enabled kernel modules include support for SATA and PATA, SCSI
   (partially), USB, Firewire (untested), Virtio (QEMU, KVM, etc.), VMware, and
diff --git a/nixos/doc/manual/configuration/profiles/base.xml b/nixos/doc/manual/configuration/profiles/base.xml
index f58a35d626e..b75f6ba25b4 100644
--- a/nixos/doc/manual/configuration/profiles/base.xml
+++ b/nixos/doc/manual/configuration/profiles/base.xml
@@ -1,15 +1,15 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-base">
  <title>Base</title>
+
  <para>
-  Defines the software packages included in the "minimal"
-  installation CD. It installs several utilities useful in a simple recovery or
-  install media, such as a text-mode web browser, and tools for manipulating
-  block devices, networking, hardware diagnostics, and filesystems (with their
-  respective kernel modules).
+  Defines the software packages included in the "minimal" installation CD. It
+  installs several utilities useful in a simple recovery or install media, such
+  as a text-mode web browser, and tools for manipulating block devices,
+  networking, hardware diagnostics, and filesystems (with their respective
+  kernel modules).
  </para>
 </section>
diff --git a/nixos/doc/manual/configuration/profiles/clone-config.xml b/nixos/doc/manual/configuration/profiles/clone-config.xml
index 87c8b9ee31b..234835845e2 100644
--- a/nixos/doc/manual/configuration/profiles/clone-config.xml
+++ b/nixos/doc/manual/configuration/profiles/clone-config.xml
@@ -1,14 +1,14 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-clone-config">
  <title>Clone Config</title>
+
  <para>
-  This profile is used in installer images.
-  It provides an editable configuration.nix that imports all the modules that
-  were also used when creating the image in the first place.
-  As a result it allows users to edit and rebuild the live-system.
+  This profile is used in installer images. It provides an editable
+  configuration.nix that imports all the modules that were also used when
+  creating the image in the first place. As a result it allows users to edit
+  and rebuild the live-system.
  </para>
 </section>
diff --git a/nixos/doc/manual/configuration/profiles/demo.xml b/nixos/doc/manual/configuration/profiles/demo.xml
index 98829e4696d..395a5ec357c 100644
--- a/nixos/doc/manual/configuration/profiles/demo.xml
+++ b/nixos/doc/manual/configuration/profiles/demo.xml
@@ -1,13 +1,15 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-demo">
  <title>Demo</title>
+
  <para>
-  This profile just enables a <systemitem class="username">demo</systemitem> user, with password <literal>demo</literal>, uid <literal>1000</literal>, <systemitem class="groupname">wheel</systemitem>
-  group and <link linkend="opt-services.xserver.displayManager.sddm.autoLogin">
-   autologin in the SDDM display manager</link>.
+  This profile just enables a <systemitem class="username">demo</systemitem>
+  user, with password <literal>demo</literal>, uid <literal>1000</literal>,
+  <systemitem class="groupname">wheel</systemitem> group and
+  <link linkend="opt-services.xserver.displayManager.sddm.autoLogin"> autologin
+  in the SDDM display manager</link>.
  </para>
 </section>
diff --git a/nixos/doc/manual/configuration/profiles/docker-container.xml b/nixos/doc/manual/configuration/profiles/docker-container.xml
index bf962442cce..efa7b8f24c4 100644
--- a/nixos/doc/manual/configuration/profiles/docker-container.xml
+++ b/nixos/doc/manual/configuration/profiles/docker-container.xml
@@ -1,15 +1,16 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-docker-container">
  <title>Docker Container</title>
+
  <para>
   This is the profile from which the Docker images are generated. It prepares a
-  working system by importing the <link linkend="sec-profile-minimal">Minimal</link> and
-  <link linkend="sec-profile-clone-config">Clone Config</link> profiles, and setting appropriate
-  configuration options that are useful inside a container context, like
-  <xref linkend="opt-boot.isContainer"/>.
+  working system by importing the
+  <link linkend="sec-profile-minimal">Minimal</link> and
+  <link linkend="sec-profile-clone-config">Clone Config</link> profiles, and
+  setting appropriate configuration options that are useful inside a container
+  context, like <xref linkend="opt-boot.isContainer"/>.
  </para>
 </section>
diff --git a/nixos/doc/manual/configuration/profiles/graphical.xml b/nixos/doc/manual/configuration/profiles/graphical.xml
index 5ded61d9763..73e3abc59d0 100644
--- a/nixos/doc/manual/configuration/profiles/graphical.xml
+++ b/nixos/doc/manual/configuration/profiles/graphical.xml
@@ -1,20 +1,21 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-graphical">
  <title>Graphical</title>
+
  <para>
   Defines a NixOS configuration with the Plasma 5 desktop. It's used by the
   graphical installation CD.
  </para>
+
  <para>
   It sets <xref linkend="opt-services.xserver.enable"/>,
   <xref linkend="opt-services.xserver.displayManager.sddm.enable"/>,
   <xref linkend="opt-services.xserver.desktopManager.plasma5.enable"/> (
   <link linkend="opt-services.xserver.desktopManager.plasma5.enableQt4Support">
-   without Qt4 Support</link>), and
+  without Qt4 Support</link>), and
   <xref linkend="opt-services.xserver.libinput.enable"/> to true. It also
   includes glxinfo and firefox in the system packages list.
  </para>
diff --git a/nixos/doc/manual/configuration/profiles/hardened.xml b/nixos/doc/manual/configuration/profiles/hardened.xml
index b3b433792f5..dc83fc837e2 100644
--- a/nixos/doc/manual/configuration/profiles/hardened.xml
+++ b/nixos/doc/manual/configuration/profiles/hardened.xml
@@ -1,22 +1,24 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-hardened">
  <title>Hardened</title>
+
  <para>
   A profile with most (vanilla) hardening options enabled by default,
   potentially at the cost of features and performance.
  </para>
+
  <para>
   This includes a hardened kernel, and limiting the system information
   available to processes through the <filename>/sys</filename> and
   <filename>/proc</filename> filesystems. It also disables the User Namespaces
   feature of the kernel, which stops Nix from being able to build anything
   (this particular setting can be overriden via
-  <xref linkend="opt-security.allowUserNamespaces"/>). See the <literal
+  <xref linkend="opt-security.allowUserNamespaces"/>). See the
+  <literal
    xlink:href="https://github.com/nixos/nixpkgs/tree/master/nixos/modules/profiles/hardened.nix">
-   profile source</literal> for further detail on which settings are altered.
+  profile source</literal> for further detail on which settings are altered.
  </para>
 </section>
diff --git a/nixos/doc/manual/configuration/profiles/headless.xml b/nixos/doc/manual/configuration/profiles/headless.xml
index 54dc61f236e..1b64497ebf7 100644
--- a/nixos/doc/manual/configuration/profiles/headless.xml
+++ b/nixos/doc/manual/configuration/profiles/headless.xml
@@ -1,18 +1,19 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-headless">
  <title>Headless</title>
+
  <para>
   Common configuration for headless machines (e.g., Amazon EC2 instances).
  </para>
+
  <para>
   Disables <link linkend="opt-sound.enable">sound</link>,
   <link linkend="opt-boot.vesa">vesa</link>, serial consoles,
   <link linkend="opt-systemd.enableEmergencyMode">emergency mode</link>,
-  <link linkend="opt-boot.loader.grub.splashImage">grub splash images</link> and
-  configures the kernel to reboot automatically on panic.
+  <link linkend="opt-boot.loader.grub.splashImage">grub splash images</link>
+  and configures the kernel to reboot automatically on panic.
  </para>
 </section>
diff --git a/nixos/doc/manual/configuration/profiles/installation-device.xml b/nixos/doc/manual/configuration/profiles/installation-device.xml
index 44ccfc538ad..3dcdf403d89 100644
--- a/nixos/doc/manual/configuration/profiles/installation-device.xml
+++ b/nixos/doc/manual/configuration/profiles/installation-device.xml
@@ -1,31 +1,34 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-installation-device">
  <title>Installation Device</title>
+
  <para>
   Provides a basic configuration for installation devices like CDs. This means
   enabling hardware scans, using the <link linkend="sec-profile-clone-config">
-   Clone Config profile</link> to guarantee
+  Clone Config profile</link> to guarantee
   <filename>/etc/nixos/configuration.nix</filename> exists (for
   <command>nixos-rebuild</command> to work), a copy of the Nixpkgs channel
   snapshot used to create the install media.
  </para>
+
  <para>
   Additionally, documentation for <link linkend="opt-documentation.enable">
-   Nixpkgs</link> and <link linkend="opt-documentation.nixos.enable">NixOS
-   </link> are forcefully enabled (to override the
-   <link linkend="sec-profile-minimal">Minimal profile</link> preference); the
-   NixOS manual is shown automatically on TTY 8, sudo and udisks are disabled.
-   Autologin is enabled as root.
+  Nixpkgs</link> and <link linkend="opt-documentation.nixos.enable">NixOS
+  </link> are forcefully enabled (to override the
+  <link linkend="sec-profile-minimal">Minimal profile</link> preference); the
+  NixOS manual is shown automatically on TTY 8, sudo and udisks are disabled.
+  Autologin is enabled as root.
  </para>
+
  <para>
-  A message is shown to the user to start a display manager if needed,
-  ssh with <xref linkend="opt-services.openssh.permitRootLogin"/> are enabled (but
+  A message is shown to the user to start a display manager if needed, ssh with
+  <xref linkend="opt-services.openssh.permitRootLogin"/> are enabled (but
   doesn't autostart). WPA Supplicant is also enabled without autostart.
  </para>
+
  <para>
   Finally, vim is installed, root is set to not have a password, the kernel is
   made more silent for remote public IP installs, and several settings are
diff --git a/nixos/doc/manual/configuration/profiles/minimal.xml b/nixos/doc/manual/configuration/profiles/minimal.xml
index a24af21bd7f..179f2d0be64 100644
--- a/nixos/doc/manual/configuration/profiles/minimal.xml
+++ b/nixos/doc/manual/configuration/profiles/minimal.xml
@@ -1,16 +1,16 @@
-
 <section xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
          xml:id="sec-profile-minimal">
  <title>Minimal</title>
+
  <para>
   This profile defines a small NixOS configuration. It does not contain any
   graphical stuff. It's a very short file that enables
   <link linkend="opt-environment.noXlibs">noXlibs</link>, sets
-  <link linkend="opt-i18n.supportedLocales">i18n.supportedLocales</link>
-  to only support the user-selected locale,
+  <link linkend="opt-i18n.supportedLocales">i18n.supportedLocales</link> to
+  only support the user-selected locale,
   <link linkend="opt-documentation.enable">disables packages' documentation
   </link>, and <link linkend="opt-sound.enable">disables sound</link>.
  </para>
diff --git a/nixos/doc/manual/configuration/profiles/qemu-guest.xml b/nixos/doc/manual/configuration/profiles/qemu-guest.xml
index d08068650fb..5d055c45d2d 100644
--- a/nixos/doc/manual/configuration/profiles/qemu-guest.xml
+++ b/nixos/doc/manual/configuration/profiles/qemu-guest.xml
@@ -4,10 +4,12 @@
          version="5.0"
          xml:id="sec-profile-qemu-guest">
  <title>QEMU Guest</title>
+
  <para>
   This profile contains common configuration for virtual machines running under
   QEMU (using virtio).
  </para>
+
  <para>
   It makes virtio modules available on the initrd, sets the system time from
   the hardware clock to work around a bug in qemu-kvm, and
diff --git a/nixos/doc/manual/configuration/wireless.xml b/nixos/doc/manual/configuration/wireless.xml
index dda2193dd93..7c7b3b4a65a 100644
--- a/nixos/doc/manual/configuration/wireless.xml
+++ b/nixos/doc/manual/configuration/wireless.xml
@@ -23,16 +23,14 @@
     psk = "abcdefgh";
   };
   "free.wifi" = {};
-}
+};
 </programlisting>
   Be aware that keys will be written to the nix store in plaintext! When no
   networks are set, it will default to using a configuration file at
   <literal>/etc/wpa_supplicant.conf</literal>. You should edit this file
-  yourself to define wireless networks, WPA keys and so on (see
-  <citerefentry>
-    <refentrytitle>wpa_supplicant.conf</refentrytitle>
-    <manvolnum>5</manvolnum>
-  </citerefentry>).
+  yourself to define wireless networks, WPA keys and so on (see <citerefentry>
+  <refentrytitle>wpa_supplicant.conf</refentrytitle>
+  <manvolnum>5</manvolnum> </citerefentry>).
  </para>
 
  <para>
diff --git a/nixos/doc/manual/configuration/x-windows.xml b/nixos/doc/manual/configuration/x-windows.xml
index e7d66f391f5..3bcb288b5eb 100644
--- a/nixos/doc/manual/configuration/x-windows.xml
+++ b/nixos/doc/manual/configuration/x-windows.xml
@@ -35,8 +35,8 @@
  </para>
  <para>
   NixOS’s default <emphasis>display manager</emphasis> (the program that
-  provides a graphical login prompt and manages the X server) is LightDM. You can
-  select an alternative one by picking one of the following lines:
+  provides a graphical login prompt and manages the X server) is LightDM. You
+  can select an alternative one by picking one of the following lines:
 <programlisting>
 <xref linkend="opt-services.xserver.displayManager.sddm.enable"/> = true;
 <xref linkend="opt-services.xserver.displayManager.slim.enable"/> = true;
@@ -60,8 +60,15 @@
 # systemctl start display-manager.service
 </screen>
  </para>
+ <para>
+  On 64-bit systems, if you want OpenGL for 32-bit programs such as in Wine,
+  you should also set the following:
+<programlisting>
+<xref linkend="opt-hardware.opengl.driSupport32Bit"/> = true;
+</programlisting>
+ </para>
  <simplesect xml:id="sec-x11-graphics-cards-nvidia">
-  <title>NVIDIA Graphics Cards</title>
+  <title>Proprietary NVIDIA drivers</title>
   <para>
    NVIDIA provides a proprietary driver for its graphics cards that has better
    3D performance than the X.org drivers. It is not enabled by default because
@@ -71,6 +78,7 @@
 </programlisting>
    Or if you have an older card, you may have to use one of the legacy drivers:
 <programlisting>
+<xref linkend="opt-services.xserver.videoDrivers"/> = [ "nvidiaLegacy390" ];
 <xref linkend="opt-services.xserver.videoDrivers"/> = [ "nvidiaLegacy340" ];
 <xref linkend="opt-services.xserver.videoDrivers"/> = [ "nvidiaLegacy304" ];
 <xref linkend="opt-services.xserver.videoDrivers"/> = [ "nvidiaLegacy173" ];
@@ -78,16 +86,9 @@
    You may need to reboot after enabling this driver to prevent a clash with
    other kernel modules.
   </para>
-  <para>
-   On 64-bit systems, if you want full acceleration for 32-bit programs such as
-   Wine, you should also set the following:
-<programlisting>
-<xref linkend="opt-hardware.opengl.driSupport32Bit"/> = true;
-</programlisting>
-  </para>
  </simplesect>
  <simplesect xml:id="sec-x11--graphics-cards-amd">
-  <title>AMD Graphics Cards</title>
+  <title>Proprietary AMD drivers</title>
   <para>
    AMD provides a proprietary driver for its graphics cards that has better 3D
    performance than the X.org drivers. It is not enabled by default because
@@ -99,11 +100,8 @@
    other kernel modules.
   </para>
   <para>
-   On 64-bit systems, if you want full acceleration for 32-bit programs such as
-   Wine, you should also set the following:
-<programlisting>
-<xref linkend="opt-hardware.opengl.driSupport32Bit"/> = true;
-</programlisting>
+   Note: for recent AMD GPUs you most likely want to keep either the defaults
+   or <literal>"amdgpu"</literal> (both free).
   </para>
  </simplesect>
  <simplesect xml:id="sec-x11-touchpads">
diff --git a/nixos/doc/manual/installation/installing-virtualbox-guest.xml b/nixos/doc/manual/installation/installing-virtualbox-guest.xml
index 766785dfe07..5c86eacfbf4 100644
--- a/nixos/doc/manual/installation/installing-virtualbox-guest.xml
+++ b/nixos/doc/manual/installation/installing-virtualbox-guest.xml
@@ -77,10 +77,10 @@
   Shared folders can be given a name and a path in the host system in the
   VirtualBox settings (Machine / Settings / Shared Folders, then click on the
   "Add" icon). Add the following to the
-  <literal>/etc/nixos/configuration.nix</literal> to auto-mount them. If you 
-   do not add <literal>"nofail"</literal>, the system will no boot properly. 
-   The same goes for disabling <literal>rngd</literal> which is normally used 
-   to get randomness but this does not work in virtual machines.
+  <literal>/etc/nixos/configuration.nix</literal> to auto-mount them. If you do
+  not add <literal>"nofail"</literal>, the system will no boot properly. The
+  same goes for disabling <literal>rngd</literal> which is normally used to get
+  randomness but this does not work in virtual machines.
  </para>
 
 <programlisting>
diff --git a/nixos/doc/manual/man-nixos-generate-config.xml b/nixos/doc/manual/man-nixos-generate-config.xml
index 43d6c2696a2..160ada9fff3 100644
--- a/nixos/doc/manual/man-nixos-generate-config.xml
+++ b/nixos/doc/manual/man-nixos-generate-config.xml
@@ -13,18 +13,18 @@
  </refnamediv>
  <refsynopsisdiv>
   <cmdsynopsis>
-   <command>nixos-generate-config</command>
+   <command>nixos-generate-config</command> 
    <arg>
     <option>--force</option>
    </arg>
-
+    
    <arg>
     <arg choice='plain'>
      <option>--root</option>
     </arg>
      <replaceable>root</replaceable>
    </arg>
-
+    
    <arg>
     <arg choice='plain'>
      <option>--dir</option>
diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml
index 654b5f4b284..0b0c0b8f6ea 100644
--- a/nixos/doc/manual/man-nixos-rebuild.xml
+++ b/nixos/doc/manual/man-nixos-rebuild.xml
@@ -13,39 +13,39 @@
  </refnamediv>
  <refsynopsisdiv>
   <cmdsynopsis>
-   <command>nixos-rebuild</command><group choice='req'>
+   <command>nixos-rebuild</command><group choice='req'> 
    <arg choice='plain'>
     <option>switch</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>boot</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>test</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>build</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>dry-build</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>dry-activate</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>edit</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>build-vm</option>
    </arg>
-
+    
    <arg choice='plain'>
     <option>build-vm-with-bootloader</option>
    </arg>
@@ -54,33 +54,33 @@
    <arg>
     <option>--upgrade</option>
    </arg>
-
+    
    <arg>
     <option>--install-bootloader</option>
    </arg>
-
+    
    <arg>
     <option>--no-build-nix</option>
    </arg>
-
+    
    <arg>
     <option>--fast</option>
    </arg>
-
+    
    <arg>
     <option>--rollback</option>
    </arg>
+    
    <arg>
-     <option>--builders</option>
-     <replaceable>builder-spec</replaceable>
+    <option>--builders</option> <replaceable>builder-spec</replaceable>
    </arg>
    <sbr />
    <arg>
-    <group choice='req'>
+    <group choice='req'> 
     <arg choice='plain'>
      <option>--profile-name</option>
     </arg>
-
+     
     <arg choice='plain'>
      <option>-p</option>
     </arg>
@@ -198,7 +198,7 @@ $ nix-build /path/to/nixpkgs/nixos -A system
      </term>
      <listitem>
       <para>
-        Opens <filename>configuration.nix</filename> in the default editor.
+       Opens <filename>configuration.nix</filename> in the default editor.
       </para>
      </listitem>
     </varlistentry>
@@ -334,25 +334,23 @@ $ ./result/bin/run-*-vm
     </listitem>
    </varlistentry>
    <varlistentry>
-     <term>
-       <option>--builders</option>
-       <replaceable>builder-spec</replaceable>
-     </term>
-     <listitem>
-       <para>
-         Allow ad-hoc remote builders for building the new system.
-         This requires the user executing <command>nixos-rebuild</command> (usually
-         root) to be configured as a trusted user in the Nix daemon. This can be
-         achieved by using the <literal>nix.trustedUsers</literal> NixOS option.
-         Examples values for that option are described in the
-		 <literal>Remote builds chapter</literal> in the Nix manual,
-         (i.e. <command>--builders "ssh://bigbrother x86_64-linux"</command>).
-         By specifying an empty string existing builders specified in
-         <filename>/etc/nix/machines</filename> can be ignored:
-         <command>--builders ""</command> for example when they are not
-         reachable due to network connectivity.
-       </para>
-     </listitem>
+    <term>
+     <option>--builders</option> <replaceable>builder-spec</replaceable>
+    </term>
+    <listitem>
+     <para>
+      Allow ad-hoc remote builders for building the new system. This requires
+      the user executing <command>nixos-rebuild</command> (usually root) to be
+      configured as a trusted user in the Nix daemon. This can be achieved by
+      using the <literal>nix.trustedUsers</literal> NixOS option. Examples
+      values for that option are described in the <literal>Remote builds
+      chapter</literal> in the Nix manual, (i.e. <command>--builders
+      "ssh://bigbrother x86_64-linux"</command>). By specifying an empty string
+      existing builders specified in <filename>/etc/nix/machines</filename> can
+      be ignored: <command>--builders ""</command> for example when they are
+      not reachable due to network connectivity.
+     </para>
+    </listitem>
    </varlistentry>
    <varlistentry>
     <term>
diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml
index 8715a05f508..3f10b26223d 100644
--- a/nixos/doc/manual/release-notes/rl-1809.xml
+++ b/nixos/doc/manual/release-notes/rl-1809.xml
@@ -639,7 +639,8 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
    </listitem>
    <listitem>
     <para>
-        Groups <literal>kvm</literal> and <literal>render</literal> are introduced now, as systemd requires them.
+     Groups <literal>kvm</literal> and <literal>render</literal> are introduced
+     now, as systemd requires them.
     </para>
    </listitem>
   </itemizedlist>
diff --git a/nixos/doc/manual/release-notes/rl-1903.xml b/nixos/doc/manual/release-notes/rl-1903.xml
index 3871d54c59c..7c94f6e9473 100644
--- a/nixos/doc/manual/release-notes/rl-1903.xml
+++ b/nixos/doc/manual/release-notes/rl-1903.xml
@@ -20,25 +20,27 @@
   <itemizedlist>
    <listitem>
     <para>
-    The default Python 3 interpreter is now CPython 3.7 instead of CPython 3.6.
+     The default Python 3 interpreter is now CPython 3.7 instead of CPython
+     3.6.
     </para>
    </listitem>
    <listitem>
     <para>
-     Added the Pantheon desktop environment.
-     It can be enabled through <varname>services.xserver.desktopManager.pantheon.enable</varname>.
+     Added the Pantheon desktop environment. It can be enabled through
+     <varname>services.xserver.desktopManager.pantheon.enable</varname>.
     </para>
     <note>
      <para>
-      <varname>services.xserver.desktopManager.pantheon</varname> default enables lightdm
-      as a display manager and using Pantheon's greeter.
+      <varname>services.xserver.desktopManager.pantheon</varname> default
+      enables lightdm as a display manager and using Pantheon's greeter.
      </para>
      <para>
-      This is because of limitations with the screenlocking implementation, whereas the
-      screenlocker would be non-functional without it.
+      This is because of limitations with the screenlocking implementation,
+      whereas the screenlocker would be non-functional without it.
      </para>
      <para>
-      Because of that it is recommended to retain this precaution, however if you'd like to change this set:
+      Because of that it is recommended to retain this precaution, however if
+      you'd like to change this set:
      </para>
      <itemizedlist>
       <listitem>
@@ -52,16 +54,29 @@
        </para>
       </listitem>
      </itemizedlist>
-     <para>to <literal>false</literal> and enable your preferred display manager.</para>
+     <para>
+      to <literal>false</literal> and enable your preferred display manager.
+     </para>
     </note>
    </listitem>
    <listitem>
+    <para>
+     A major refactoring of the Kubernetes module has been completed.
+     Refactorings primarily focus on decoupling components and enhancing
+     security. Two-way TLS and RBAC has been enabled by default for all
+     components, which slightly changes the way the module is configured. See:
+     <xref linkend="sec-kubernetes"/> for details.
+    </para>
+   </listitem>
+   <listitem>
      <para>
-       A major refactoring of the Kubernetes module has been completed.
-       Refactorings primarily focus on decoupling components and enhancing
-       security. Two-way TLS and RBAC has been enabled by default for all
-       components, which slightly changes the way the module is configured.
-       See: <xref linkend="sec-kubernetes"/> for details.
+       There is now a set of <option>confinement</option> options for
+       <option>systemd.services</option>, which allows to restrict services
+       into a <citerefentry>
+        <refentrytitle>chroot</refentrytitle>
+        <manvolnum>2</manvolnum>
+      </citerefentry>ed environment that only contains the store paths from
+      the runtime closure of the service.
      </para>
    </listitem>
   </itemizedlist>
@@ -87,10 +102,11 @@
    <listitem>
     <para>
      There is a new <varname>security.googleOsLogin</varname> module for using
-     <link xlink:href="https://cloud.google.com/compute/docs/instances/managing-instance-access">OS Login</link>
-     to manage SSH access to Google Compute Engine instances, which supersedes
-     the imperative and broken <literal>google-accounts-daemon</literal> used
-     in <literal>nixos/modules/virtualisation/google-compute-config.nix</literal>.
+     <link xlink:href="https://cloud.google.com/compute/docs/instances/managing-instance-access">OS
+     Login</link> to manage SSH access to Google Compute Engine instances,
+     which supersedes the imperative and broken
+     <literal>google-accounts-daemon</literal> used in
+     <literal>nixos/modules/virtualisation/google-compute-config.nix</literal>.
     </para>
    </listitem>
    <listitem>
@@ -101,8 +117,9 @@
    <listitem>
     <para>
      There is a new <varname>services.cockroachdb</varname> module for running
-     CockroachDB databases. NixOS now ships with CockroachDB 2.1.x as well, available
-     on <literal>x86_64-linux</literal> and <literal>aarch64-linux</literal>.
+     CockroachDB databases. NixOS now ships with CockroachDB 2.1.x as well,
+     available on <literal>x86_64-linux</literal> and
+     <literal>aarch64-linux</literal>.
     </para>
    </listitem>
   </itemizedlist>
@@ -110,15 +127,15 @@
   <itemizedlist>
    <listitem>
     <para>
-      <literal>./security/duosec.nix</literal>
+     <literal>./security/duosec.nix</literal>
     </para>
    </listitem>
    <listitem>
     <para>
      The <link xlink:href="https://duo.com/docs/duounix">PAM module for Duo
-     Security</link> has been enabled for use.  One can configure it using
-     the <option>security.duosec</option> options along with the
-     corresponding PAM option in
+     Security</link> has been enabled for use. One can configure it using the
+     <option>security.duosec</option> options along with the corresponding PAM
+     option in
      <option>security.pam.services.&lt;name?&gt;.duoSecurity.enable</option>.
     </para>
    </listitem>
@@ -184,36 +201,37 @@
    </listitem>
    <listitem>
     <para>
-      The <varname>buildPythonPackage</varname> function now sets <varname>strictDeps = true</varname>
-      to help distinguish between native and non-native dependencies in order to
-      improve cross-compilation compatibility. Note however that this may break
-      user expressions.
+     The <varname>buildPythonPackage</varname> function now sets
+     <varname>strictDeps = true</varname> to help distinguish between native
+     and non-native dependencies in order to improve cross-compilation
+     compatibility. Note however that this may break user expressions.
     </para>
    </listitem>
    <listitem>
     <para>
-      The <varname>buildPythonPackage</varname> function now sets <varname>LANG = C.UTF-8</varname>
-      to enable Unicode support. The <varname>glibcLocales</varname> package is no longer needed as a build input.
+     The <varname>buildPythonPackage</varname> function now sets <varname>LANG
+     = C.UTF-8</varname> to enable Unicode support. The
+     <varname>glibcLocales</varname> package is no longer needed as a build
+     input.
     </para>
    </listitem>
    <listitem>
     <para>
-      The Syncthing state and configuration data has been moved from
-      <varname>services.syncthing.dataDir</varname> to the newly defined
-      <varname>services.syncthing.configDir</varname>, which default to
-      <literal>/var/lib/syncthing/.config/syncthing</literal>.
-      This change makes possible to share synced directories using ACLs
-      without Syncthing resetting the permission on every start.
+     The Syncthing state and configuration data has been moved from
+     <varname>services.syncthing.dataDir</varname> to the newly defined
+     <varname>services.syncthing.configDir</varname>, which default to
+     <literal>/var/lib/syncthing/.config/syncthing</literal>. This change makes
+     possible to share synced directories using ACLs without Syncthing
+     resetting the permission on every start.
     </para>
    </listitem>
    <listitem>
     <para>
-      The <literal>ntp</literal> module now has sane default restrictions.
-      If you're relying on the previous defaults, which permitted all queries
-      and commands from all firewall-permitted sources, you can set
-      <varname>services.ntp.restrictDefault</varname> and
-      <varname>services.ntp.restrictSource</varname> to
-      <literal>[]</literal>.
+     The <literal>ntp</literal> module now has sane default restrictions. If
+     you're relying on the previous defaults, which permitted all queries and
+     commands from all firewall-permitted sources, you can set
+     <varname>services.ntp.restrictDefault</varname> and
+     <varname>services.ntp.restrictSource</varname> to <literal>[]</literal>.
     </para>
    </listitem>
    <listitem>
@@ -241,17 +259,21 @@
    </listitem>
    <listitem>
     <para>
-      Options
-      <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.userName</literal> and
-      <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.modulePackages</literal>
-      were removed. They were never used for anything and can therefore safely be removed.
+     Options
+     <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.userName</literal>
+     and
+     <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.modulePackages</literal>
+     were removed. They were never used for anything and can therefore safely
+     be removed.
     </para>
    </listitem>
    <listitem>
     <para>
-     Package <literal>wasm</literal> has been renamed <literal>proglodyte-wasm</literal>. The package
-     <literal>wasm</literal> will be pointed to <literal>ocamlPackages.wasm</literal> in 19.09, so
-     make sure to update your configuration if you want to keep <literal>proglodyte-wasm</literal>
+     Package <literal>wasm</literal> has been renamed
+     <literal>proglodyte-wasm</literal>. The package <literal>wasm</literal>
+     will be pointed to <literal>ocamlPackages.wasm</literal> in 19.09, so make
+     sure to update your configuration if you want to keep
+     <literal>proglodyte-wasm</literal>
     </para>
    </listitem>
    <listitem>
@@ -279,37 +301,41 @@
    </listitem>
    <listitem>
     <para>
-     Package <literal>consul-ui</literal> and passthrough <literal>consul.ui</literal> have been removed.
-     The package <literal>consul</literal> now uses upstream releases that vendor the UI into the binary.
-     See <link xlink:href="https://github.com/NixOS/nixpkgs/pull/48714#issuecomment-433454834">#48714</link>
+     Package <literal>consul-ui</literal> and passthrough
+     <literal>consul.ui</literal> have been removed. The package
+     <literal>consul</literal> now uses upstream releases that vendor the UI
+     into the binary. See
+     <link xlink:href="https://github.com/NixOS/nixpkgs/pull/48714#issuecomment-433454834">#48714</link>
      for details.
     </para>
    </listitem>
    <listitem>
     <para>
-      Slurm introduces the new option
-      <literal>services.slurm.stateSaveLocation</literal>,
-      which is now set to <literal>/var/spool/slurm</literal> by default
-      (instead of <literal>/var/spool</literal>).
-      Make sure to move all files to the new directory or to set the option accordingly.
+     Slurm introduces the new option
+     <literal>services.slurm.stateSaveLocation</literal>, which is now set to
+     <literal>/var/spool/slurm</literal> by default (instead of
+     <literal>/var/spool</literal>). Make sure to move all files to the new
+     directory or to set the option accordingly.
     </para>
     <para>
-      The slurmctld now runs as user <literal>slurm</literal> instead of <literal>root</literal>.
-      If you want to keep slurmctld running as <literal>root</literal>, set
-      <literal>services.slurm.user = root</literal>.
+     The slurmctld now runs as user <literal>slurm</literal> instead of
+     <literal>root</literal>. If you want to keep slurmctld running as
+     <literal>root</literal>, set <literal>services.slurm.user =
+     root</literal>.
     </para>
     <para>
-      The options <literal>services.slurm.nodeName</literal> and
-      <literal>services.slurm.partitionName</literal> are now sets of
-      strings to correctly reflect that fact that each of these
-      options can occour more than once in the configuration.
+     The options <literal>services.slurm.nodeName</literal> and
+     <literal>services.slurm.partitionName</literal> are now sets of strings to
+     correctly reflect that fact that each of these options can occour more
+     than once in the configuration.
     </para>
    </listitem>
    <listitem>
     <para>
-      The <literal>solr</literal> package has been upgraded from 4.10.3 to 7.5.0 and has undergone
-      some major changes. The <literal>services.solr</literal> module has been updated to reflect
-      these changes. Please review http://lucene.apache.org/solr/ carefully before upgrading.
+     The <literal>solr</literal> package has been upgraded from 4.10.3 to 7.5.0
+     and has undergone some major changes. The <literal>services.solr</literal>
+     module has been updated to reflect these changes. Please review
+     http://lucene.apache.org/solr/ carefully before upgrading.
     </para>
    </listitem>
    <listitem>
@@ -321,46 +347,49 @@
    </listitem>
    <listitem>
     <para>
-     The option <literal>services.xserver.displayManager.job.logToFile</literal> which was
+     The option
+     <literal>services.xserver.displayManager.job.logToFile</literal> which was
      previously set to <literal>true</literal> when using the display managers
-     <literal>lightdm</literal>, <literal>sddm</literal> or <literal>xpra</literal> has been
-     reset to the default value (<literal>false</literal>).
+     <literal>lightdm</literal>, <literal>sddm</literal> or
+     <literal>xpra</literal> has been reset to the default value
+     (<literal>false</literal>).
     </para>
    </listitem>
    <listitem>
     <para>
      Network interface indiscriminate NixOS firewall options
-     (<literal>networking.firewall.allow*</literal>) are now preserved when also
-     setting interface specific rules such as <literal>networking.firewall.interfaces.en0.allow*</literal>.
-     These rules continue to use the pseudo device "default"
-     (<literal>networking.firewall.interfaces.default.*</literal>), and assigning
-     to this pseudo device will override the (<literal>networking.firewall.allow*</literal>)
-     options.
-   </para>
-  </listitem>
-  <listitem>
-   <para>
+     (<literal>networking.firewall.allow*</literal>) are now preserved when
+     also setting interface specific rules such as
+     <literal>networking.firewall.interfaces.en0.allow*</literal>. These rules
+     continue to use the pseudo device "default"
+     (<literal>networking.firewall.interfaces.default.*</literal>), and
+     assigning to this pseudo device will override the
+     (<literal>networking.firewall.allow*</literal>) options.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      The <literal>nscd</literal> service now disables all caching of
      <literal>passwd</literal> and <literal>group</literal> databases by
      default. This was interferring with the correct functioning of the
      <literal>libnss_systemd.so</literal> module which is used by
      <literal>systemd</literal> to manage uids and usernames in the presence of
-     <literal>DynamicUser=</literal> in systemd services.  This was already the
+     <literal>DynamicUser=</literal> in systemd services. This was already the
      default behaviour in presence of <literal>services.sssd.enable =
-       true</literal> because nscd caching would interfere with
-     <literal>sssd</literal> in unpredictable ways as well.  Because we're
-     using nscd not for caching, but for convincing glibc to find NSS modules
-     in the nix store instead of an absolute path, we have decided to disable
-     caching globally now, as it's usually not the behaviour the user wants and
-     can lead to surprising behaviour.  Furthermore, negative caching of host
+     true</literal> because nscd caching would interfere with
+     <literal>sssd</literal> in unpredictable ways as well. Because we're using
+     nscd not for caching, but for convincing glibc to find NSS modules in the
+     nix store instead of an absolute path, we have decided to disable caching
+     globally now, as it's usually not the behaviour the user wants and can
+     lead to surprising behaviour. Furthermore, negative caching of host
      lookups is also disabled now by default. This should fix the issue of dns
      lookups failing in the presence of an unreliable network.
-   </para>
-   <para>
-     If the old behaviour is desired, this can be restored by setting
-     the <literal>services.nscd.config</literal> option
-     with the desired caching parameters.
-     <programlisting>
+    </para>
+    <para>
+     If the old behaviour is desired, this can be restored by setting the
+     <literal>services.nscd.config</literal> option with the desired caching
+     parameters.
+<programlisting>
      services.nscd.config =
      ''
      server-user             nscd
@@ -393,97 +422,116 @@
      shared                  hosts           yes
      '';
      </programlisting>
-     See <link xlink:href="https://github.com/NixOS/nixpkgs/pull/50316">#50316</link>
+     See
+     <link xlink:href="https://github.com/NixOS/nixpkgs/pull/50316">#50316</link>
      for details.
-   </para>
-  </listitem>
-  <listitem>
-   <para>
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      GitLab Shell previously used the nix store paths for the
      <literal>gitlab-shell</literal> command in its
      <literal>authorized_keys</literal> file, which might stop working after
      garbage collection. To circumvent that, we regenerated that file on each
-     startup.  As <literal>gitlab-shell</literal> has now been changed to use
+     startup. As <literal>gitlab-shell</literal> has now been changed to use
      <literal>/var/run/current-system/sw/bin/gitlab-shell</literal>, this is
      not necessary anymore, but there might be leftover lines with a nix store
      path. Regenerate the <literal>authorized_keys</literal> file via
      <command>sudo -u git -H gitlab-rake gitlab:shell:setup</command> in that
      case.
-   </para>
-  </listitem>
-  <listitem>
-   <para>
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      The <literal>pam_unix</literal> account module is now loaded with its
      control field set to <literal>required</literal> instead of
      <literal>sufficient</literal>, so that later PAM account modules that
-     might do more extensive checks are being executed.
-     Previously, the whole account module verification was exited prematurely
-     in case a nss module provided the account name to
-     <literal>pam_unix</literal>.
-     The LDAP and SSSD NixOS modules already add their NSS modules when
-     enabled. In case your setup breaks due to some later PAM account module
-     previosuly shadowed, or failing NSS lookups, please file a bug. You can
-     get back the old behaviour by manually setting
-     <literal><![CDATA[security.pam.services.<name?>.text]]></literal>.
-   </para>
-  </listitem>
-  <listitem>
-   <para>
+     might do more extensive checks are being executed. Previously, the whole
+     account module verification was exited prematurely in case a nss module
+     provided the account name to <literal>pam_unix</literal>. The LDAP and
+     SSSD NixOS modules already add their NSS modules when enabled. In case
+     your setup breaks due to some later PAM account module previosuly
+     shadowed, or failing NSS lookups, please file a bug. You can get back the
+     old behaviour by manually setting <literal>
+<![CDATA[security.pam.services.<name?>.text]]>
+     </literal>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      The <literal>pam_unix</literal> password module is now loaded with its
      control field set to <literal>sufficient</literal> instead of
-     <literal>required</literal>, so that password managed only
-     by later PAM password modules are being executed.
-     Previously, for example, changing an LDAP account's password through PAM
-     was not possible: the whole password module verification
-     was exited prematurely by <literal>pam_unix</literal>,
-     preventing <literal>pam_ldap</literal> to manage the password as it should.
-   </para>
-  </listitem>
-   <listitem>
-    <para>
-     <literal>fish</literal> has been upgraded to 3.0.
-     It comes with a number of improvements and backwards incompatible changes.
-     See the <literal>fish</literal> <link xlink:href="https://github.com/fish-shell/fish-shell/releases/tag/3.0.0">release notes</link> for more information.
-    </para>
-   </listitem>
-  <listitem>
-    <para>
-      The ibus-table input method has had a change in config format, which
-      causes all previous settings to be lost. See
-      <link xlink:href="https://github.com/mike-fabian/ibus-table/commit/f9195f877c5212fef0dfa446acb328c45ba5852b">this commit message</link>
-      for details.
-    </para>
-  </listitem>
-  <listitem>
-   <para>
-    NixOS module system type <literal>types.optionSet</literal> and
-    <literal>lib.mkOption</literal> argument <literal>options</literal> are deprecated.
-    Use <literal>types.submodule</literal> instead.
-    (<link xlink:href="https://github.com/NixOS/nixpkgs/pull/54637">#54637</link>)
-   </para>
-  </listitem>
-  <listitem>
-   <para>
-    <literal>matrix-synapse</literal> has been updated to version 0.99. It will
-    <link xlink:href="https://github.com/matrix-org/synapse/pull/4509">no longer generate a self-signed certificate on first launch</link>
-    and will be <link xlink:href="https://matrix.org/blog/2019/02/05/synapse-0-99-0/">the last version to accept self-signed certificates</link>.
-    As such, it is now recommended to use a proper certificate verified by a
-    root CA (for example Let's Encrypt).
-    The new <link linkend="module-services-matrix">manual chapter on Matrix</link> contains a working example of using nginx as a reverse proxy
-    in front of <literal>matrix-synapse</literal>, using Let's Encrypt certificates.
-   </para>
-  </listitem>
+     <literal>required</literal>, so that password managed only by later PAM
+     password modules are being executed. Previously, for example, changing an
+     LDAP account's password through PAM was not possible: the whole password
+     module verification was exited prematurely by <literal>pam_unix</literal>,
+     preventing <literal>pam_ldap</literal> to manage the password as it
+     should.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     <literal>fish</literal> has been upgraded to 3.0. It comes with a number
+     of improvements and backwards incompatible changes. See the
+     <literal>fish</literal>
+     <link xlink:href="https://github.com/fish-shell/fish-shell/releases/tag/3.0.0">release
+     notes</link> for more information.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The ibus-table input method has had a change in config format, which
+     causes all previous settings to be lost. See
+     <link xlink:href="https://github.com/mike-fabian/ibus-table/commit/f9195f877c5212fef0dfa446acb328c45ba5852b">this
+     commit message</link> for details.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     NixOS module system type <literal>types.optionSet</literal> and
+     <literal>lib.mkOption</literal> argument <literal>options</literal> are
+     deprecated. Use <literal>types.submodule</literal> instead.
+     (<link xlink:href="https://github.com/NixOS/nixpkgs/pull/54637">#54637</link>)
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     <literal>matrix-synapse</literal> has been updated to version 0.99. It
+     will <link xlink:href="https://github.com/matrix-org/synapse/pull/4509">no
+     longer generate a self-signed certificate on first launch</link> and will
+     be
+     <link xlink:href="https://matrix.org/blog/2019/02/05/synapse-0-99-0/">the
+     last version to accept self-signed certificates</link>. As such, it is now
+     recommended to use a proper certificate verified by a root CA (for example
+     Let's Encrypt). The new <link linkend="module-services-matrix">manual
+     chapter on Matrix</link> contains a working example of using nginx as a
+     reverse proxy in front of <literal>matrix-synapse</literal>, using Let's
+     Encrypt certificates.
+    </para>
+   </listitem>
    <listitem>
     <para>
      <literal>mailutils</literal> now works by default when
      <literal>sendmail</literal> is not in a setuid wrapper. As a consequence,
-     the <literal>sendmailPath</literal> argument, having lost its main use, has
-     been removed.
+     the <literal>sendmailPath</literal> argument, having lost its main use,
+     has been removed.
     </para>
    </listitem>
    <listitem>
     <para>
-     <literal>graylog</literal> has been upgraded from version 2.* to 3.*. Some setups making use of extraConfig (especially those exposing Graylog via reverse proxies) need to be updated as upstream removed/replaced some settings. See <link xlink:href="http://docs.graylog.org/en/3.0/pages/upgrade/graylog-3.0.html#simplified-http-interface-configuration">Upgrading Graylog</link> for details.
+     <literal>graylog</literal> has been upgraded from version 2.* to 3.*. Some
+     setups making use of extraConfig (especially those exposing Graylog via
+     reverse proxies) need to be updated as upstream removed/replaced some
+     settings. See
+     <link xlink:href="http://docs.graylog.org/en/3.0/pages/upgrade/graylog-3.0.html#simplified-http-interface-configuration">Upgrading
+     Graylog</link> for details.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+      The option <literal>users.ldap.bind.password</literal> was renamed to <literal>users.ldap.bind.passwordFile</literal>,
+      and needs to be readable by the <literal>nslcd</literal> user.
+      Same applies to the new <literal>users.ldap.daemon.rootpwmodpwFile</literal> option.
     </para>
    </listitem>
   </itemizedlist>
@@ -500,206 +548,219 @@
    <listitem>
     <para>
      The <option>services.matomo</option> module gained the option
-     <option>services.matomo.package</option> which determines the used
-     Matomo version.
+     <option>services.matomo.package</option> which determines the used Matomo
+     version.
     </para>
     <para>
-     The Matomo module now also comes with the systemd service <literal>matomo-archive-processing.service</literal>
-     and a timer that automatically triggers archive processing every hour.
-     This means that you can safely
+     The Matomo module now also comes with the systemd service
+     <literal>matomo-archive-processing.service</literal> and a timer that
+     automatically triggers archive processing every hour. This means that you
+     can safely
      <link xlink:href="https://matomo.org/docs/setup-auto-archiving/#disable-browser-triggers-for-matomo-archiving-and-limit-matomo-reports-to-updating-every-hour">
-      disable browser triggers for Matomo archiving
-     </link> at <literal>Administration > System > General Settings</literal>.
+     disable browser triggers for Matomo archiving </link> at
+     <literal>Administration > System > General Settings</literal>.
     </para>
     <para>
      Additionally, you can enable to
      <link xlink:href="https://matomo.org/docs/privacy/#step-2-delete-old-visitors-logs">
-      delete old visitor logs
-     </link> at <literal>Administration > System > Privacy</literal>,
-     but make sure that you run <literal>systemctl start matomo-archive-processing.service</literal>
-     at least once without errors if you have already collected data before,
-     so that the reports get archived before the source data gets deleted.
+     delete old visitor logs </link> at <literal>Administration > System >
+     Privacy</literal>, but make sure that you run <literal>systemctl start
+     matomo-archive-processing.service</literal> at least once without errors
+     if you have already collected data before, so that the reports get
+     archived before the source data gets deleted.
     </para>
    </listitem>
    <listitem>
     <para>
-     <literal>composableDerivation</literal> along with supporting library functions
-     has been removed.
+     <literal>composableDerivation</literal> along with supporting library
+     functions has been removed.
     </para>
    </listitem>
    <listitem>
     <para>
-     The deprecated <literal>truecrypt</literal> package has been removed
-     and <literal>truecrypt</literal> attribute is now an alias for
+     The deprecated <literal>truecrypt</literal> package has been removed and
+     <literal>truecrypt</literal> attribute is now an alias for
      <literal>veracrypt</literal>. VeraCrypt is backward-compatible with
-     TrueCrypt volumes. Note that <literal>cryptsetup</literal> also
-     supports loading TrueCrypt volumes.
+     TrueCrypt volumes. Note that <literal>cryptsetup</literal> also supports
+     loading TrueCrypt volumes.
     </para>
    </listitem>
    <listitem>
     <para>
-      The Kubernetes DNS addons, kube-dns, has been replaced with CoreDNS.
-      This change is made in accordance with Kubernetes making CoreDNS the official default
-      starting from
-      <link xlink:href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md#sig-cluster-lifecycle">Kubernetes v1.11</link>.
-      Please beware that upgrading DNS-addon on existing clusters might induce
-      minor downtime while the DNS-addon terminates and re-initializes.
-      Also note that the DNS-service now runs with 2 pod replicas by default.
-      The desired number of replicas can be configured using:
-      <option>services.kubernetes.addons.dns.replicas</option>.
+     The Kubernetes DNS addons, kube-dns, has been replaced with CoreDNS. This
+     change is made in accordance with Kubernetes making CoreDNS the official
+     default starting from
+     <link xlink:href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md#sig-cluster-lifecycle">Kubernetes
+     v1.11</link>. Please beware that upgrading DNS-addon on existing clusters
+     might induce minor downtime while the DNS-addon terminates and
+     re-initializes. Also note that the DNS-service now runs with 2 pod
+     replicas by default. The desired number of replicas can be configured
+     using: <option>services.kubernetes.addons.dns.replicas</option>.
     </para>
    </listitem>
    <listitem>
-     <para>
-       The quassel-webserver package and module was removed from nixpkgs due to the lack
-       of maintainers.
-     </para>
+    <para>
+     The quassel-webserver package and module was removed from nixpkgs due to
+     the lack of maintainers.
+    </para>
    </listitem>
    <listitem>
     <para>
-     The manual gained a
-     <link linkend="module-services-matrix">
-      new chapter on self-hosting <literal>matrix-synapse</literal> and <literal>riot-web</literal>
-     </link>, the most prevalent server and client implementations for the
-     <link xlink:href="https://matrix.org/">Matrix</link> federated communication network.
+     The manual gained a <link linkend="module-services-matrix"> new chapter on
+     self-hosting <literal>matrix-synapse</literal> and
+     <literal>riot-web</literal> </link>, the most prevalent server and client
+     implementations for the
+     <link xlink:href="https://matrix.org/">Matrix</link> federated
+     communication network.
     </para>
    </listitem>
    <listitem>
-     <para>
-       The astah-community package was removed from nixpkgs due to it being discontinued and the downloads not being available anymore.
-     </para>
+    <para>
+     The astah-community package was removed from nixpkgs due to it being
+     discontinued and the downloads not being available anymore.
+    </para>
    </listitem>
    <listitem>
-     <para>
-       The httpd service now saves log files with a .log file extension by default for
-       easier integration with the logrotate service.
-     </para>
+    <para>
+     The httpd service now saves log files with a .log file extension by
+     default for easier integration with the logrotate service.
+    </para>
    </listitem>
    <listitem>
-     <para>
-       The owncloud server packages and httpd subservice module were removed
-       from nixpkgs due to the lack of maintainers.
-     </para>
+    <para>
+     The owncloud server packages and httpd subservice module were removed from
+     nixpkgs due to the lack of maintainers.
+    </para>
    </listitem>
    <listitem>
-     <para>
-       It is possible now to uze ZRAM devices as general purpose ephemeral block devices,
-       not only as swap. Using more than 1 device as ZRAM swap is no longer recommended,
-       but is still possible by setting <literal>zramSwap.swapDevices</literal> explicitly.
-     </para>
-     <para>
-      ZRAM algorithm can be changed now.
-     </para>
-     <para>
-      Changes to ZRAM algorithm are applied during <literal>nixos-rebuild switch</literal>,
-      so make sure you have enough swap space on disk to survive ZRAM device rebuild. Alternatively,
-      use <literal>nixos-rebuild boot; reboot</literal>.
-     </para>
+    <para>
+     It is possible now to uze ZRAM devices as general purpose ephemeral block
+     devices, not only as swap. Using more than 1 device as ZRAM swap is no
+     longer recommended, but is still possible by setting
+     <literal>zramSwap.swapDevices</literal> explicitly.
+    </para>
+    <para>
+     ZRAM algorithm can be changed now.
+    </para>
+    <para>
+     Changes to ZRAM algorithm are applied during <literal>nixos-rebuild
+     switch</literal>, so make sure you have enough swap space on disk to
+     survive ZRAM device rebuild. Alternatively, use <literal>nixos-rebuild
+     boot; reboot</literal>.
+    </para>
    </listitem>
    <listitem>
     <para>
-      Flat volumes are now disabled by default in <literal>hardware.pulseaudio</literal>.
-      This has been done to prevent applications, which are unaware of this feature, setting
-      their volumes to 100% on startup causing harm to your audio hardware and potentially your ears.
+     Flat volumes are now disabled by default in
+     <literal>hardware.pulseaudio</literal>. This has been done to prevent
+     applications, which are unaware of this feature, setting their volumes to
+     100% on startup causing harm to your audio hardware and potentially your
+     ears.
     </para>
     <note>
      <para>
-      With this change application specific volumes are relative to the master volume which can be
-      adjusted independently, whereas before they were absolute; meaning that in effect, it scaled the
-      device-volume with the volume of the loudest application.
+      With this change application specific volumes are relative to the master
+      volume which can be adjusted independently, whereas before they were
+      absolute; meaning that in effect, it scaled the device-volume with the
+      volume of the loudest application.
      </para>
     </note>
    </listitem>
    <listitem>
     <para>
-     The <link xlink:href="https://github.com/DanielAdolfsson/ndppd"><literal>ndppd</literal></link> module
-     now supports <link linkend="opt-services.ndppd.enable">all config options</link> provided by the current
-     upstream version as service options. Additionally the <literal>ndppd</literal> package doesn't contain
-     the systemd unit configuration from upstream anymore, the unit is completely configured by the NixOS module now.
+     The
+     <link xlink:href="https://github.com/DanielAdolfsson/ndppd"><literal>ndppd</literal></link>
+     module now supports <link linkend="opt-services.ndppd.enable">all config
+     options</link> provided by the current upstream version as service
+     options. Additionally the <literal>ndppd</literal> package doesn't contain
+     the systemd unit configuration from upstream anymore, the unit is
+     completely configured by the NixOS module now.
     </para>
    </listitem>
    <listitem>
     <para>
-     New installs of NixOS will default to the Redmine 4.x series unless otherwise specified in
-     <literal>services.redmine.package</literal> while existing installs of NixOS will default to
-     the Redmine 3.x series.
+     New installs of NixOS will default to the Redmine 4.x series unless
+     otherwise specified in <literal>services.redmine.package</literal> while
+     existing installs of NixOS will default to the Redmine 3.x series.
     </para>
    </listitem>
    <listitem>
     <para>
-     The <link linkend="opt-services.grafana.enable">Grafana module</link> now supports declarative
-     <link xlink:href="http://docs.grafana.org/administration/provisioning/">datasource and dashboard</link>
-     provisioning.
+     The <link linkend="opt-services.grafana.enable">Grafana module</link> now
+     supports declarative
+     <link xlink:href="http://docs.grafana.org/administration/provisioning/">datasource
+     and dashboard</link> provisioning.
     </para>
    </listitem>
    <listitem>
-     <para>
-       The use of insecure ports on kubernetes has been deprecated.
-       Thus options:
-       <varname>services.kubernetes.apiserver.port</varname> and
-       <varname>services.kubernetes.controllerManager.port</varname>
-       has been renamed to <varname>.insecurePort</varname>,
-       and default of both options has changed to 0 (disabled).
-     </para>
-    </listitem>
-    <listitem>
-      <para>
-        Note that the default value of
-        <varname>services.kubernetes.apiserver.bindAddress</varname>
-        has changed from 127.0.0.1 to 0.0.0.0, allowing the apiserver to be
-        accessible from outside the master node itself.
-        If the apiserver insecurePort is enabled,
-        it is strongly recommended to only bind on the loopback interface. See:
-        <varname>services.kubernetes.apiserver.insecurebindAddress</varname>.
-      </para>
-    </listitem>
-    <listitem>
-      <para>
-        The option <varname>services.kubernetes.apiserver.allowPrivileged</varname>
-        and <varname>services.kubernetes.kubelet.allowPrivileged</varname> now
-        defaults to false. Disallowing privileged containers on the cluster.
-      </para>
-    </listitem>
-    <listitem>
-      <para>
-        The kubernetes module does no longer add the kubernetes package to
-        <varname>environment.systemPackages</varname> implicitly.
-      </para>
-    </listitem>
-    <listitem>
-      <para>
-        The <literal>intel</literal> driver has been removed from the default list of
-        <link linkend="opt-services.xserver.videoDrivers">X.org video drivers</link>.
-        The <literal>modesetting</literal> driver should take over automatically,
-        it is better maintained upstream and has less problems with advanced X11 features.
-        This can lead to a change in the output names used by <literal>xrandr</literal>.
-        Some performance regressions on some GPU models might happen.
-        Some OpenCL and VA-API applications might also break
-        (Beignet seems to provide OpenCL support with
-        <literal>modesetting</literal> driver, too).
-        Kernel mode setting API does not support backlight control,
-        so <literal>xbacklight</literal> tool will not work;
-        backlight level can be controlled directly via <literal>/sys/</literal>
-        or with <literal>brightnessctl</literal>.
-        Users who need this functionality more than multi-output XRandR are advised
-        to add `intel` to `videoDrivers` and report an issue (or provide additional
-        details in an existing one)
-      </para>
+    <para>
+     The use of insecure ports on kubernetes has been deprecated. Thus options:
+     <varname>services.kubernetes.apiserver.port</varname> and
+     <varname>services.kubernetes.controllerManager.port</varname> has been
+     renamed to <varname>.insecurePort</varname>, and default of both options
+     has changed to 0 (disabled).
+    </para>
    </listitem>
    <listitem>
-     <para>
-       Openmpi has been updated to version 4.0.0, which removes some deprecated MPI-1 symbols.
-       This may break some older applications that still rely on those symbols.
-       An upgrade guide can be found <link xlink:href="https://www.open-mpi.org/faq/?category=mpi-removed">here</link>.
-     </para>
     <para>
-     The nginx package now relies on OpenSSL 1.1 and supports TLS 1.3 by default. You can set the protocols used by the nginx service using <xref linkend="opt-services.nginx.sslProtocols"/>.
+     Note that the default value of
+     <varname>services.kubernetes.apiserver.bindAddress</varname> has changed
+     from 127.0.0.1 to 0.0.0.0, allowing the apiserver to be accessible from
+     outside the master node itself. If the apiserver insecurePort is enabled,
+     it is strongly recommended to only bind on the loopback interface. See:
+     <varname>services.kubernetes.apiserver.insecurebindAddress</varname>.
     </para>
    </listitem>
    <listitem>
-     <para>
-       A new subcommand <command>nixos-rebuild edit</command> was added.
-     </para>
+    <para>
+     The option
+     <varname>services.kubernetes.apiserver.allowPrivileged</varname> and
+     <varname>services.kubernetes.kubelet.allowPrivileged</varname> now
+     defaults to false. Disallowing privileged containers on the cluster.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The kubernetes module does no longer add the kubernetes package to
+     <varname>environment.systemPackages</varname> implicitly.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The <literal>intel</literal> driver has been removed from the default list
+     of <link linkend="opt-services.xserver.videoDrivers">X.org video
+     drivers</link>. The <literal>modesetting</literal> driver should take over
+     automatically, it is better maintained upstream and has less problems with
+     advanced X11 features. This can lead to a change in the output names used
+     by <literal>xrandr</literal>. Some performance regressions on some GPU
+     models might happen. Some OpenCL and VA-API applications might also break
+     (Beignet seems to provide OpenCL support with
+     <literal>modesetting</literal> driver, too). Kernel mode setting API does
+     not support backlight control, so <literal>xbacklight</literal> tool will
+     not work; backlight level can be controlled directly via
+     <literal>/sys/</literal> or with <literal>brightnessctl</literal>. Users
+     who need this functionality more than multi-output XRandR are advised to
+     add `intel` to `videoDrivers` and report an issue (or provide additional
+     details in an existing one)
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Openmpi has been updated to version 4.0.0, which removes some deprecated
+     MPI-1 symbols. This may break some older applications that still rely on
+     those symbols. An upgrade guide can be found
+     <link xlink:href="https://www.open-mpi.org/faq/?category=mpi-removed">here</link>.
+    </para>
+    <para>
+     The nginx package now relies on OpenSSL 1.1 and supports TLS 1.3 by
+     default. You can set the protocols used by the nginx service using
+     <xref linkend="opt-services.nginx.sslProtocols"/>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     A new subcommand <command>nixos-rebuild edit</command> was added.
+    </para>
    </listitem>
   </itemizedlist>
  </section>
diff --git a/nixos/doc/manual/release-notes/rl-1909.xml b/nixos/doc/manual/release-notes/rl-1909.xml
index f54592b6bf6..2cfaec49c02 100644
--- a/nixos/doc/manual/release-notes/rl-1909.xml
+++ b/nixos/doc/manual/release-notes/rl-1909.xml
@@ -46,6 +46,39 @@
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          version="5.0"
+         xml:id="sec-release-19.09-incompatibilities">
+  <title>Backward Incompatibilities</title>
+
+  <para>
+   When upgrading from a previous release, please be aware of the following
+   incompatible changes:
+  </para>
+
+  <itemizedlist>
+   <listitem>
+    <para>
+     Buildbot no longer supports Python 2, as support was dropped upstream in
+     version 2.0.0. Configurations may need to be modified to make them
+     compatible with Python 3.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     PostgreSQL now uses
+     <filename class="directory">/run/postgresql</filename> as its socket
+     directory instead of <filename class="directory">/tmp</filename>. So
+     if you run an application like eg. Nextcloud, where you need to use
+     the Unix socket path as the database host name, you need to change it
+     accordingly.
+    </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-19.09-notable-changes">
   <title>Other Notable Changes</title>
 
@@ -53,14 +86,27 @@
    <listitem>
     <para>
      The <option>documentation</option> module gained an option named
-     <option>documentation.nixos.includeAllModules</option> which makes the generated
-     <citerefentry><refentrytitle>configuration.nix</refentrytitle>
-     <manvolnum>5</manvolnum></citerefentry> manual page include all options from all NixOS modules
-     included in a given <literal>configuration.nix</literal> configuration file. Currently, it is
-     set to <literal>false</literal> by default as enabling it frequently prevents evaluation. But
-     the plan is to eventually have it set to <literal>true</literal> by default. Please set it to
-     <literal>true</literal> now in your <literal>configuration.nix</literal> and fix all the bugs
-     it uncovers.
+     <option>documentation.nixos.includeAllModules</option> which makes the
+     generated <citerefentry>
+     <refentrytitle>configuration.nix</refentrytitle>
+     <manvolnum>5</manvolnum></citerefentry> manual page include all options
+     from all NixOS modules included in a given
+     <literal>configuration.nix</literal> configuration file. Currently, it is
+     set to <literal>false</literal> by default as enabling it frequently
+     prevents evaluation. But the plan is to eventually have it set to
+     <literal>true</literal> by default. Please set it to
+     <literal>true</literal> now in your <literal>configuration.nix</literal>
+     and fix all the bugs it uncovers.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The <literal>vlc</literal> package gained support for Chromecast
+     streaming, enabled by default. TCP port 8010 must be open for it to work,
+     so something like <literal>networking.firewall.allowedTCPPorts = [ 8010
+     ];</literal> may be required in your configuration. Also consider enabling
+     <link xlink:href="https://nixos.wiki/wiki/Accelerated_Video_Playback">
+     Accelerated Video Playback</link> for better transcoding performance.
     </para>
    </listitem>
   </itemizedlist>
diff --git a/nixos/modules/config/ldap.nix b/nixos/modules/config/ldap.nix
index f65a3fc50d5..e008497a2a6 100644
--- a/nixos/modules/config/ldap.nix
+++ b/nixos/modules/config/ldap.nix
@@ -27,25 +27,29 @@ let
     '';
   };
 
-  nslcdConfig = {
-    target = "nslcd.conf";
-    source = writeText "nslcd.conf" ''
-      uid nslcd
-      gid nslcd
-      uri ${cfg.server}
-      base ${cfg.base}
-      timelimit ${toString cfg.timeLimit}
-      bind_timelimit ${toString cfg.bind.timeLimit}
-      ${optionalString (cfg.bind.distinguishedName != "")
-        "binddn ${cfg.bind.distinguishedName}" }
-      ${optionalString (cfg.daemon.rootpwmoddn != "")
-        "rootpwmoddn ${cfg.daemon.rootpwmoddn}" }
-      ${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
-    '';
-  };
-
-  insertLdapPassword = !config.users.ldap.daemon.enable &&
-    config.users.ldap.bind.distinguishedName != "";
+  nslcdConfig = writeText "nslcd.conf" ''
+    uid nslcd
+    gid nslcd
+    uri ${cfg.server}
+    base ${cfg.base}
+    timelimit ${toString cfg.timeLimit}
+    bind_timelimit ${toString cfg.bind.timeLimit}
+    ${optionalString (cfg.bind.distinguishedName != "")
+      "binddn ${cfg.bind.distinguishedName}" }
+    ${optionalString (cfg.daemon.rootpwmoddn != "")
+      "rootpwmoddn ${cfg.daemon.rootpwmoddn}" }
+    ${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
+  '';
+
+  # nslcd normally reads configuration from /etc/nslcd.conf.
+  # this file might contain secrets. We append those at runtime,
+  # so redirect its location to something more temporary.
+  nslcdWrapped = runCommandNoCC "nslcd-wrapped" { nativeBuildInputs = [ makeWrapper ]; } ''
+    mkdir -p $out/bin
+    makeWrapper ${nss_pam_ldapd}/sbin/nslcd $out/bin/nslcd \
+      --set LD_PRELOAD    "${pkgs.libredirect}/lib/libredirect.so" \
+      --set NIX_REDIRECTS "/etc/nslcd.conf=/run/nslcd/nslcd.conf"
+  '';
 
 in
 
@@ -139,13 +143,13 @@ in
           '';
         };
 
-        rootpwmodpw = mkOption {
+        rootpwmodpwFile = mkOption {
           default = "";
           example = "/run/keys/nslcd.rootpwmodpw";
           type = types.str;
           description = ''
-            The path to a file containing the credentials with which
-            to bind to the LDAP server if the root user tries to change a user's password
+            The path to a file containing the credentials with which to bind to
+            the LDAP server if the root user tries to change a user's password.
           '';
         };
       };
@@ -161,7 +165,7 @@ in
           '';
         };
 
-        password = mkOption {
+        passwordFile = mkOption {
           default = "/etc/ldap/bind.password";
           type = types.str;
           description = ''
@@ -220,14 +224,14 @@ in
 
   config = mkIf cfg.enable {
 
-    environment.etc = if cfg.daemon.enable then [nslcdConfig] else [ldapConfig];
+    environment.etc = optional (!cfg.daemon.enable) ldapConfig;
 
-    system.activationScripts = mkIf insertLdapPassword {
+    system.activationScripts = mkIf (!cfg.daemon.enable) {
       ldap = stringAfter [ "etc" "groups" "users" ] ''
-        if test -f "${cfg.bind.password}" ; then
+        if test -f "${cfg.bind.passwordFile}" ; then
           umask 0077
           conf="$(mktemp)"
-          printf 'bindpw %s\n' "$(cat ${cfg.bind.password})" |
+          printf 'bindpw %s\n' "$(cat ${cfg.bind.passwordFile})" |
           cat ${ldapConfig.source} - >"$conf"
           mv -fT "$conf" /etc/ldap.conf
         fi
@@ -251,7 +255,6 @@ in
     };
 
     systemd.services = mkIf cfg.daemon.enable {
-
       nslcd = {
         wantedBy = [ "multi-user.target" ];
 
@@ -259,32 +262,32 @@ in
           umask 0077
           conf="$(mktemp)"
           {
-            cat ${nslcdConfig.source}
-            test -z '${cfg.bind.distinguishedName}' -o ! -f '${cfg.bind.password}' ||
-            printf 'bindpw %s\n' "$(cat '${cfg.bind.password}')"
-            test -z '${cfg.daemon.rootpwmoddn}' -o ! -f '${cfg.daemon.rootpwmodpw}' ||
-            printf 'rootpwmodpw %s\n' "$(cat '${cfg.daemon.rootpwmodpw}')"
+            cat ${nslcdConfig}
+            test -z '${cfg.bind.distinguishedName}' -o ! -f '${cfg.bind.passwordFile}' ||
+            printf 'bindpw %s\n' "$(cat '${cfg.bind.passwordFile}')"
+            test -z '${cfg.daemon.rootpwmoddn}' -o ! -f '${cfg.daemon.rootpwmodpwFile}' ||
+            printf 'rootpwmodpw %s\n' "$(cat '${cfg.daemon.rootpwmodpwFile}')"
           } >"$conf"
-          mv -fT "$conf" /etc/nslcd.conf
+          mv -fT "$conf" /run/nslcd/nslcd.conf
         '';
-
-        # NOTE: because one cannot pass a custom config path to `nslcd`
-        # (which is only able to use `/etc/nslcd.conf`)
-        # changes in `nslcdConfig` won't change `serviceConfig`,
-        # and thus won't restart `nslcd`.
-        # Therefore `restartTriggers` is used on `/etc/nslcd.conf`.
-        restartTriggers = [ nslcdConfig.source ];
+        restartTriggers = [ "/run/nslcd/nslcd.conf" ];
 
         serviceConfig = {
-          ExecStart = "${nss_pam_ldapd}/sbin/nslcd";
+          ExecStart = "${nslcdWrapped}/bin/nslcd";
           Type = "forking";
-          PIDFile = "/run/nslcd/nslcd.pid";
           Restart = "always";
+          User = "nslcd";
+          Group = "nslcd";
           RuntimeDirectory = [ "nslcd" ];
+          PIDFile = "/run/nslcd/nslcd.pid";
         };
       };
 
     };
 
   };
+
+  imports =
+    [ (mkRenamedOptionModule [ "users" "ldap" "bind" "password"] [ "users" "ldap" "bind" "passwordFile"])
+    ];
 }
diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix
index 9d202347702..aad02a9ca4e 100644
--- a/nixos/modules/config/no-x-libs.nix
+++ b/nixos/modules/config/no-x-libs.nix
@@ -34,7 +34,7 @@ with lib;
       networkmanager-openvpn = super.networkmanager-openvpn.override { withGnome = false; };
       networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; };
       networkmanager-iodine = super.networkmanager-iodine.override { withGnome = false; };
-      pinentry = super.pinentry.override { gtk2 = null; qt = null; };
+      pinentry = super.pinentry.override { gtk2 = null; gcr = null; qt = null; };
       gobject-introspection = super.gobject-introspection.override { x11Support = false; };
     }));
   };
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index 69cc22aaa34..c79be810eef 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -38,6 +38,12 @@ in {
         firmwareLinuxNonfree
         intel2200BGFirmware
         rtl8192su-firmware
+        rt5677-firmware
+        rtl8723bs-firmware
+        rtlwifi_new-firmware
+        zd1211fw
+        alsa-firmware
+        openelec-dvb-firmware
       ] ++ optional (pkgs.stdenv.hostPlatform.isAarch32 || pkgs.stdenv.hostPlatform.isAarch64) raspberrypiWirelessFirmware
         ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [
         rtl8723bs-firmware
@@ -54,6 +60,10 @@ in {
       }];
       hardware.firmware = with pkgs; [
         broadcom-bt-firmware
+        b43Firmware_5_1_138
+        b43Firmware_6_30_163_46
+        b43FirmwareCutter
+        facetimehd-firmware
       ];
     })
   ];
diff --git a/nixos/modules/hardware/logitech.nix b/nixos/modules/hardware/logitech.nix
new file mode 100644
index 00000000000..d6f43bdddcc
--- /dev/null
+++ b/nixos/modules/hardware/logitech.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.hardware.logitech;
+
+in {
+  options.hardware.logitech = {
+    enable = mkEnableOption "Logitech Devices";
+
+    enableGraphical = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Enable graphical support applications.";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    environment.systemPackages = [
+      pkgs.ltunify
+    ] ++ lib.optional cfg.enableGraphical pkgs.solaar;
+
+    # ltunifi and solaar both provide udev rules but the most up-to-date have been split
+    # out into a dedicated derivation
+    services.udev.packages = with pkgs; [ logitech-udev-rules ];
+  };
+}
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index e78e290e743..fd780be2082 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -88,7 +88,7 @@ let
   #     result in incorrect boot entries.
 
   baseIsolinuxCfg = ''
-    SERIAL 0 38400
+    SERIAL 0 115200
     TIMEOUT ${builtins.toString syslinuxTimeout}
     UI vesamenu.c32
     MENU TITLE NixOS
@@ -165,6 +165,8 @@ let
     else
       "# No refind for ${targetArch}"
   ;
+  
+  grubPkgs = if config.boot.loader.grub.forcei686 then pkgs.pkgsi686Linux else pkgs; 
 
   grubMenuCfg = ''
     #
@@ -241,7 +243,7 @@ let
     # Modules that may or may not be available per-platform.
     echo "Adding additional modules:"
     for mod in efi_uga; do
-      if [ -f ${pkgs.grub2_efi}/lib/grub/${pkgs.grub2_efi.grubTarget}/$mod.mod ]; then
+      if [ -f ${grubPkgs.grub2_efi}/lib/grub/${grubPkgs.grub2_efi.grubTarget}/$mod.mod ]; then
         echo " - $mod"
         MODULES+=" $mod"
       fi
@@ -249,9 +251,9 @@ let
 
     # Make our own efi program, we can't rely on "grub-install" since it seems to
     # probe for devices, even with --skip-fs-probe.
-    ${pkgs.grub2_efi}/bin/grub-mkimage -o $out/EFI/boot/boot${targetArch}.efi -p /EFI/boot -O ${pkgs.grub2_efi.grubTarget} \
+    ${grubPkgs.grub2_efi}/bin/grub-mkimage -o $out/EFI/boot/boot${targetArch}.efi -p /EFI/boot -O ${grubPkgs.grub2_efi.grubTarget} \
       $MODULES
-    cp ${pkgs.grub2_efi}/share/grub/unicode.pf2 $out/EFI/boot/
+    cp ${grubPkgs.grub2_efi}/share/grub/unicode.pf2 $out/EFI/boot/
 
     cat <<EOF > $out/EFI/boot/grub.cfg
 
@@ -362,7 +364,7 @@ let
 
   # Name used by UEFI for architectures.
   targetArch =
-    if pkgs.stdenv.isi686 then
+    if pkgs.stdenv.isi686 || config.boot.loader.grub.forcei686 then
       "ia32"
     else if pkgs.stdenv.isx86_64 then
       "x64"
@@ -506,7 +508,7 @@ in
     # here and it causes a cyclic dependency.
     boot.loader.grub.enable = false;
 
-    environment.systemPackages = [ pkgs.grub2 pkgs.grub2_efi ]
+    environment.systemPackages =  [ grubPkgs.grub2 grubPkgs.grub2_efi ]
       ++ optional canx86BiosBoot pkgs.syslinux
     ;
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index b2f2c1ac8cb..03e5f537c22 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -35,6 +35,7 @@
   ./config/users-groups.nix
   ./config/vpnc.nix
   ./config/zram.nix
+  ./hardware/acpilight.nix
   ./hardware/all-firmware.nix
   ./hardware/bladeRF.nix
   ./hardware/brightnessctl.nix
@@ -45,6 +46,7 @@
   ./hardware/sensor/iio.nix
   ./hardware/ksm.nix
   ./hardware/ledger.nix
+  ./hardware/logitech.nix
   ./hardware/mcelog.nix
   ./hardware/network/b43.nix
   ./hardware/nitrokey.nix
@@ -136,6 +138,7 @@
   ./programs/vim.nix
   ./programs/wavemon.nix
   ./programs/way-cooler.nix
+  ./programs/waybar.nix
   ./programs/wireshark.nix
   ./programs/xfs_quota.nix
   ./programs/xonsh.nix
@@ -170,6 +173,7 @@
   ./security/rtkit.nix
   ./security/wrappers/default.nix
   ./security/sudo.nix
+  ./security/systemd-confinement.nix
   ./services/admin/oxidized.nix
   ./services/admin/salt/master.nix
   ./services/admin/salt/minion.nix
@@ -347,6 +351,7 @@
   ./services/mail/exim.nix
   ./services/mail/freepops.nix
   ./services/mail/mail.nix
+  ./services/mail/mailcatcher.nix
   ./services/mail/mailhog.nix
   ./services/mail/mlmmj.nix
   ./services/mail/offlineimap.nix
@@ -628,6 +633,7 @@
   ./services/networking/prosody.nix
   ./services/networking/quagga.nix
   ./services/networking/quassel.nix
+  ./services/networking/quicktun.nix
   ./services/networking/racoon.nix
   ./services/networking/radicale.nix
   ./services/networking/radvd.nix
@@ -766,6 +772,7 @@
   ./services/web-servers/nginx/default.nix
   ./services/web-servers/nginx/gitweb.nix
   ./services/web-servers/phpfpm/default.nix
+  ./services/web-servers/unit/default.nix
   ./services/web-servers/shellinabox.nix
   ./services/web-servers/tomcat.nix
   ./services/web-servers/traefik.nix
@@ -873,9 +880,11 @@
   ./tasks/trackpoint.nix
   ./tasks/powertop.nix
   ./testing/service-runner.nix
+  ./virtualisation/anbox.nix
   ./virtualisation/container-config.nix
   ./virtualisation/containers.nix
   ./virtualisation/docker.nix
+  ./virtualisation/docker-containers.nix
   ./virtualisation/ecs-agent.nix
   ./virtualisation/libvirtd.nix
   ./virtualisation/lxc.nix
diff --git a/nixos/modules/programs/browserpass.nix b/nixos/modules/programs/browserpass.nix
index 5f8a44a9848..47b9d1ccb1f 100644
--- a/nixos/modules/programs/browserpass.nix
+++ b/nixos/modules/programs/browserpass.nix
@@ -4,15 +4,34 @@ with lib;
 
 {
 
-  ###### interface
-  options = {
-    programs.browserpass.enable = mkEnableOption "the NativeMessaging configuration for Chromium, Chrome, and Vivaldi.";
-  };
+  options.programs.browserpass.enable = mkEnableOption "Browserpass native messaging host";
 
-  ###### implementation
   config = mkIf config.programs.browserpass.enable {
-    environment.systemPackages = [ pkgs.browserpass ];
-    environment.etc = {
+    environment.etc = let
+      appId = "com.github.browserpass.native.json";
+      source = part: "${pkgs.browserpass}/lib/browserpass/${part}/${appId}";
+    in {
+      # chromium
+      "chromium/native-messaging-hosts/${appId}".source = source "hosts/chromium";
+      "chromium/policies/managed/${appId}".source = source "policies/chromium";
+
+      # chrome
+      "opt/chrome/native-messaging-hosts/${appId}".source = source "hosts/chromium";
+      "opt/chrome/policies/managed/${appId}".source = source "policies/chromium";
+
+      # vivaldi
+      "opt/vivaldi/native-messaging-hosts/${appId}".source = source "hosts/chromium";
+      "opt/vivaldi/policies/managed/${appId}".source = source "policies/chromium";
+
+      # brave
+      "opt/brave/native-messaging-hosts/${appId}".source = source "hosts/chromium";
+      "opt/brave/policies/managed/${appId}".source = source "policies/chromium";
+    }
+    # As with the v2 backwards compatibility in the pkgs.browserpass
+    # declaration, this part can be removed once the browser extension
+    # auto-updates to v3 (planned 2019-04-13, see
+    # https://github.com/browserpass/browserpass-native/issues/31)
+    // {
       "chromium/native-messaging-hosts/com.dannyvankooten.browserpass.json".source = "${pkgs.browserpass}/etc/chrome-host.json";
       "chromium/policies/managed/com.dannyvankooten.browserpass.json".source = "${pkgs.browserpass}/etc/chrome-policy.json";
       "opt/chrome/native-messaging-hosts/com.dannyvankooten.browserpass.json".source = "${pkgs.browserpass}/etc/chrome-host.json";
diff --git a/nixos/modules/programs/gnupg.nix b/nixos/modules/programs/gnupg.nix
index 22521280e93..9618d61a1f5 100644
--- a/nixos/modules/programs/gnupg.nix
+++ b/nixos/modules/programs/gnupg.nix
@@ -11,6 +11,15 @@ in
 {
 
   options.programs.gnupg = {
+    package = mkOption {
+      type = types.package;
+      default = pkgs.gnupg;
+      defaultText = "pkgs.gnupg";
+      description = ''
+        The gpg package that should be used.
+      '';
+    };
+
     agent.enable = mkOption {
       type = types.bool;
       default = false;
@@ -75,7 +84,7 @@ in
       wantedBy = [ "sockets.target" ];
     };
 
-    systemd.packages = [ pkgs.gnupg ];
+    systemd.packages = [ cfg.package ];
 
     environment.interactiveShellInit = ''
       # Bind gpg-agent to this TTY if gpg commands are used.
@@ -84,12 +93,12 @@ in
     '' + (optionalString cfg.agent.enableSSHSupport ''
       # SSH agent protocol doesn't support changing TTYs, so bind the agent
       # to every new TTY.
-      ${pkgs.gnupg}/bin/gpg-connect-agent --quiet updatestartuptty /bye > /dev/null
+      ${cfg.package}/bin/gpg-connect-agent --quiet updatestartuptty /bye > /dev/null
     '');
 
     environment.extraInit = mkIf cfg.agent.enableSSHSupport ''
       if [ -z "$SSH_AUTH_SOCK" ]; then
-        export SSH_AUTH_SOCK=$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)
+        export SSH_AUTH_SOCK=$(${cfg.package}/bin/gpgconf --list-dirs agent-ssh-socket)
       fi
     '';
 
diff --git a/nixos/modules/programs/waybar.nix b/nixos/modules/programs/waybar.nix
new file mode 100644
index 00000000000..22530e6c7d4
--- /dev/null
+++ b/nixos/modules/programs/waybar.nix
@@ -0,0 +1,20 @@
+{ lib, pkgs, config, ... }:
+
+with lib;
+
+{
+  options.programs.waybar = {
+    enable = mkEnableOption "waybar";
+  };
+
+  config = mkIf config.programs.waybar.enable {
+    systemd.user.services.waybar = {
+      description = "Waybar as systemd service";
+      wantedBy = [ "graphical-session.target" ];
+      partOf = [ "graphical-session.target" ];
+      script = "${pkgs.waybar}/bin/waybar";
+    };
+  };
+
+  meta.maintainers = [ maintainers.FlorianFranzen ];
+}
diff --git a/nixos/modules/programs/zsh/oh-my-zsh.xml b/nixos/modules/programs/zsh/oh-my-zsh.xml
index b26980daf06..568c2de6557 100644
--- a/nixos/modules/programs/zsh/oh-my-zsh.xml
+++ b/nixos/modules/programs/zsh/oh-my-zsh.xml
@@ -87,9 +87,9 @@
 
   <para>
    <emphasis>Please keep in mind that this is not compatible with
-   <literal>programs.zsh.ohMyZsh.custom</literal> as it requires an immutable store
-   path while <literal>custom</literal> shall remain mutable! An evaluation
-   failure will be thrown if both <literal>custom</literal> and
+   <literal>programs.zsh.ohMyZsh.custom</literal> as it requires an immutable
+   store path while <literal>custom</literal> shall remain mutable! An
+   evaluation failure will be thrown if both <literal>custom</literal> and
    <literal>customPkgs</literal> are set.</emphasis>
   </para>
  </section>
diff --git a/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix
index 90fd1c5b73a..b7117e5f90d 100644
--- a/nixos/modules/programs/zsh/zsh.nix
+++ b/nixos/modules/programs/zsh/zsh.nix
@@ -79,6 +79,33 @@ in
         type = types.lines;
       };
 
+      histSize = mkOption {
+        default = 2000;
+        description = ''
+          Change history size.
+        '';
+        type = types.int;
+      };
+
+      histFile = mkOption {
+        default = "$HOME/.zsh_history";
+        description = ''
+          Change history file.
+        '';
+        type = types.str;
+      };
+
+      setOptions = mkOption {
+        type = types.listOf types.str;
+        default = [
+          "HIST_IGNORE_DUPS" "SHARE_HISTORY" "HIST_FCNTL_LOCK"
+        ];
+        example = [ "EXTENDED_HISTORY" "RM_STAR_WAIT" ];
+        description = ''
+          Configure zsh options.
+        '';
+      };
+
       enableCompletion = mkOption {
         default = true;
         description = ''
@@ -162,12 +189,12 @@ in
 
         . /etc/zinputrc
 
-        # history defaults
-        SAVEHIST=2000
-        HISTSIZE=2000
-        HISTFILE=$HOME/.zsh_history
+        # Don't export these, otherwise other shells (bash) will try to use same histfile
+        SAVEHIST=${toString cfg.histSize}
+        HISTSIZE=${toString cfg.histSize}
+        HISTFILE=${cfg.histFile}
 
-        setopt HIST_IGNORE_DUPS SHARE_HISTORY HIST_FCNTL_LOCK
+        ${optionalString (cfg.setOptions != []) "setopt ${concatStringsSep " " cfg.setOptions}"}
 
         HELPDIR="${pkgs.zsh}/share/zsh/$ZSH_VERSION/help"
 
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index a7243e8eae0..30d11cc58fa 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -4,26 +4,12 @@ with lib;
 
 {
   imports = [
-    # !!! These were renamed the other way, but got reverted later.
-    # !!! Drop these before 18.09 is released.
-    (mkRenamedOptionModule [ "system" "nixos" "stateVersion" ] [ "system" "stateVersion" ])
-    (mkRenamedOptionModule [ "system" "nixos" "defaultChannel" ] [ "system" "defaultChannel" ])
-
-    (mkRenamedOptionModule [ "environment" "x11Packages" ] [ "environment" "systemPackages" ])
-    (mkRenamedOptionModule [ "environment" "enableBashCompletion" ] [ "programs" "bash" "enableCompletion" ])
-    (mkRenamedOptionModule [ "environment" "nix" ] [ "nix" "package" ])
-    (mkRenamedOptionModule [ "fonts" "enableFontConfig" ] [ "fonts" "fontconfig" "enable" ])
-    (mkRenamedOptionModule [ "fonts" "extraFonts" ] [ "fonts" "fonts" ])
-
-    (mkRenamedOptionModule [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ])
     (mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "hardware" "enableRedistributableFirmware" ])
     (mkRenamedOptionModule [ "networking" "enableIntel3945ABGFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
     (mkRenamedOptionModule [ "networking" "enableIntel2100BGFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
     (mkRenamedOptionModule [ "networking" "enableRalinkFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
     (mkRenamedOptionModule [ "networking" "enableRTL8192cFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
     (mkRenamedOptionModule [ "networking" "networkmanager" "useDnsmasq" ] [ "networking" "networkmanager" "dns" ])
-
-    (mkRenamedOptionModule [ "services" "cadvisor" "host" ] [ "services" "cadvisor" "listenAddress" ])
     (mkChangedOptionModule [ "services" "printing" "gutenprint" ] [ "services" "printing" "drivers" ]
       (config:
         let enabled = getAttrFromPath [ "services" "printing" "gutenprint" ] config;
@@ -33,11 +19,7 @@ with lib;
         let value = getAttrFromPath [ "services" "ddclient" "domain" ] config;
         in if value != "" then [ value ] else []))
     (mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "")
-    (mkRenamedOptionModule [ "services" "elasticsearch" "host" ] [ "services" "elasticsearch" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "graphite" "api" "host" ] [ "services" "graphite" "api" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "graphite" "web" "host" ] [ "services" "graphite" "web" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "i2pd" "extIp" ] [ "services" "i2pd" "address" ])
-    (mkRenamedOptionModule [ "services" "kibana" "host" ] [ "services" "kibana" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "admissionControl" ] [ "services" "kubernetes" "apiserver" "enableAdmissionPlugins" ])
     (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "address" ] ["services" "kubernetes" "apiserver" "bindAddress"])
     (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "port" ] ["services" "kubernetes" "apiserver" "insecurePort"])
@@ -54,7 +36,6 @@ with lib;
     (mkRenamedOptionModule [ "services" "kubernetes" "proxy" "address" ] ["services" "kubernetes" "proxy" "bindAddress"])
     (mkRemovedOptionModule [ "services" "kubernetes" "verbose" ] "")
     (mkRenamedOptionModule [ "services" "logstash" "address" ] [ "services" "logstash" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "mpd" "network" "host" ] [ "services" "mpd" "network" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "neo4j" "host" ] [ "services" "neo4j" "defaultListenAddress" ])
     (mkRenamedOptionModule [ "services" "neo4j" "listenAddress" ] [ "services" "neo4j" "defaultListenAddress" ])
     (mkRenamedOptionModule [ "services" "neo4j" "enableBolt" ] [ "services" "neo4j" "bolt" "enable" ])
@@ -64,10 +45,6 @@ with lib;
     (mkRemovedOptionModule [ "services" "neo4j" "port" ] "Use services.neo4j.http.listenAddress instead.")
     (mkRemovedOptionModule [ "services" "neo4j" "boltPort" ] "Use services.neo4j.bolt.listenAddress instead.")
     (mkRemovedOptionModule [ "services" "neo4j" "httpsPort" ] "Use services.neo4j.https.listenAddress instead.")
-    (mkRenamedOptionModule [ "services" "shout" "host" ] [ "services" "shout" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "sslh" "host" ] [ "services" "sslh" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "statsd" "host" ] [ "services" "statsd" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "subsonic" "host" ] [ "services" "subsonic" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ])
     (mkRenamedOptionModule [ "services" "vmwareGuest" ] [ "virtualisation" "vmware" "guest" ])
     (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ])
@@ -91,82 +68,31 @@ with lib;
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "logToJournal" ] [ "services" "xserver" "displayManager" "job" "logToJournal" ])
 
     # Old Grub-related options.
-    (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ])
-    (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ])
     (mkRenamedOptionModule [ "boot" "loader" "grub" "timeout" ] [ "boot" "loader" "timeout" ])
     (mkRenamedOptionModule [ "boot" "loader" "gummiboot" "timeout" ] [ "boot" "loader" "timeout" ])
 
-    # smartd
-    (mkRenamedOptionModule [ "services" "smartd" "deviceOpts" ] [ "services" "smartd" "defaults" "monitored" ])
-
     # OpenSSH
-    (mkRenamedOptionModule [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ])
     (mkAliasOptionModule [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ])
-    (mkRenamedOptionModule [ "services" "sshd" "allowSFTP" ] [ "services" "openssh" "allowSFTP" ])
-    (mkRenamedOptionModule [ "services" "sshd" "forwardX11" ] [ "services" "openssh" "forwardX11" ])
-    (mkRenamedOptionModule [ "services" "sshd" "gatewayPorts" ] [ "services" "openssh" "gatewayPorts" ])
-    (mkRenamedOptionModule [ "services" "sshd" "permitRootLogin" ] [ "services" "openssh" "permitRootLogin" ])
-    (mkRenamedOptionModule [ "services" "xserver" "startSSHAgent" ] [ "services" "xserver" "startOpenSSHAgent" ])
-    (mkRenamedOptionModule [ "services" "xserver" "startOpenSSHAgent" ] [ "programs" "ssh" "startAgent" ])
     (mkAliasOptionModule [ "services" "openssh" "knownHosts" ] [ "programs" "ssh" "knownHosts" ])
 
-    # VirtualBox
-    (mkRenamedOptionModule [ "services" "virtualbox" "enable" ] [ "virtualisation" "virtualbox" "guest" "enable" ])
-    (mkRenamedOptionModule [ "services" "virtualboxGuest" "enable" ] [ "virtualisation" "virtualbox" "guest" "enable" ])
-    (mkRenamedOptionModule [ "programs" "virtualbox" "enable" ] [ "virtualisation" "virtualbox" "host" "enable" ])
-    (mkRenamedOptionModule [ "programs" "virtualbox" "addNetworkInterface" ] [ "virtualisation" "virtualbox" "host" "addNetworkInterface" ])
-    (mkRenamedOptionModule [ "programs" "virtualbox" "enableHardening" ] [ "virtualisation" "virtualbox" "host" "enableHardening" ])
-    (mkRenamedOptionModule [ "services" "virtualboxHost" "enable" ] [ "virtualisation" "virtualbox" "host" "enable" ])
-    (mkRenamedOptionModule [ "services" "virtualboxHost" "addNetworkInterface" ] [ "virtualisation" "virtualbox" "host" "addNetworkInterface" ])
-    (mkRenamedOptionModule [ "services" "virtualboxHost" "enableHardening" ] [ "virtualisation" "virtualbox" "host" "enableHardening" ])
-
     # libvirtd
     (mkRemovedOptionModule [ "virtualisation" "libvirtd" "enableKVM" ]
       "Set the option `virtualisation.libvirtd.qemuPackage' instead.")
 
-    # Tarsnap
-    (mkRenamedOptionModule [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ])
-
     # ibus
     (mkRenamedOptionModule [ "programs" "ibus" "plugins" ] [ "i18n" "inputMethod" "ibus" "engines" ])
 
-    # proxy
-    (mkRenamedOptionModule [ "nix" "proxy" ] [ "networking" "proxy" "default" ])
-
     # sandboxing
     (mkRenamedOptionModule [ "nix" "useChroot" ] [ "nix" "useSandbox" ])
     (mkRenamedOptionModule [ "nix" "chrootDirs" ] [ "nix" "sandboxPaths" ])
 
-    # KDE
-    (mkRenamedOptionModule [ "kde" "extraPackages" ] [ "environment" "systemPackages" ])
-    (mkRenamedOptionModule [ "environment" "kdePackages" ] [ "environment" "systemPackages" ])
-
-    # Multiple efi bootloaders now
-    (mkRenamedOptionModule [ "boot" "loader" "efi" "efibootmgr" "enable" ] [ "boot" "loader" "efi" "canTouchEfiVariables" ])
-
-    # NixOS environment changes
-    # !!! this hardcodes bash, could we detect from config which shell is actually used?
-    (mkRenamedOptionModule [ "environment" "promptInit" ] [ "programs" "bash" "promptInit" ])
-
-    (mkRenamedOptionModule [ "services" "xserver" "driSupport" ] [ "hardware" "opengl" "driSupport" ])
-    (mkRenamedOptionModule [ "services" "xserver" "driSupport32Bit" ] [ "hardware" "opengl" "driSupport32Bit" ])
-    (mkRenamedOptionModule [ "services" "xserver" "s3tcSupport" ] [ "hardware" "opengl" "s3tcSupport" ])
-    (mkRenamedOptionModule [ "hardware" "opengl" "videoDrivers" ] [ "services" "xserver" "videoDrivers" ])
     (mkRenamedOptionModule [ "services" "xserver" "vaapiDrivers" ] [ "hardware" "opengl" "extraPackages" ])
 
-    (mkRenamedOptionModule [ "services" "mysql55" ] [ "services" "mysql" ])
-
     (mkAliasOptionModule [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ])
 
     # opendkim
     (mkRenamedOptionModule [ "services" "opendkim" "keyFile" ] [ "services" "opendkim" "keyPath" ])
 
-    # XBMC
-    (mkRenamedOptionModule [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ])
-    (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ])
-
-    (mkRenamedOptionModule [ "services" "hostapd" "extraCfg" ] [ "services" "hostapd" "extraConfig" ])
-
     # Enlightenment
     (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "e19" "enable" ] [ "services" "xserver" "desktopManager" "enlightenment" "enable" ])
 
diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix
index 14bf118f2d8..997328ad9e6 100644
--- a/nixos/modules/security/duosec.nix
+++ b/nixos/modules/security/duosec.nix
@@ -76,7 +76,7 @@ in
       };
 
       failmode = mkOption {
-        type = types.enum [ "safe" "enum" ];
+        type = types.enum [ "safe" "secure" ];
         default = "safe";
         description = ''
           On service or configuration errors that prevent Duo
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 03d2f899f2a..46ce274a2a9 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -48,6 +48,16 @@ let
         '';
       };
 
+      yubicoAuth = mkOption {
+        default = config.security.pam.yubico.enable;
+        type = types.bool;
+        description = ''
+          If set, users listed in
+          <filename>~/.yubico/authorized_yubikeys</filename>
+          are able to log in with the asociated Yubikey tokens.
+        '';
+      };
+
       googleAuthenticator = {
         enable = mkOption {
           default = false;
@@ -340,6 +350,8 @@ let
               "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
           ${let oath = config.security.pam.oath; in optionalString cfg.oathAuth
               "auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"}
+          ${let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth
+              "auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so id=${toString yubi.id} ${optionalString yubi.debug "debug"}"}
         '' +
           # Modules in this block require having the password set in PAM_AUTHTOK.
           # pam_unix is marked as 'sufficient' on NixOS which means nothing will run
@@ -636,6 +648,54 @@ in
       };
     };
 
+    security.pam.yubico = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enables Yubico PAM (<literal>yubico-pam</literal>) module.
+
+          If set, users listed in
+          <filename>~/.yubico/authorized_yubikeys</filename>
+          are able to log in with the associated Yubikey tokens.
+
+          The file must have only one line:
+          <literal>username:yubikey_token_id1:yubikey_token_id2</literal>
+          More information can be found <link
+          xlink:href="https://developers.yubico.com/yubico-pam/">here</link>.
+        '';
+      };
+      control = mkOption {
+        default = "sufficient";
+        type = types.enum [ "required" "requisite" "sufficient" "optional" ];
+        description = ''
+          This option sets pam "control".
+          If you want to have multi factor authentication, use "required".
+          If you want to use Yubikey instead of regular password, use "sufficient".
+
+          Read
+          <citerefentry>
+            <refentrytitle>pam.conf</refentrytitle>
+            <manvolnum>5</manvolnum>
+          </citerefentry>
+          for better understanding of this option.
+        '';
+      };
+      id = mkOption {
+        example = "42";
+        type = types.string;
+        description = "client id";
+      };
+
+      debug = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Debug output to stderr.
+        '';
+      };
+    };
+
     security.pam.enableEcryptfs = mkOption {
       default = false;
       description = ''
diff --git a/nixos/modules/security/systemd-confinement.nix b/nixos/modules/security/systemd-confinement.nix
new file mode 100644
index 00000000000..cd4eb81dbe1
--- /dev/null
+++ b/nixos/modules/security/systemd-confinement.nix
@@ -0,0 +1,199 @@
+{ config, pkgs, lib, ... }:
+
+let
+  toplevelConfig = config;
+  inherit (lib) types;
+  inherit (import ../system/boot/systemd-lib.nix {
+    inherit config pkgs lib;
+  }) mkPathSafeName;
+in {
+  options.systemd.services = lib.mkOption {
+    type = types.attrsOf (types.submodule ({ name, config, ... }: {
+      options.confinement.enable = lib.mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If set, all the required runtime store paths for this service are
+          bind-mounted into a <literal>tmpfs</literal>-based <citerefentry>
+            <refentrytitle>chroot</refentrytitle>
+            <manvolnum>2</manvolnum>
+          </citerefentry>.
+        '';
+      };
+
+      options.confinement.fullUnit = lib.mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to include the full closure of the systemd unit file into the
+          chroot, instead of just the dependencies for the executables.
+
+          <warning><para>While it may be tempting to just enable this option to
+          make things work quickly, please be aware that this might add paths
+          to the closure of the chroot that you didn't anticipate. It's better
+          to use <option>confinement.packages</option> to <emphasis
+          role="strong">explicitly</emphasis> add additional store paths to the
+          chroot.</para></warning>
+        '';
+      };
+
+      options.confinement.packages = lib.mkOption {
+        type = types.listOf (types.either types.str types.package);
+        default = [];
+        description = let
+          mkScOption = optName: "<option>serviceConfig.${optName}</option>";
+        in ''
+          Additional packages or strings with context to add to the closure of
+          the chroot. By default, this includes all the packages from the
+          ${lib.concatMapStringsSep ", " mkScOption [
+            "ExecReload" "ExecStartPost" "ExecStartPre" "ExecStop"
+            "ExecStopPost"
+          ]} and ${mkScOption "ExecStart"} options. If you want to have all the
+          dependencies of this systemd unit, you can use
+          <option>confinement.fullUnit</option>.
+
+          <note><para>The store paths listed in <option>path</option> are
+          <emphasis role="strong">not</emphasis> included in the closure as
+          well as paths from other options except those listed
+          above.</para></note>
+        '';
+      };
+
+      options.confinement.binSh = lib.mkOption {
+        type = types.nullOr types.path;
+        default = toplevelConfig.environment.binsh;
+        defaultText = "config.environment.binsh";
+        example = lib.literalExample "\${pkgs.dash}/bin/dash";
+        description = ''
+          The program to make available as <filename>/bin/sh</filename> inside
+          the chroot. If this is set to <literal>null</literal>, no
+          <filename>/bin/sh</filename> is provided at all.
+
+          This is useful for some applications, which for example use the
+          <citerefentry>
+            <refentrytitle>system</refentrytitle>
+            <manvolnum>3</manvolnum>
+          </citerefentry> library function to execute commands.
+        '';
+      };
+
+      options.confinement.mode = lib.mkOption {
+        type = types.enum [ "full-apivfs" "chroot-only" ];
+        default = "full-apivfs";
+        description = ''
+          The value <literal>full-apivfs</literal> (the default) sets up
+          private <filename class="directory">/dev</filename>, <filename
+          class="directory">/proc</filename>, <filename
+          class="directory">/sys</filename> and <filename
+          class="directory">/tmp</filename> file systems in a separate user
+          name space.
+
+          If this is set to <literal>chroot-only</literal>, only the file
+          system name space is set up along with the call to <citerefentry>
+            <refentrytitle>chroot</refentrytitle>
+            <manvolnum>2</manvolnum>
+          </citerefentry>.
+
+          <note><para>This doesn't cover network namespaces and is solely for
+          file system level isolation.</para></note>
+        '';
+      };
+
+      config = let
+        rootName = "${mkPathSafeName name}-chroot";
+        inherit (config.confinement) binSh fullUnit;
+        wantsAPIVFS = lib.mkDefault (config.confinement.mode == "full-apivfs");
+      in lib.mkIf config.confinement.enable {
+        serviceConfig = {
+          RootDirectory = pkgs.runCommand rootName {} "mkdir \"$out\"";
+          TemporaryFileSystem = "/";
+          PrivateMounts = lib.mkDefault true;
+
+          # https://github.com/NixOS/nixpkgs/issues/14645 is a future attempt
+          # to change some of these to default to true.
+          #
+          # If we run in chroot-only mode, having something like PrivateDevices
+          # set to true by default will mount /dev within the chroot, whereas
+          # with "chroot-only" it's expected that there are no /dev, /proc and
+          # /sys file systems available.
+          #
+          # However, if this suddenly becomes true, the attack surface will
+          # increase, so let's explicitly set these options to true/false
+          # depending on the mode.
+          MountAPIVFS = wantsAPIVFS;
+          PrivateDevices = wantsAPIVFS;
+          PrivateTmp = wantsAPIVFS;
+          PrivateUsers = wantsAPIVFS;
+          ProtectControlGroups = wantsAPIVFS;
+          ProtectKernelModules = wantsAPIVFS;
+          ProtectKernelTunables = wantsAPIVFS;
+        };
+        confinement.packages = let
+          execOpts = [
+            "ExecReload" "ExecStart" "ExecStartPost" "ExecStartPre" "ExecStop"
+            "ExecStopPost"
+          ];
+          execPkgs = lib.concatMap (opt: let
+            isSet = config.serviceConfig ? ${opt};
+          in lib.optional isSet config.serviceConfig.${opt}) execOpts;
+          unitAttrs = toplevelConfig.systemd.units."${name}.service";
+          allPkgs = lib.singleton (builtins.toJSON unitAttrs);
+          unitPkgs = if fullUnit then allPkgs else execPkgs;
+        in unitPkgs ++ lib.optional (binSh != null) binSh;
+      };
+    }));
+  };
+
+  config.assertions = lib.concatLists (lib.mapAttrsToList (name: cfg: let
+    whatOpt = optName: "The 'serviceConfig' option '${optName}' for"
+                    + " service '${name}' is enabled in conjunction with"
+                    + " 'confinement.enable'";
+  in lib.optionals cfg.confinement.enable [
+    { assertion = !cfg.serviceConfig.RootDirectoryStartOnly or false;
+      message = "${whatOpt "RootDirectoryStartOnly"}, but right now systemd"
+              + " doesn't support restricting bind-mounts to 'ExecStart'."
+              + " Please either define a separate service or find a way to run"
+              + " commands other than ExecStart within the chroot.";
+    }
+    { assertion = !cfg.serviceConfig.DynamicUser or false;
+      message = "${whatOpt "DynamicUser"}. Please create a dedicated user via"
+              + " the 'users.users' option instead as this combination is"
+              + " currently not supported.";
+    }
+  ]) config.systemd.services);
+
+  config.systemd.packages = lib.concatLists (lib.mapAttrsToList (name: cfg: let
+    rootPaths = let
+      contents = lib.concatStringsSep "\n" cfg.confinement.packages;
+    in pkgs.writeText "${mkPathSafeName name}-string-contexts.txt" contents;
+
+    chrootPaths = pkgs.runCommand "${mkPathSafeName name}-chroot-paths" {
+      closureInfo = pkgs.closureInfo { inherit rootPaths; };
+      serviceName = "${name}.service";
+      excludedPath = rootPaths;
+    } ''
+      mkdir -p "$out/lib/systemd/system"
+      serviceFile="$out/lib/systemd/system/$serviceName"
+
+      echo '[Service]' > "$serviceFile"
+
+      # /bin/sh is special here, because the option value could contain a
+      # symlink and we need to properly resolve it.
+      ${lib.optionalString (cfg.confinement.binSh != null) ''
+        binsh=${lib.escapeShellArg cfg.confinement.binSh}
+        realprog="$(readlink -e "$binsh")"
+        echo "BindReadOnlyPaths=$realprog:/bin/sh" >> "$serviceFile"
+      ''}
+
+      while read storePath; do
+        if [ -L "$storePath" ]; then
+          # Currently, systemd can't cope with symlinks in Bind(ReadOnly)Paths,
+          # so let's just bind-mount the target to that location.
+          echo "BindReadOnlyPaths=$(readlink -e "$storePath"):$storePath"
+        elif [ "$storePath" != "$excludedPath" ]; then
+          echo "BindReadOnlyPaths=$storePath"
+        fi
+      done < "$closureInfo/store-paths" >> "$serviceFile"
+    '';
+  in lib.optional cfg.confinement.enable chrootPaths) config.systemd.services);
+}
diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix
index 0f07e6133bb..9c615fbe885 100644
--- a/nixos/modules/services/continuous-integration/buildbot/master.nix
+++ b/nixos/modules/services/continuous-integration/buildbot/master.nix
@@ -199,10 +199,10 @@ in {
 
       package = mkOption {
         type = types.package;
-        default = pkgs.pythonPackages.buildbot-full;
-        defaultText = "pkgs.pythonPackages.buildbot-full";
+        default = pkgs.python3Packages.buildbot-full;
+        defaultText = "pkgs.python3Packages.buildbot-full";
         description = "Package to use for buildbot.";
-        example = literalExample "pkgs.python3Packages.buildbot-full";
+        example = literalExample "pkgs.python3Packages.buildbot";
       };
 
       packages = mkOption {
diff --git a/nixos/modules/services/continuous-integration/buildbot/worker.nix b/nixos/modules/services/continuous-integration/buildbot/worker.nix
index 4130ec918a7..49e04ca3622 100644
--- a/nixos/modules/services/continuous-integration/buildbot/worker.nix
+++ b/nixos/modules/services/continuous-integration/buildbot/worker.nix
@@ -118,10 +118,10 @@ in {
 
       package = mkOption {
         type = types.package;
-        default = pkgs.pythonPackages.buildbot-worker;
-        defaultText = "pkgs.pythonPackages.buildbot-worker";
+        default = pkgs.python3Packages.buildbot-worker;
+        defaultText = "pkgs.python3Packages.buildbot-worker";
         description = "Package to use for buildbot worker.";
-        example = literalExample "pkgs.python3Packages.buildbot-worker";
+        example = literalExample "pkgs.python2Packages.buildbot-worker";
       };
 
       packages = mkOption {
diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix
index 467feb09b3a..89291d4438f 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -103,6 +103,24 @@ in
       };
 
       initialDatabases = mkOption {
+        type = types.listOf (types.submodule {
+          options = {
+            name = mkOption {
+              type = types.str;
+              description = ''
+                The name of the database to create.
+              '';
+            };
+            schema = mkOption {
+              type = types.nullOr types.path;
+              default = null;
+              description = ''
+                The initial schema of the database; if null (the default),
+                an empty database is created.
+              '';
+            };
+          };
+        });
         default = [];
         description = ''
           List of database names and their initial schemas that should be used to create databases on the first startup
@@ -115,11 +133,13 @@ in
       };
 
       initialScript = mkOption {
+        type = types.nullOr types.lines;
         default = null;
         description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database";
       };
 
       ensureDatabases = mkOption {
+        type = types.listOf types.str;
         default = [];
         description = ''
           Ensures that the specified databases exist.
@@ -134,6 +154,38 @@ in
       };
 
       ensureUsers = mkOption {
+        type = types.listOf (types.submodule {
+          options = {
+            name = mkOption {
+              type = types.str;
+              description = ''
+                Name of the user to ensure.
+              '';
+            };
+            ensurePermissions = mkOption {
+              type = types.attrsOf types.str;
+              default = {};
+              description = ''
+                Permissions to ensure for the user, specified as attribute set.
+                The attribute names specify the database and tables to grant the permissions for,
+                separated by a dot. You may use wildcards here.
+                The attribute values specfiy the permissions to grant.
+                You may specify one or multiple comma-separated SQL privileges here.
+
+                For more information on how to specify the target
+                and on which privileges exist, see the
+                <link xlink:href="https://mariadb.com/kb/en/library/grant/">GRANT syntax</link>.
+                The attributes are used as <code>GRANT ''${attrName} ON ''${attrValue}</code>.
+              '';
+              example = literalExample ''
+                {
+                  "database.*" = "ALL PRIVILEGES";
+                  "*.*" = "SELECT, LOCK TABLES";
+                }
+              '';
+            };
+          };
+        });
         default = [];
         description = ''
           Ensures that the specified users exist and have at least the ensured permissions.
@@ -143,20 +195,22 @@ in
           option is changed. This means that users created and permissions assigned once through this option or
           otherwise have to be removed manually.
         '';
-        example = literalExample ''[
-          {
-            name = "nextcloud";
-            ensurePermissions = {
-              "nextcloud.*" = "ALL PRIVILEGES";
-            };
-          }
-          {
-            name = "backup";
-            ensurePermissions = {
-              "*.*" = "SELECT, LOCK TABLES";
-            };
-          }
-        ]'';
+        example = literalExample ''
+          [
+            {
+              name = "nextcloud";
+              ensurePermissions = {
+                "nextcloud.*" = "ALL PRIVILEGES";
+              };
+            }
+            {
+              name = "backup";
+              ensurePermissions = {
+                "*.*" = "SELECT, LOCK TABLES";
+              };
+            }
+          ]
+        '';
       };
 
       # FIXME: remove this option; it's a really bad idea.
diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix
index 21c6a0b8db4..c101e7375af 100644
--- a/nixos/modules/services/databases/openldap.nix
+++ b/nixos/modules/services/databases/openldap.nix
@@ -8,7 +8,20 @@ let
   openldap = pkgs.openldap;
 
   dataFile = pkgs.writeText "ldap-contents.ldif" cfg.declarativeContents;
-  configFile = pkgs.writeText "slapd.conf" cfg.extraConfig;
+  configFile = pkgs.writeText "slapd.conf" ((optionalString cfg.defaultSchemas ''
+    include ${pkgs.openldap.out}/etc/schema/core.schema
+    include ${pkgs.openldap.out}/etc/schema/cosine.schema
+    include ${pkgs.openldap.out}/etc/schema/inetorgperson.schema
+    include ${pkgs.openldap.out}/etc/schema/nis.schema
+  '') + ''
+    ${cfg.extraConfig}
+    database ${cfg.database}
+    suffix ${cfg.suffix}
+    rootdn ${cfg.rootdn}
+    rootpw ${cfg.rootpw}
+    directory ${cfg.dataDir}
+    ${cfg.extraDatabaseConfig}
+  '');
   configOpts = if cfg.configDir == null then "-f ${configFile}"
                else "-F ${cfg.configDir}";
 in
@@ -54,6 +67,52 @@ in
         description = "The database directory.";
       };
 
+      defaultSchemas = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Include the default schemas core, cosine, inetorgperson and nis.
+          This setting will be ignored if configDir is set.
+        '';
+      };
+
+      database = mkOption {
+        type = types.str;
+        default = "mdb";
+        description = ''
+          Database type to use for the LDAP.
+          This setting will be ignored if configDir is set.
+        '';
+      };
+
+      suffix = mkOption {
+        type = types.str;
+        example = "dc=example,dc=org";
+        description = ''
+          Specify the DN suffix of queries that will be passed to this backend
+          database.
+          This setting will be ignored if configDir is set.
+        '';
+      };
+
+      rootdn = mkOption {
+        type = types.str;
+        example = "cn=admin,dc=example,dc=org";
+        description = ''
+          Specify the distinguished name that is not subject to access control
+          or administrative limit restrictions for operations on this database.
+          This setting will be ignored if configDir is set.
+        '';
+      };
+
+      rootpw = mkOption {
+        type = types.str;
+        description = ''
+          Password for the root user.
+          This setting will be ignored if configDir is set.
+        '';
+      };
+
       logLevel = mkOption {
         type = types.str;
         default = "0";
@@ -118,6 +177,39 @@ in
           # ...
         '';
       };
+
+      extraDatabaseConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          slapd.conf configuration after the database option.
+          This setting will be ignored if configDir is set.
+        '';
+        example = ''
+          # Indices to maintain for this directory
+          # unique id so equality match only
+          index uid eq
+          # allows general searching on commonname, givenname and email
+          index cn,gn,mail eq,sub
+          # allows multiple variants on surname searching
+          index sn eq,sub
+          # sub above includes subintial,subany,subfinal
+          # optimise department searches
+          index ou eq
+          # if searches will include objectClass uncomment following
+          # index objectClass eq
+          # shows use of default index parameter
+          index default eq,sub
+          # indices missing - uses default eq,sub
+          index telephonenumber
+
+          # other database parameters
+          # read more in slapd.conf reference section
+          cachesize 10000
+          checkpoint 128 15
+        '';
+      };
+
     };
 
   };
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index aeab445a998..87b236dd5fd 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -238,6 +238,7 @@ in
             User = "postgres";
             Group = "postgres";
             PermissionsStartOnly = true;
+            RuntimeDirectory = "postgresql";
             Type = if lib.versionAtLeast cfg.package.version "9.6"
                    then "notify"
                    else "simple";
diff --git a/nixos/modules/services/desktops/gsignond.nix b/nixos/modules/services/desktops/gsignond.nix
index cf26e05d5c1..5ab9add9f32 100644
--- a/nixos/modules/services/desktops/gsignond.nix
+++ b/nixos/modules/services/desktops/gsignond.nix
@@ -9,6 +9,8 @@ let
 in
 {
 
+  meta.maintainers = pkgs.pantheon.maintainers;
+
   ###### interface
 
   options = {
diff --git a/nixos/modules/services/desktops/pantheon/contractor.nix b/nixos/modules/services/desktops/pantheon/contractor.nix
index bd538db7241..2638a21df73 100644
--- a/nixos/modules/services/desktops/pantheon/contractor.nix
+++ b/nixos/modules/services/desktops/pantheon/contractor.nix
@@ -6,6 +6,8 @@ with lib;
 
 {
 
+  meta.maintainers = pkgs.pantheon.maintainers;
+
   ###### interface
 
   options = {
diff --git a/nixos/modules/services/desktops/pantheon/files.nix b/nixos/modules/services/desktops/pantheon/files.nix
index 2edbe5b3a6d..577aad6c298 100644
--- a/nixos/modules/services/desktops/pantheon/files.nix
+++ b/nixos/modules/services/desktops/pantheon/files.nix
@@ -6,6 +6,8 @@ with lib;
 
 {
 
+  meta.maintainers = pkgs.pantheon.maintainers;
+
   ###### interface
 
   options = {
diff --git a/nixos/modules/services/mail/davmail.nix b/nixos/modules/services/mail/davmail.nix
index a0cb81f84da..5b5cc294e5c 100644
--- a/nixos/modules/services/mail/davmail.nix
+++ b/nixos/modules/services/mail/davmail.nix
@@ -58,18 +58,26 @@ in
 
     config = mkIf cfg.enable {
 
-      services.davmail.config.davmail = mapAttrs (name: mkDefault) {
-        server = true;
-        disableUpdateCheck = true;
-        logFilePath = "/var/log/davmail/davmail.log";
-        logFileSize = "1MB";
-        mode = "auto";
-        url = cfg.url;
-        caldavPort = 1080;
-        imapPort = 1143;
-        ldapPort = 1389;
-        popPort = 1110;
-        smtpPort = 1025;
+      services.davmail.config = {
+        davmail = mapAttrs (name: mkDefault) {
+          server = true;
+          disableUpdateCheck = true;
+          logFilePath = "/var/log/davmail/davmail.log";
+          logFileSize = "1MB";
+          mode = "auto";
+          url = cfg.url;
+          caldavPort = 1080;
+          imapPort = 1143;
+          ldapPort = 1389;
+          popPort = 1110;
+          smtpPort = 1025;
+        };
+        log4j = {
+          logger.davmail = mkDefault "WARN";
+          logger.httpclient.wire = mkDefault "WARN";
+          logger.org.apache.commons.httpclient = mkDefault "WARN";
+          rootLogger = mkDefault "WARN";
+        };
       };
 
       systemd.services.davmail = {
diff --git a/nixos/modules/services/mail/mailcatcher.nix b/nixos/modules/services/mail/mailcatcher.nix
new file mode 100644
index 00000000000..2c6aadadce9
--- /dev/null
+++ b/nixos/modules/services/mail/mailcatcher.nix
@@ -0,0 +1,60 @@
+{ config, pkgs, lib, ... }:
+
+let
+  cfg = config.services.mailcatcher;
+
+  inherit (lib) mkEnableOption mkIf mkOption types;
+in
+{
+  # interface
+
+  options = {
+
+    services.mailcatcher = {
+      enable = mkEnableOption "Enable MailCatcher.";
+
+      http.ip = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = "The ip address of the http server.";
+      };
+
+      http.port = mkOption {
+        type = types.port;
+        default = 1080;
+        description = "The port address of the http server.";
+      };
+
+      smtp.ip = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = "The ip address of the smtp server.";
+      };
+
+      smtp.port = mkOption {
+        type = types.port;
+        default = 1025;
+        description = "The port address of the smtp server.";
+      };
+    };
+
+  };
+
+  # implementation
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.mailcatcher ];
+
+    systemd.services.mailcatcher = {
+      description = "MailCatcher Service";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        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}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix
index f3d90e532c8..c87607d2666 100644
--- a/nixos/modules/services/misc/docker-registry.nix
+++ b/nixos/modules/services/misc/docker-registry.nix
@@ -14,9 +14,10 @@ let
     log.fields.service = "registry";
     storage = {
       cache.blobdescriptor = blobCache;
-      filesystem.rootdirectory = cfg.storagePath;
       delete.enabled = cfg.enableDelete;
-    };
+    } // (if cfg.storagePath != null
+          then { filesystem.rootdirectory = cfg.storagePath; }
+          else {});
     http = {
       addr = "${cfg.listenAddress}:${builtins.toString cfg.port}";
       headers.X-Content-Type-Options = ["nosniff"];
@@ -61,9 +62,12 @@ in {
     };
 
     storagePath = mkOption {
-      type = types.path;
+      type = types.nullOr types.path;
       default = "/var/lib/docker-registry";
-      description = "Docker registry storage path.";
+      description = ''
+        Docker registry storage path for the filesystem storage backend. Set to
+        null to configure another backend via extraConfig.
+      '';
     };
 
     enableDelete = mkOption {
@@ -140,9 +144,12 @@ in {
       startAt = optional cfg.enableGarbageCollect cfg.garbageCollectDates;
     };
 
-    users.users.docker-registry = {
-      createHome = true;
-      home = cfg.storagePath;
-    };
+    users.users.docker-registry =
+      if cfg.storagePath != null
+      then {
+        createHome = true;
+        home = cfg.storagePath;
+      }
+      else {};
   };
 }
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index baa1c855c11..71277b48ecd 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -160,6 +160,22 @@ let
      '';
   };
 
+  gitlab-rails = pkgs.stdenv.mkDerivation rec {
+    name = "gitlab-rails";
+    buildInputs = [ pkgs.makeWrapper ];
+    dontBuild = true;
+    unpackPhase = ":";
+    installPhase = ''
+      mkdir -p $out/bin
+      makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rails $out/bin/gitlab-rails \
+          ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \
+          --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar config.services.postgresql.package pkgs.coreutils pkgs.procps ]}:$PATH' \
+          --run 'cd ${cfg.packages.gitlab}/share/gitlab'
+     '';
+  };
+
+  extraGitlabRb = pkgs.writeText "extra-gitlab.rb" cfg.extraGitlabRb;
+
   smtpSettings = pkgs.writeText "gitlab-smtp-settings.rb" ''
     if Rails.env.production?
       Rails.application.config.action_mailer.delivery_method = :smtp
@@ -266,6 +282,26 @@ in {
         description = "Extra configuration in config/database.yml.";
       };
 
+      extraGitlabRb = mkOption {
+        type = types.str;
+        default = "";
+        example = ''
+          if Rails.env.production?
+            Rails.application.config.action_mailer.delivery_method = :sendmail
+            ActionMailer::Base.delivery_method = :sendmail
+            ActionMailer::Base.sendmail_settings = {
+              location: "/run/wrappers/bin/sendmail",
+              arguments: "-i -t"
+            }
+          end
+        '';
+        description = ''
+          Extra configuration to be placed in config/extra-gitlab.rb. This can
+          be used to add configuration not otherwise exposed through this module's
+          options.
+        '';
+      };
+
       host = mkOption {
         type = types.str;
         default = config.networking.hostName;
@@ -439,7 +475,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.git gitlab-rake cfg.packages.gitlab-shell ];
+    environment.systemPackages = [ pkgs.git gitlab-rake gitlab-rails cfg.packages.gitlab-shell ];
 
     # Redis is required for the sidekiq queue runner.
     services.redis.enable = mkDefault true;
@@ -512,6 +548,7 @@ in {
       wantedBy = [ "multi-user.target" ];
       path = with pkgs; [
         openssh
+        procps  # See https://gitlab.com/gitlab-org/gitaly/issues/1562
         gitAndTools.git
         cfg.packages.gitaly.rubyEnv
         cfg.packages.gitaly.rubyEnv.wrappedRuby
@@ -586,6 +623,7 @@ in {
         [ -L /run/gitlab/uploads ] || ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads
         cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
         cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
+        ln -sf ${extraGitlabRb} ${cfg.statePath}/config/initializers/extra-gitlab.rb
         ${optionalString cfg.smtp.enable ''
           ln -sf ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb
         ''}
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index b06c1c4bbc6..fce9b29011f 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -146,7 +146,7 @@ in
         PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6";
         PLEX_MEDIA_SERVER_TMPDIR="/tmp";
         PLEX_MEDIA_SERVER_USE_SYSLOG="true";
-        LD_LIBRARY_PATH="/run/opengl-driver/lib:${cfg.package}/usr/lib/plexmediaserver";
+        LD_LIBRARY_PATH="/run/opengl-driver/lib:${cfg.package}/usr/lib/plexmediaserver/lib";
         LC_ALL="en_US.UTF-8";
         LANG="en_US.UTF-8";
       };
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index aba64e4f60f..4ea891262e5 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -261,10 +261,14 @@ let
     fi
   '';
 
+  canonicalizePortList =
+    ports: lib.unique (builtins.sort builtins.lessThan ports);
+
   commonOptions = {
     allowedTCPPorts = mkOption {
-      type = types.listOf types.int;
+      type = types.listOf types.port;
       default = [ ];
+      apply = canonicalizePortList;
       example = [ 22 80 ];
       description =
         '' 
@@ -274,7 +278,7 @@ let
     };
 
     allowedTCPPortRanges = mkOption {
-      type = types.listOf (types.attrsOf types.int);
+      type = types.listOf (types.attrsOf types.port);
       default = [ ];
       example = [ { from = 8999; to = 9003; } ];
       description =
@@ -285,8 +289,9 @@ let
     };
 
     allowedUDPPorts = mkOption {
-      type = types.listOf types.int;
+      type = types.listOf types.port;
       default = [ ];
+      apply = canonicalizePortList;
       example = [ 53 ];
       description =
         ''
@@ -295,7 +300,7 @@ let
     };
 
     allowedUDPPortRanges = mkOption {
-      type = types.listOf (types.attrsOf types.int);
+      type = types.listOf (types.attrsOf types.port);
       default = [ ];
       example = [ { from = 60000; to = 61000; } ];
       description =
diff --git a/nixos/modules/services/networking/quicktun.nix b/nixos/modules/services/networking/quicktun.nix
new file mode 100644
index 00000000000..5bcf923f909
--- /dev/null
+++ b/nixos/modules/services/networking/quicktun.nix
@@ -0,0 +1,118 @@
+{ config, pkgs, lib, ... }:
+
+let
+
+  cfg = config.services.quicktun;
+
+in
+
+with lib;
+
+{
+  options = {
+
+    services.quicktun = mkOption {
+      default = { };
+      description = "QuickTun tunnels";
+      type = types.attrsOf (types.submodule {
+        options = {
+          tunMode = mkOption {
+            type = types.int;
+            default = 0;
+            example = 1;
+            description = "";
+          };
+
+          remoteAddress = mkOption {
+            type = types.str;
+            example = "tunnel.example.com";
+            description = "";
+          };
+
+          localAddress = mkOption {
+            type = types.str;
+            example = "0.0.0.0";
+            description = "";
+          };
+
+          localPort = mkOption {
+            type = types.int;
+            default = 2998;
+            description = "";
+          };
+
+          remotePort = mkOption {
+            type = types.int;
+            default = 2998;
+            description = "";
+          };
+
+          remoteFloat = mkOption {
+            type = types.int;
+            default = 0;
+            description = "";
+          };
+
+          protocol = mkOption {
+            type = types.str;
+            default = "nacltai";
+            description = "";
+          };
+
+          privateKey = mkOption {
+            type = types.str;
+            description = "";
+          };
+
+          publicKey = mkOption {
+            type = types.str;
+            description = "";
+          };
+
+          timeWindow = mkOption {
+            type = types.int;
+            default = 5;
+            description = "";
+          };
+
+          upScript = mkOption {
+            type = types.lines;
+            default = "";
+            description = "";
+          };
+        };
+      });
+    };
+
+  };
+
+  config = mkIf (cfg != []) {
+    systemd.services = fold (a: b: a // b) {} (
+      mapAttrsToList (name: qtcfg: {
+        "quicktun-${name}" = {
+          wantedBy = [ "multi-user.target" ];
+          after = [ "network.target" ];
+          environment = {
+            "INTERFACE" = name;
+            "TUN_MODE" = toString qtcfg.tunMode;
+            "REMOTE_ADDRESS" = qtcfg.remoteAddress;
+            "LOCAL_ADDRESS" = qtcfg.localAddress;
+            "LOCAL_PORT" = toString qtcfg.localPort;
+            "REMOTE_PORT" = toString qtcfg.remotePort;
+            "REMOTE_FLOAT" = toString qtcfg.remoteFloat;
+            "PRIVATE_KEY" = qtcfg.privateKey;
+            "PUBLIC_KEY" = qtcfg.publicKey;
+            "TIME_WINDOW" = toString qtcfg.timeWindow;
+            "TUN_UP_SCRIPT" = pkgs.writeScript "quicktun-${name}-up.sh" qtcfg.upScript;
+            "SUID" = "nobody";
+          };
+          serviceConfig = {
+            Type = "simple";
+            ExecStart = "${pkgs.quicktun}/bin/quicktun.${qtcfg.protocol}";
+          };
+        };
+      }) cfg
+    );
+  };
+
+}
diff --git a/nixos/modules/services/scheduling/cron.nix b/nixos/modules/services/scheduling/cron.nix
index 6f6977b38a1..3bc31832946 100644
--- a/nixos/modules/services/scheduling/cron.nix
+++ b/nixos/modules/services/scheduling/cron.nix
@@ -64,8 +64,8 @@ in
           sendmail. See <option>security.wrappers</option>
 
           If neither /var/cron/cron.deny nor /var/cron/cron.allow exist only root
-          will is allowed to have its own crontab file. The /var/cron/cron.deny file
-          is created automatically for you. So every user can use a crontab.
+          is allowed to have its own crontab file. The /var/cron/cron.deny file
+          is created automatically for you, so every user can use a crontab.
 
           Many nixos modules set systemCronJobs, so if you decide to disable vixie cron
           and enable another cron daemon, you may want it to get its system crontab
diff --git a/nixos/modules/services/search/elasticsearch-curator.nix b/nixos/modules/services/search/elasticsearch-curator.nix
index 8cb1275284a..9620c3e0b6d 100644
--- a/nixos/modules/services/search/elasticsearch-curator.nix
+++ b/nixos/modules/services/search/elasticsearch-curator.nix
@@ -86,7 +86,7 @@ in {
       startAt = cfg.interval;
       serviceConfig = {
         ExecStart =
-          "${pkgs.python3Packages.elasticsearch-curator}/bin/curator" +
+          "${pkgs.elasticsearch-curator}/bin/curator" +
           " --config ${curatorConfig} ${curatorAction}";
       };
     };
diff --git a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
index 50775c5262f..644aad82df2 100644
--- a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
+++ b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
@@ -3,112 +3,18 @@
   poolName = "icingaweb2";
   phpfpmSocketName = "/var/run/phpfpm/${poolName}.sock";
 
-  formatBool = b: if b then "1" else "0";
-
-  configIni = let
-    config = cfg.generalConfig;
-  in ''
-    [global]
-    show_stacktraces = "${formatBool config.showStacktraces}"
-    show_application_state_messages = "${formatBool config.showApplicationStateMessages}"
-    module_path = "${pkgs.icingaweb2}/modules${optionalString (builtins.length config.modulePath > 0) ":${concatStringsSep ":" config.modulePath}"}"
-    config_backend = "${config.configBackend}"
-    ${optionalString (config.configBackend == "db") ''config_resource = "${config.configResource}"''}
-
-    [logging]
-    log = "${config.log}"
-    ${optionalString (config.log != "none") ''level = "${config.logLevel}"''}
-    ${optionalString (config.log == "php" || config.log == "syslog") ''application = "${config.logApplication}"''}
-    ${optionalString (config.log == "syslog") ''facility = "${config.logFacility}"''}
-    ${optionalString (config.log == "file") ''file = "${config.logFile}"''}
-
-    [themes]
-    default = "${config.themeDefault}"
-    disabled = "${formatBool config.themeDisabled}"
-
-    [authentication]
-    ${optionalString (config.authDefaultDomain != null) ''default_domain = "${config.authDefaultDomain}"''}
-  '';
-
-  resourcesIni = concatStringsSep "\n" (mapAttrsToList (name: config: ''
-    [${name}]
-    type = "${config.type}"
-    ${optionalString (config.type == "db") ''
-      db = "${config.db}"
-      host = "${config.host}"
-      ${optionalString (config.port != null) ''port = "${toString config.port}"''}
-      username = "${config.username}"
-      password = "${config.password}"
-      dbname = "${config.dbname}"
-      ${optionalString (config.charset != null) ''charset = "${config.charset}"''}
-      use_ssl = "${formatBool config.useSSL}"
-      ${optionalString (config.sslCert != null) ''ssl_cert = "${config.sslCert}"''}
-      ${optionalString (config.sslKey != null) ''ssl_cert = "${config.sslKey}"''}
-      ${optionalString (config.sslCA != null) ''ssl_cert = "${config.sslCA}"''}
-      ${optionalString (config.sslCApath != null) ''ssl_cert = "${config.sslCApath}"''}
-      ${optionalString (config.sslCipher != null) ''ssl_cert = "${config.sslCipher}"''}
-    ''}
-    ${optionalString (config.type == "ldap") ''
-      hostname = "${config.host}"
-      ${optionalString (config.port != null) ''port = "${toString config.port}"''}
-      root_dn = "${config.rootDN}"
-      bind_dn = "${config.username}"
-      bind_pw = "${config.password}"
-      encryption = "${config.ldapEncryption}"
-      timeout = "${toString config.ldapTimeout}"
-    ''}
-    ${optionalString (config.type == "ssh") ''
-      user = "${config.username}"
-      private_key = "${config.sshPrivateKey}"
-    ''}
-
-  '') cfg.resources);
-
-  authenticationIni = concatStringsSep "\n" (mapAttrsToList (name: config: ''
-    [${name}]
-    backend = "${config.backend}"
-    ${optionalString (config.domain != null) ''domain = "${config.domain}"''}
-    ${optionalString (config.backend == "external" && config.externalStripRegex != null) ''strip_username_regexp = "${config.externalStripRegex}"''}
-    ${optionalString (config.backend != "external") ''resource = "${config.resource}"''}
-    ${optionalString (config.backend == "ldap" || config.backend == "msldap") ''
-      ${optionalString (config.ldapUserClass != null) ''user_class = "${config.ldapUserClass}"''}
-      ${optionalString (config.ldapUserNameAttr != null) ''user_name_attribute = "${config.ldapUserNameAttr}"''}
-      ${optionalString (config.ldapFilter != null) ''filter = "${config.ldapFilter}"''}
-    ''}
-  '') cfg.authentications);
-
-  groupsIni = concatStringsSep "\n" (mapAttrsToList (name: config: ''
-    [${name}]
-    backend = "${config.backend}"
-    resource = "${config.resource}"
-    ${optionalString (config.backend != "db") ''
-      ${optionalString (config.ldapUserClass != null) ''user_class = "${config.ldapUserClass}"''}
-      ${optionalString (config.ldapUserNameAttr != null) ''user_name_attribute = "${config.ldapUserNameAttr}"''}
-      ${optionalString (config.ldapGroupClass != null) ''group_class = "${config.ldapGroupClass}"''}
-      ${optionalString (config.ldapGroupNameAttr != null) ''group_name_attribute = "${config.ldapGroupNameAttr}"''}
-      ${optionalString (config.ldapGroupFilter != null) ''group_filter = "${config.ldapGroupFilter}"''}
-    ''}
-    ${optionalString (config.backend == "msldap" && config.ldapNestedSearch) ''nested_group_search = "1"''}
-  '') cfg.groupBackends);
-
-  rolesIni = let
-    optionalList = var: attribute: optionalString (builtins.length var > 0) ''${attribute} = "${concatStringsSep "," var}"'';
-  in concatStringsSep "\n" (mapAttrsToList (name: config: ''
-    [${name}]
-    ${optionalList config.users "users"}
-    ${optionalList config.groups "groups"}
-    ${optionalList config.permissions "permissions"}
-    ${optionalList config.permissions "permissions"}
-    ${concatStringsSep "\n" (mapAttrsToList (key: value: optionalList value key) config.extraAssignments)}
-  '') cfg.roles);
-
+  defaultConfig = {
+    global = {
+      module_path = "${pkgs.icingaweb2}/modules${optionalString (builtins.length config.modulePath > 0) ":${concatStringsSep ":" config.modulePath}"}";
+    };
+  };
 in {
   options.services.icingaweb2 = with types; {
     enable = mkEnableOption "the icingaweb2 web interface";
 
     pool = mkOption {
       type = str;
-      default = "${poolName}";
+      default = poolName;
       description = ''
          Name of existing PHP-FPM pool that is used to run Icingaweb2.
          If not specified, a pool will automatically created with default values.
@@ -143,7 +49,7 @@ in {
       default = {};
       example = literalExample ''
         {
-          "snow" = pkgs.icingaweb2Modules.theme-snow;
+          "snow" = icingaweb2Modules.theme-snow;
         }
       '';
       description = ''
@@ -153,419 +59,130 @@ in {
       '';
     };
 
-    generalConfig = {
-      mutable = mkOption {
-        type = bool;
-        default = false;
-        description = ''
-          Make config.ini mutable (e.g. via the web interface).
-          Not that you need to update module_path manually.
-        '';
-      };
-
-      showStacktraces = mkOption {
-        type = bool;
-        default = true;
-        description = "Enable stack traces in the Web UI";
-      };
-
-      showApplicationStateMessages = mkOption {
-        type = bool;
-        default = true;
-        description = "Enable application state messages in the Web UI";
-      };
-
-      modulePath = mkOption {
-        type = listOf str;
-        default = [];
-        description = "List of additional module search paths";
-      };
-
-      configBackend = mkOption {
-        type = enum [ "ini" "db" "none" ];
-        default = "db";
-        description = "Where to store user preferences";
-      };
-
-      configResource = mkOption {
-        type = nullOr str;
-        default = null;
-        description = "Database resource where user preferences are stored (if they are stored in a database)";
-      };
-
-      log = mkOption {
-        type = enum [ "syslog" "php" "file" "none" ];
-        default = "syslog";
-        description = "Logging target";
-      };
-
-      logLevel = mkOption {
-        type = enum [ "ERROR" "WARNING" "INFO" "DEBUG" ];
-        default = "ERROR";
-        description = "Maximum logging level to emit";
-      };
-
-      logApplication = mkOption {
-        type = str;
-        default = "icingaweb2";
-        description = "Application name to log under (syslog and php log)";
-      };
-
-      logFacility = mkOption {
-        type = enum [ "user" "local0" "local1" "local2" "local3" "local4" "local5" "local6" "local7" ];
-        default = "user";
-        description = "Syslog facility to log to";
-      };
-
-      logFile = mkOption {
-        type = str;
-        default = "/var/log/icingaweb2/icingaweb2.log";
-        description = "File to log to";
-      };
-
-      themeDefault = mkOption {
-        type = str;
-        default = "Icinga";
-        description = "Name of the default theme";
-      };
-
-      themeDisabled = mkOption {
-        type = bool;
-        default = false;
-        description = "Disallow users to change the theme";
-      };
-
-      authDefaultDomain = mkOption {
-        type = nullOr str;
-        default = null;
-        description = "Domain for users logging in without a qualified domain";
+    generalConfig = mkOption {
+      type = nullOr attrs;
+      default = null;
+      example = {
+        general = {
+          showStacktraces = 1;
+          config_resource = "icingaweb_db";
+        };
+        logging = {
+          log = "syslog";
+          level = "CRITICAL";
+        };
       };
-    };
+      description = ''
+        config.ini contents.
+        Will automatically be converted to a .ini file.
+        If you don't set global.module_path, the module will take care of it.
 
-    mutableResources = mkOption {
-      type = bool;
-      default = false;
-      description = "Make resources.ini mutable (e.g. via the web interface)";
+        If the value is null, no config.ini is created and you can
+        modify it manually (e.g. via the web interface).
+        Note that you need to update module_path manually.
+      '';
     };
 
     resources = mkOption {
-      default = {};
-      description = "Icingaweb 2 resources to define";
-      type = attrsOf (submodule ({ name, ... }: {
-        options = {
-          name = mkOption {
-            visible = false;
-            default = name;
-            type = str;
-            description = "Name of this resource";
-          };
-
-          type = mkOption {
-            type = enum [ "db" "ldap" "ssh" ];
-            default = "db";
-            description = "Type of this resouce";
-          };
-
-          db = mkOption {
-            type = enum [ "mysql" "pgsql" ];
-            default = "mysql";
-            description = "Type of this database resource";
-          };
-
-          host = mkOption {
-            type = str;
-            description = "Host to connect to";
-          };
-
-          port = mkOption {
-            type = nullOr port;
-            default = null;
-            description = "Port to connect on";
-          };
-
-          username = mkOption {
-            type = str;
-            description = "Database or SSH user or LDAP bind DN to connect with";
-          };
-
-          password = mkOption {
-            type = str;
-            description = "Password for the database user or LDAP bind DN";
-          };
-
-          dbname = mkOption {
-            type = str;
-            description = "Name of the database to connect to";
-          };
-
-          charset = mkOption {
-            type = nullOr str;
-            default = null;
-            example = "utf8";
-            description = "Database character set to connect with";
-          };
-
-          useSSL = mkOption {
-            type = nullOr bool;
-            default = false;
-            description = "Whether to connect to the database using SSL";
-          };
-
-          sslCert = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "The file path to the SSL certificate. Only available for the mysql database.";
-          };
-
-          sslKey = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "The file path to the SSL key. Only available for the mysql database.";
-          };
-
-          sslCA = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "The file path to the SSL certificate authority. Only available for the mysql database.";
-          };
-
-          sslCApath = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "The file path to the directory that contains the trusted SSL CA certificates in PEM format. Only available for the mysql database.";
-          };
-
-          sslCipher = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "A list of one or more permissible ciphers to use for SSL encryption, in a format understood by OpenSSL. Only available for the mysql database.";
-          };
-
-          rootDN = mkOption {
-            type = str;
-            description = "Root object of the LDAP tree";
-          };
-
-          ldapEncryption = mkOption {
-            type = enum [ "none" "starttls" "ldaps" ];
-            default = "none";
-            description = "LDAP encryption to use";
-          };
-
-          ldapTimeout = mkOption {
-            type = ints.positive;
-            default = 5;
-            description = "Connection timeout for every LDAP connection";
-          };
-
-          sshPrivateKey = mkOption {
-            type = str;
-            description = "The path to the private key of the user";
-          };
+      type = nullOr attrs;
+      default = null;
+      example = {
+        icingaweb_db = {
+          type = "db";
+          db = "mysql";
+          host = "localhost";
+          username = "icingaweb2";
+          password = "icingaweb2";
+          dbname = "icingaweb2";
         };
-      }));
-    };
+      };
+      description = ''
+        resources.ini contents.
+        Will automatically be converted to a .ini file.
 
-    mutableAuthConfig = mkOption {
-      type = bool;
-      default = true;
-      description = "Make authentication.ini mutable (e.g. via the web interface)";
+        If the value is null, no resources.ini is created and you can
+        modify it manually (e.g. via the web interface).
+        Note that if you set passwords here, they will go into the nix store.
+      '';
     };
 
     authentications = mkOption {
-      default = {};
-      description = "Icingaweb 2 authentications to define";
-      type = attrsOf (submodule ({ name, ... }: {
-        options = {
-          name = mkOption {
-            visible = false;
-            default = name;
-            type = str;
-            description = "Name of this authentication";
-          };
-
-          backend = mkOption {
-            type = enum [ "external" "ldap" "msldap" "db" ];
-            default = "db";
-            description = "The type of this authentication backend";
-          };
-
-          domain = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "Domain for domain-aware authentication";
-          };
-
-          externalStripRegex = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "Regular expression to strip off specific user name parts";
-          };
-
-          resource = mkOption {
-            type = str;
-            description = "Name of the database/LDAP resource";
-          };
-
-          ldapUserClass = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP user class";
-          };
-
-          ldapUserNameAttr = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP attribute which contains the username";
-          };
-
-          ldapFilter = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP search filter";
-          };
+      type = nullOr attrs;
+      default = null;
+      example = {
+        icingaweb = {
+          backend = "db";
+          resource = "icingaweb_db";
         };
-      }));
-    };
+      };
+      description = ''
+        authentication.ini contents.
+        Will automatically be converted to a .ini file.
 
-    mutableGroupsConfig = mkOption {
-      type = bool;
-      default = true;
-      description = "Make groups.ini mutable (e.g. via the web interface)";
+        If the value is null, no authentication.ini is created and you can
+        modify it manually (e.g. via the web interface).
+      '';
     };
 
     groupBackends = mkOption {
-      default = {};
-      description = "Icingaweb 2 group backends to define";
-      type = attrsOf (submodule ({ name, ... }: {
-        options = {
-          name = mkOption {
-            visible = false;
-            default = name;
-            type = str;
-            description = "Name of this group backend";
-          };
-
-          backend = mkOption {
-            type = enum [ "ldap" "msldap" "db" ];
-            default = "db";
-            description = "The type of this group backend";
-          };
-
-          resource = mkOption {
-            type = str;
-            description = "Name of the database/LDAP resource";
-          };
-
-          ldapUserClass = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP user class";
-          };
-
-          ldapUserNameAttr = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP attribute which contains the username";
-          };
-
-          ldapGroupClass = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP group class";
-          };
-
-          ldapGroupNameAttr = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP attribute which contains the groupname";
-          };
-
-          ldapGroupFilter = mkOption {
-            type = nullOr str;
-            default = null;
-            description = "LDAP group search filter";
-          };
-
-          ldapNestedSearch = mkOption {
-            type = bool;
-            default = false;
-            description = "Enable nested group search in Active Directory based on the user";
-          };
+      type = nullOr attrs;
+      default = null;
+      example = {
+        icingaweb = {
+          backend = "db";
+          resource = "icingaweb_db";
         };
-      }));
-    };
+      };
+      description = ''
+        groups.ini contents.
+        Will automatically be converted to a .ini file.
 
-    mutableRolesConfig = mkOption {
-      type = bool;
-      default = true;
-      description = "Make roles.ini mutable (e.g. via the web interface)";
+        If the value is null, no groups.ini is created and you can
+        modify it manually (e.g. via the web interface).
+      '';
     };
 
     roles = mkOption {
-      default = {};
-      description = "Icingaweb 2 roles to define";
-      type = attrsOf (submodule ({ name, ... }: {
-        options = {
-          name = mkOption {
-            visible = false;
-            default = name;
-            type = str;
-            description = "Name of this role";
-          };
-
-          users = mkOption {
-            type = listOf str;
-            default = [];
-            description = "List of users that are assigned to the role";
-          };
-
-          groups = mkOption {
-            type = listOf str;
-            default = [];
-            description = "List of groups that are assigned to the role";
-          };
-
-          permissions = mkOption {
-            type = listOf str;
-            default = [];
-            example = [ "application/share/navigation" "config/*" ];
-            description = "The permissions to grant";
-          };
-
-          extraAssignments = mkOption {
-            type = attrsOf (listOf str);
-            default = {};
-            example = { "monitoring/blacklist/properties" = [ "sla" "customer"]; };
-            description = "Additional assignments of this role";
-          };
+      type = nullOr attrs;
+      default = null;
+      example = {
+        Administrators = {
+          users = "admin";
+          permissions = "*";
         };
-      }));
+      };
+      description = ''
+        roles.ini contents.
+        Will automatically be converted to a .ini file.
+
+        If the value is null, no roles.ini is created and you can
+        modify it manually (e.g. via the web interface).
+      '';
     };
   };
 
   config = mkIf cfg.enable {
     services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") {
-      "${poolName}" = {
-        listen = phpfpmSocketName;
-        phpOptions = ''
-          extension = ${pkgs.phpPackages.imagick}/lib/php/extensions/imagick.so
-          date.timezone = "${cfg.timezone}"
-        '';
-        extraConfig = ''
-          listen.owner = nginx
-          listen.group = nginx
-          listen.mode = 0600
-          user = icingaweb2
-          pm = dynamic
-          pm.max_children = 75
-          pm.start_servers = 2
-          pm.min_spare_servers = 2
-          pm.max_spare_servers = 10
-        '';
-      };
+      "${poolName}" = ''
+        listen = "${phpfpmSocketName}"
+        listen.owner = nginx
+        listen.group = nginx
+        listen.mode = 0600
+        user = icingaweb2
+        pm = dynamic
+        pm.max_children = 75
+        pm.start_servers = 2
+        pm.min_spare_servers = 2
+        pm.max_spare_servers = 10
+      '';
     };
 
+    services.phpfpm.phpOptions = mkIf (cfg.pool == "${poolName}")
+      ''
+        extension = ${pkgs.phpPackages.imagick}/lib/php/extensions/imagick.so
+        date.timezone = "${cfg.timezone}"
+      '';
+
     systemd.services."phpfpm-${poolName}".serviceConfig.ReadWritePaths = [ "/etc/icingaweb2" ];
 
     services.nginx = {
@@ -609,11 +226,11 @@ in {
       // doModule "test"
       // doModule "translation"
       # Configs
-      // optionalAttrs (!cfg.generalConfig.mutable) { "icingaweb2/config.ini".text = configIni; }
-      // optionalAttrs (!cfg.mutableResources) { "icingaweb2/resources.ini".text = resourcesIni; }
-      // optionalAttrs (!cfg.mutableAuthConfig) { "icingaweb2/authentication.ini".text = authenticationIni; }
-      // optionalAttrs (!cfg.mutableGroupsConfig) { "icingaweb2/groups.ini".text = groupsIni; }
-      // optionalAttrs (!cfg.mutableRolesConfig) { "icingaweb2/roles.ini".text = rolesIni; };
+      // optionalAttrs (cfg.generalConfig != null) { "icingaweb2/config.ini".text = generators.toINI {} (defaultConfig // cfg.generalConfig); }
+      // optionalAttrs (cfg.resources != null) { "icingaweb2/resources.ini".text = generators.toINI {} cfg.resources; }
+      // optionalAttrs (cfg.authentications != null) { "icingaweb2/authentication.ini".text = generators.toINI {} cfg.authentications; }
+      // optionalAttrs (cfg.groupBackends != null) { "icingaweb2/groups.ini".text = generators.toINI {} cfg.groupBackends; }
+      // optionalAttrs (cfg.roles != null) { "icingaweb2/roles.ini".text = generators.toINI {} cfg.roles; };
 
     # User and group
     users.groups.icingaweb2 = {};
diff --git a/nixos/modules/services/web-apps/matomo-doc.xml b/nixos/modules/services/web-apps/matomo-doc.xml
index 20d2de9f418..021a89be3f6 100644
--- a/nixos/modules/services/web-apps/matomo-doc.xml
+++ b/nixos/modules/services/web-apps/matomo-doc.xml
@@ -12,15 +12,15 @@
   An automatic setup is not suported by Matomo, so you need to configure Matomo
   itself in the browser-based Matomo setup.
  </para>
-
  <section xml:id="module-services-matomo-database-setup">
   <title>Database Setup</title>
+
   <para>
    You also need to configure a MariaDB or MySQL database and -user for Matomo
    yourself, and enter those credentials in your browser. You can use
    passwordless database authentication via the UNIX_SOCKET authentication
    plugin with the following SQL commands:
-   <programlisting>
+<programlisting>
         # For MariaDB
         INSTALL PLUGIN unix_socket SONAME 'auth_socket';
         CREATE DATABASE matomo;
@@ -46,30 +46,32 @@
    database is not on the same host.
   </para>
  </section>
-
  <section xml:id="module-services-matomo-archive-processing">
   <title>Archive Processing</title>
+
   <para>
-   This module comes with the systemd service <literal>matomo-archive-processing.service</literal>
-   and a timer that automatically triggers archive processing every hour.
-   This means that you can safely
+   This module comes with the systemd service
+   <literal>matomo-archive-processing.service</literal> and a timer that
+   automatically triggers archive processing every hour. This means that you
+   can safely
    <link xlink:href="https://matomo.org/docs/setup-auto-archiving/#disable-browser-triggers-for-matomo-archiving-and-limit-matomo-reports-to-updating-every-hour">
-    disable browser triggers for Matomo archiving
-   </link> at <literal>Administration > System > General Settings</literal>.
+   disable browser triggers for Matomo archiving </link> at
+   <literal>Administration > System > General Settings</literal>.
   </para>
+
   <para>
    With automatic archive processing, you can now also enable to
    <link xlink:href="https://matomo.org/docs/privacy/#step-2-delete-old-visitors-logs">
-    delete old visitor logs
-   </link> at <literal>Administration > System > Privacy</literal>,
-   but make sure that you run <literal>systemctl start matomo-archive-processing.service</literal>
-   at least once without errors if you have already collected data before,
-   so that the reports get archived before the source data gets deleted.
+   delete old visitor logs </link> at <literal>Administration > System >
+   Privacy</literal>, but make sure that you run <literal>systemctl start
+   matomo-archive-processing.service</literal> at least once without errors if
+   you have already collected data before, so that the reports get archived
+   before the source data gets deleted.
   </para>
  </section>
-
  <section xml:id="module-services-matomo-backups">
   <title>Backup</title>
+
   <para>
    You only need to take backups of your MySQL database and the
    <filename>/var/lib/matomo/config/config.ini.php</filename> file. Use a user
@@ -78,9 +80,9 @@
    <link xlink:href="https://matomo.org/faq/how-to-install/faq_138/" />.
   </para>
  </section>
-
  <section xml:id="module-services-matomo-issues">
   <title>Issues</title>
+
   <itemizedlist>
    <listitem>
     <para>
@@ -97,7 +99,6 @@
    </listitem>
   </itemizedlist>
  </section>
-
  <section xml:id="module-services-matomo-other-web-servers">
   <title>Using other Web Servers than nginx</title>
 
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index 5ad241ace5c..d0e45e1c12a 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -32,7 +32,7 @@ let
     cd ${pkgs.nextcloud}
     exec /run/wrappers/bin/sudo -u nextcloud \
       NEXTCLOUD_CONFIG_DIR="${cfg.home}/config" \
-      ${config.services.phpfpm.phpPackage}/bin/php \
+      ${phpPackage}/bin/php \
       -c ${pkgs.writeText "php.ini" phpOptionsStr}\
       occ $*
   '';
@@ -172,7 +172,7 @@ in {
           Database host.
 
           Note: for using Unix authentication with PostgreSQL, this should be
-          set to <literal>/tmp</literal>.
+          set to <literal>/run/postgresql</literal>.
         '';
       };
       dbport = mkOption {
@@ -360,7 +360,7 @@ in {
           environment.NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config";
           serviceConfig.Type = "oneshot";
           serviceConfig.User = "nextcloud";
-          serviceConfig.ExecStart = "${pkgs.php}/bin/php -f ${pkgs.nextcloud}/cron.php";
+          serviceConfig.ExecStart = "${phpPackage}/bin/php -f ${pkgs.nextcloud}/cron.php";
         };
       };
 
diff --git a/nixos/modules/services/web-apps/nextcloud.xml b/nixos/modules/services/web-apps/nextcloud.xml
index 9600d1be7c8..dfefa55c5d5 100644
--- a/nixos/modules/services/web-apps/nextcloud.xml
+++ b/nixos/modules/services/web-apps/nextcloud.xml
@@ -4,24 +4,26 @@
          version="5.0"
          xml:id="module-services-nextcloud">
  <title>Nextcloud</title>
-
  <para>
-  <link xlink:href="https://nextcloud.com/">Nextcloud</link> is an open-source, self-hostable cloud
-  platform. The server setup can be automated using
-  <link linkend="opt-services.nextcloud.enable">services.nextcloud</link>. A desktop client is packaged
-  at <literal>pkgs.nextcloud-client</literal>.
+  <link xlink:href="https://nextcloud.com/">Nextcloud</link> is an open-source,
+  self-hostable cloud platform. The server setup can be automated using
+  <link linkend="opt-services.nextcloud.enable">services.nextcloud</link>. A
+  desktop client is packaged at <literal>pkgs.nextcloud-client</literal>.
  </para>
-
  <section xml:id="module-services-nextcloud-basic-usage">
   <title>Basic usage</title>
+
   <para>
    Nextcloud is a PHP-based application which requires an HTTP server
-   (<literal><link linkend="opt-services.nextcloud.enable">services.nextcloud</link></literal> optionally supports
-   <literal><link linkend="opt-services.nginx.enable">services.nginx</link></literal>) and a database
-   (it's recommended to use <literal><link linkend="opt-services.postgresql.enable">services.postgresql</link></literal>).
+   (<literal><link linkend="opt-services.nextcloud.enable">services.nextcloud</link></literal>
+   optionally supports
+   <literal><link linkend="opt-services.nginx.enable">services.nginx</link></literal>)
+   and a database (it's recommended to use
+   <literal><link linkend="opt-services.postgresql.enable">services.postgresql</link></literal>).
   </para>
+
   <para>
-    A very basic configuration may look like this:
+   A very basic configuration may look like this:
 <programlisting>{ pkgs, ... }:
 {
   services.nextcloud = {
@@ -31,7 +33,7 @@
     config = {
       <link linkend="opt-services.nextcloud.config.dbtype">dbtype</link> = "pgsql";
       <link linkend="opt-services.nextcloud.config.dbuser">dbuser</link> = "nextcloud";
-      <link linkend="opt-services.nextcloud.config.dbhost">dbhost</link> = "/tmp"; # nextcloud will add /.s.PGSQL.5432 by itself
+      <link linkend="opt-services.nextcloud.config.dbhost">dbhost</link> = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
       <link linkend="opt-services.nextcloud.config.dbname">dbname</link> = "nextcloud";
       <link linkend="opt-services.nextcloud.config.adminpassFile">adminpassFile</link> = "/path/to/admin-pass-file";
       <link linkend="opt-services.nextcloud.config.adminuser">adminuser</link> = "root";
@@ -55,45 +57,59 @@
   <link linkend="opt-networking.firewall.allowedTCPPorts">networking.firewall.allowedTCPPorts</link> = [ 80 443 ];
 }</programlisting>
   </para>
+
   <para>
-   The options <literal>hostName</literal> and <literal>nginx.enable</literal> are used internally to configure an
-   HTTP server using <literal><link xlink:href="https://php-fpm.org/">PHP-FPM</link></literal> and <literal>nginx</literal>.
-   The <literal>config</literal> attribute set is used for the <literal>config.php</literal> which is used
-   for the application's configuration.
-   <emphasis>Beware: this isn't entirely pure since the config is modified by the application's runtime!</emphasis>
+   The options <literal>hostName</literal> and <literal>nginx.enable</literal>
+   are used internally to configure an HTTP server using
+   <literal><link xlink:href="https://php-fpm.org/">PHP-FPM</link></literal>
+   and <literal>nginx</literal>. The <literal>config</literal> attribute set is
+   used for the <literal>config.php</literal> which is used for the
+   application's configuration. <emphasis>Beware: this isn't entirely pure
+   since the config is modified by the application's runtime!</emphasis>
   </para>
+
   <para>
-    In case the application serves multiple hosts (those are checked with
-    <literal><link xlink:href="http://php.net/manual/en/reserved.variables.server.php">$_SERVER['HTTP_HOST']</link></literal>)
-    those can be added using
-    <literal><link linkend="opt-services.nextcloud.config.extraTrustedDomains">services.nextcloud.config.extraTrustedDomains</link></literal>.
+   In case the application serves multiple hosts (those are checked with
+   <literal><link xlink:href="http://php.net/manual/en/reserved.variables.server.php">$_SERVER['HTTP_HOST']</link></literal>)
+   those can be added using
+   <literal><link linkend="opt-services.nextcloud.config.extraTrustedDomains">services.nextcloud.config.extraTrustedDomains</link></literal>.
   </para>
  </section>
-
  <section xml:id="module-services-nextcloud-pitfalls-during-upgrade">
   <title>Pitfalls</title>
+
   <para>
-   Unfortunately Nextcloud appears to be very stateful when it comes to managing its own configuration. The
-   config file lives in the home directory of the <literal>nextcloud</literal> user (by default
-   <literal>/var/lib/nextcloud/config/config.php</literal>) and is also used to track several
-   states of the application (e.g. whether installed or not).
+   Unfortunately Nextcloud appears to be very stateful when it comes to
+   managing its own configuration. The config file lives in the home directory
+   of the <literal>nextcloud</literal> user (by default
+   <literal>/var/lib/nextcloud/config/config.php</literal>) and is also used to
+   track several states of the application (e.g. whether installed or not).
   </para>
+
   <para>
-   Right now changes to the <literal>services.nextcloud.config</literal> attribute set won't take effect
-   after the first install
-   (except <literal><link linkend="opt-services.nextcloud.config.extraTrustedDomains">services.nextcloud.config.extraTrustedDomains</link></literal>) since the actual configuration
-   file is generated by the NextCloud installer which also sets up critical parts such as the database
-   structure.
+   Right now changes to the <literal>services.nextcloud.config</literal>
+   attribute set won't take effect after the first install (except
+   <literal><link linkend="opt-services.nextcloud.config.extraTrustedDomains">services.nextcloud.config.extraTrustedDomains</link></literal>)
+   since the actual configuration file is generated by the NextCloud installer
+   which also sets up critical parts such as the database structure.
   </para>
+
   <para>
-   <emphasis>Warning: don't delete <literal>config.php</literal>! This file tracks the application's state and a deletion can cause unwanted side-effects!</emphasis>
+   <emphasis>Warning: don't delete <literal>config.php</literal>! This file
+   tracks the application's state and a deletion can cause unwanted
+   side-effects!</emphasis>
   </para>
+
   <para>
-   <emphasis>Warning: don't rerun <literal>nextcloud-occ maintenance:install</literal>! This command tries to install the application and can cause unwanted side-effects!</emphasis>
+   <emphasis>Warning: don't rerun <literal>nextcloud-occ
+   maintenance:install</literal>! This command tries to install the application
+   and can cause unwanted side-effects!</emphasis>
   </para>
+
   <para>
-    The issues are known and reported in <link xlink:href="https://github.com/NixOS/nixpkgs/issues/49783">#49783</link>, for now it's unfortunately necessary to manually work around these issues.
+   The issues are known and reported in
+   <link xlink:href="https://github.com/NixOS/nixpkgs/issues/49783">#49783</link>,
+   for now it's unfortunately necessary to manually work around these issues.
   </para>
  </section>
-
 </chapter>
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 1eac5be2f8d..8f00f81b078 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -705,10 +705,7 @@ in
 
         path =
           [ httpd pkgs.coreutils pkgs.gnugrep ]
-          ++ # Needed for PHP's mail() function.  !!! Probably the
-             # ssmtp module should export the path to sendmail in
-             # some way.
-             optional config.networking.defaultMailServer.directDelivery pkgs.ssmtp
+          ++ optional enablePHP pkgs.system-sendmail # Needed for PHP's mail() function.
           ++ concatMap (svc: svc.extraServerPath) allSubservices;
 
         environment =
diff --git a/nixos/modules/services/web-servers/meguca.nix b/nixos/modules/services/web-servers/meguca.nix
index 11aebcb91d8..5a00070dc94 100644
--- a/nixos/modules/services/web-servers/meguca.nix
+++ b/nixos/modules/services/web-servers/meguca.nix
@@ -86,11 +86,19 @@ in with lib; {
       default = false;
       description = "Serve and listen only through HTTPS.";
     };
+
+    videoPaths = mkOption {
+      type = types.listOf types.path;
+      default = [];
+      example = [ "/home/okina/Videos/tehe_pero.webm" ];
+      description = "Videos that will be symlinked into www/videos.";
+    };
   };
 
   config = mkIf cfg.enable {
     security.sudo.enable = cfg.enable;
     services.postgresql.enable = cfg.enable;
+    services.postgresql.package = pkgs.postgresql_11;
     services.meguca.passwordFile = mkDefault (pkgs.writeText "meguca-password-file" cfg.password);
     services.meguca.postgresArgsFile = mkDefault (pkgs.writeText "meguca-postgres-args" cfg.postgresArgs);
     services.meguca.postgresArgs = mkDefault "user=meguca password=${cfg.password} dbname=meguca sslmode=disable";
@@ -102,8 +110,16 @@ in with lib; {
 
       preStart = ''
         # Ensure folder exists or create it and links and permissions are correct
-        mkdir -p ${escapeShellArg cfg.dataDir}
-        ln -sf ${pkgs.meguca}/share/meguca/www ${escapeShellArg cfg.dataDir}
+        mkdir -p ${escapeShellArg cfg.dataDir}/www
+        rm -rf ${escapeShellArg cfg.dataDir}/www/videos
+        ln -sf ${pkgs.meguca}/share/meguca/www/* ${escapeShellArg cfg.dataDir}/www
+        unlink ${escapeShellArg cfg.dataDir}/www/videos
+        mkdir -p ${escapeShellArg cfg.dataDir}/www/videos
+
+        for vid in ${escapeShellArg cfg.videoPaths}; do
+          ln -sf $vid ${escapeShellArg cfg.dataDir}/www/videos
+        done
+
         chmod 750 ${escapeShellArg cfg.dataDir}
         chown -R meguca:meguca ${escapeShellArg cfg.dataDir}
 
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 1c9fbe048f8..3a154ab75ba 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -44,19 +44,7 @@ let
     }
   ''));
 
-  awkFormat = builtins.toFile "awkFormat-nginx.awk" ''
-    awk -f
-    {sub(/^[ \t]+/,"");idx=0}
-    /\{/{ctx++;idx=1}
-    /\}/{ctx--}
-    {id="";for(i=idx;i<ctx;i++)id=sprintf("%s%s", id, "\t");printf "%s%s\n", id, $0}
-  '';
-
-  configFile = pkgs.runCommand "nginx.conf" {} (''
-    awk -f ${awkFormat} ${pre-configFile} | sed '/^\s*$/d' > $out
-  '');
-
-  pre-configFile = pkgs.writeText "pre-nginx.conf" ''
+  configFile = pkgs.writers.writeNginxConfig "nginx.conf" ''
     user ${cfg.user} ${cfg.group};
     error_log ${cfg.logError};
     daemon off;
@@ -276,6 +264,7 @@ let
       ${optionalString (config.tryFiles != null) "try_files ${config.tryFiles};"}
       ${optionalString (config.root != null) "root ${config.root};"}
       ${optionalString (config.alias != null) "alias ${config.alias};"}
+      ${optionalString (config.return != null) "return ${config.return};"}
       ${config.extraConfig}
       ${optionalString (config.proxyPass != null && cfg.recommendedProxySettings) "include ${recommendedProxyConfig};"}
     }
@@ -373,7 +362,7 @@ in
       preStart =  mkOption {
         type = types.lines;
         default = ''
-          test -d ${cfg.stateDir}/logs || mkdir -m 750 -p ${cfg.stateDir}/logs  
+          test -d ${cfg.stateDir}/logs || mkdir -m 750 -p ${cfg.stateDir}/logs
           test `stat -c %a ${cfg.stateDir}` = "750" || chmod 750 ${cfg.stateDir}
           test `stat -c %a ${cfg.stateDir}/logs` = "750" || chmod 750 ${cfg.stateDir}/logs
           chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir}
diff --git a/nixos/modules/services/web-servers/nginx/location-options.nix b/nixos/modules/services/web-servers/nginx/location-options.nix
index 9b44433d384..aeb9b1dd79e 100644
--- a/nixos/modules/services/web-servers/nginx/location-options.nix
+++ b/nixos/modules/services/web-servers/nginx/location-options.nix
@@ -64,6 +64,15 @@ with lib;
       '';
     };
 
+    return = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      example = "301 http://example.com$request_uri;";
+      description = ''
+        Adds a return directive, for e.g. redirections.
+      '';
+    };
+
     extraConfig = mkOption {
       type = types.lines;
       default = "";
diff --git a/nixos/modules/services/web-servers/unit/default.nix b/nixos/modules/services/web-servers/unit/default.nix
new file mode 100644
index 00000000000..a4a9d370d64
--- /dev/null
+++ b/nixos/modules/services/web-servers/unit/default.nix
@@ -0,0 +1,125 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.unit;
+
+  configFile = pkgs.writeText "unit.json" cfg.config;
+
+in {
+  options = {
+    services.unit = {
+      enable = mkEnableOption "Unit App Server";
+      package = mkOption {
+        type = types.package;
+        default = pkgs.unit;
+        defaultText = "pkgs.unit";
+        description = "Unit package to use.";
+      };
+      user = mkOption {
+        type = types.str;
+        default = "unit";
+        description = "User account under which unit runs.";
+      };
+      group = mkOption {
+        type = types.str;
+        default = "unit";
+        description = "Group account under which unit runs.";
+      };
+      stateDir = mkOption {
+        default = "/var/spool/unit";
+        description = "Unit data directory.";
+      };
+      logDir = mkOption {
+        default = "/var/log/unit";
+        description = "Unit log directory.";
+      };
+      config = mkOption {
+        type = types.str;
+        default = ''
+          {
+            "listeners": {},
+            "applications": {}
+          }
+        '';
+        example = literalExample ''
+          {
+            "listeners": {
+              "*:8300": {
+                "application": "example-php-72"
+              }
+            },
+            "applications": {
+              "example-php-72": {
+                "type": "php 7.2",
+                "processes": 4,
+                "user": "nginx",
+                "group": "nginx",
+                "root": "/var/www",
+                "index": "index.php",
+                "options": {
+                  "file": "/etc/php.d/default.ini",
+                  "admin": {
+                    "max_execution_time": "30",
+                    "max_input_time": "30",
+                    "display_errors": "off",
+                    "display_startup_errors": "off",
+                    "open_basedir": "/dev/urandom:/proc/cpuinfo:/proc/meminfo:/etc/ssl/certs:/var/www",
+                    "disable_functions": "exec,passthru,shell_exec,system"
+                  }
+                }
+              }
+            }
+          }
+        '';
+        description = "Unit configuration in JSON format. More details here https://unit.nginx.org/configuration";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+
+    systemd.tmpfiles.rules = [
+      "d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -"
+      "d '${cfg.logDir}' 0750 ${cfg.user} ${cfg.group} - -"
+     ];
+
+    systemd.services.unit = {
+      description = "Unit App Server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      path = with pkgs; [ curl ];
+      preStart = ''
+        test -f '/run/unit/control.unit.sock' || rm -f '/run/unit/control.unit.sock'
+      '';
+      postStart = ''
+        curl -X PUT --data-binary '@${configFile}' --unix-socket '/run/unit/control.unit.sock' 'http://localhost/config'
+      '';
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID";
+        CapabilityBoundingSet = "CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID";
+        ExecStart = ''
+          ${cfg.package}/bin/unitd --control 'unix:/run/unit/control.unit.sock' --pid '/run/unit/unit.pid' \
+                                   --log '${cfg.logDir}/unit.log' --state '${cfg.stateDir}' --no-daemon \
+                                   --user ${cfg.user} --group ${cfg.group}
+        '';
+        RuntimeDirectory = "unit";
+        RuntimeDirectoryMode = "0750";
+      };
+    };
+
+    users.users = optionalAttrs (cfg.user == "unit") (singleton {
+      name = "unit";
+      group = cfg.group;
+    });
+
+    users.groups = optionalAttrs (cfg.group == "unit") (singleton {
+      name = "unit";
+    });
+  };
+}
diff --git a/nixos/modules/services/x11/colord.nix b/nixos/modules/services/x11/colord.nix
index d9e81d75072..17568df091d 100644
--- a/nixos/modules/services/x11/colord.nix
+++ b/nixos/modules/services/x11/colord.nix
@@ -18,22 +18,23 @@ in {
 
   config = mkIf cfg.enable {
 
+    environment.systemPackages = [ pkgs.colord ];
+
     services.dbus.packages = [ pkgs.colord ];
 
     services.udev.packages = [ pkgs.colord ];
 
-    environment.systemPackages = [ pkgs.colord ];
+    systemd.packages = [ pkgs.colord ];
 
-    systemd.services.colord = {
-      description = "Manage, Install and Generate Color Profiles";
-      serviceConfig = {
-        Type = "dbus";
-        BusName = "org.freedesktop.ColorManager";
-        ExecStart = "${pkgs.colord}/libexec/colord";
-        PrivateTmp = true;
-      };
+    environment.etc."tmpfiles.d/colord.conf".source = "${pkgs.colord}/lib/tmpfiles.d/colord.conf";
+
+    users.users.colord = {
+      home = "/var/lib/colord";
+      group = "colord";
     };
 
+    users.groups.colord = {};
+
   };
 
 }
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 67faddb1ddb..d0278271409 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -14,6 +14,9 @@ let
 in
 
 {
+
+  meta.maintainers = pkgs.pantheon.maintainers;
+
   options = {
 
     services.xserver.desktopManager.pantheon = {
diff --git a/nixos/modules/services/x11/window-managers/dwm.nix b/nixos/modules/services/x11/window-managers/dwm.nix
index a74bfce097d..7777913ce1e 100644
--- a/nixos/modules/services/x11/window-managers/dwm.nix
+++ b/nixos/modules/services/x11/window-managers/dwm.nix
@@ -25,7 +25,7 @@ in
       { name = "dwm";
         start =
           ''
-            ${pkgs.dwm}/bin/dwm &
+            dwm &
             waitPID=$!
           '';
       };
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index c4d5b6a9cde..e767b0eda31 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -246,7 +246,7 @@ in
         default = [ "ati" "cirrus" "vesa" "vmware" "modesetting" ];
         example = [
           "ati_unfree" "amdgpu" "amdgpu-pro"
-          "nv" "nvidia" "nvidiaLegacy340" "nvidiaLegacy304"
+          "nv" "nvidia" "nvidiaLegacy390" "nvidiaLegacy340" "nvidiaLegacy304"
         ];
         # TODO(@oxij): think how to easily add the rest, like those nvidia things
         relatedPackages = concatLists
@@ -259,6 +259,11 @@ in
           The names of the video drivers the configuration
           supports. They will be tried in order until one that
           supports your card is found.
+          Don't combine those with "incompatible" OpenGL implementations,
+          e.g. free ones (mesa-based) with proprietary ones.
+
+          For unfree "nvidia*", the supported GPU lists are on
+          https://www.nvidia.com/object/unix.html
         '';
       };
 
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index a1537ad3ced..d3cf8b29bb4 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -8,13 +8,17 @@ let
 
   efi = config.boot.loader.efi;
 
-  realGrub = if cfg.version == 1 then pkgs.grub
-    else if cfg.zfsSupport then pkgs.grub2.override { zfsSupport = true; }
+  grubPkgs = 
+    # Package set of targeted architecture
+    if cfg.forcei686 then pkgs.pkgsi686Linux else pkgs;
+
+  realGrub = if cfg.version == 1 then grubPkgs.grub
+    else if cfg.zfsSupport then grubPkgs.grub2.override { zfsSupport = true; }
     else if cfg.trustedBoot.enable
          then if cfg.trustedBoot.isHPLaptop
-              then pkgs.trustedGrub-for-HP
-              else pkgs.trustedGrub
-         else pkgs.grub2;
+              then grubPkgs.trustedGrub-for-HP
+              else grubPkgs.trustedGrub
+         else grubPkgs.grub2;
 
   grub =
     # Don't include GRUB if we're only generating a GRUB menu (e.g.,
@@ -58,14 +62,10 @@ let
         version extraConfig extraPerEntryConfig extraEntries forceInstall useOSProber
         extraEntriesBeforeNixOS extraPrepareConfig extraInitrd configurationLimit copyKernels
         default fsIdentifier efiSupport efiInstallAsRemovable gfxmodeEfi gfxmodeBios;
-      path = (makeBinPath ([
-        pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfs-progs
-        pkgs.utillinux ]
-        ++ (optional (cfg.efiSupport && (cfg.version == 2)) pkgs.efibootmgr)
-        ++ (optionals cfg.useOSProber [pkgs.busybox pkgs.os-prober])
-      )) + ":" + (makeSearchPathOutput "bin" "sbin" [
-        pkgs.mdadm pkgs.utillinux
-      ]);
+      path = with pkgs; makeBinPath (
+        [ coreutils gnused gnugrep findutils diffutils btrfs-progs utillinux mdadm ]
+        ++ optional (cfg.efiSupport && (cfg.version == 2)) efibootmgr
+        ++ optionals cfg.useOSProber [ busybox os-prober ]);
       font = if cfg.font == null then ""
         else (if lib.last (lib.splitString "." cfg.font) == "pf2"
              then cfg.font
@@ -512,6 +512,15 @@ in
         '';
       };
 
+      forcei686 = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to force the use of a ia32 boot loader on x64 systems. Required 
+          to install and run NixOS on 64bit x86 systems with 32bit (U)EFI.
+        '';
+      };
+
       trustedBoot = {
 
         enable = mkOption {
diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix
index 68a40377ee1..28ad4f121bb 100644
--- a/nixos/modules/system/boot/systemd-lib.nix
+++ b/nixos/modules/system/boot/systemd-lib.nix
@@ -9,12 +9,11 @@ in rec {
 
   shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s);
 
+  mkPathSafeName = lib.replaceChars ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""];
+
   makeUnit = name: unit:
-    let
-      pathSafeName = lib.replaceChars ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""] name;
-    in
     if unit.enable then
-      pkgs.runCommand "unit-${pathSafeName}"
+      pkgs.runCommand "unit-${mkPathSafeName name}"
         { preferLocalBuild = true;
           allowSubstitutes = false;
           inherit (unit) text;
@@ -24,7 +23,7 @@ in rec {
           echo -n "$text" > $out/${shellEscape name}
         ''
     else
-      pkgs.runCommand "unit-${pathSafeName}-disabled"
+      pkgs.runCommand "unit-${mkPathSafeName name}-disabled"
         { preferLocalBuild = true;
           allowSubstitutes = false;
         }
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index 07f8214cea2..43764bb82f1 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -209,10 +209,17 @@ in
 
     assertions = let
       ls = sep: concatMapStringsSep sep (x: x.mountPoint);
+      notAutoResizable = fs: fs.autoResize && !(hasPrefix "ext" fs.fsType || fs.fsType == "f2fs");
     in [
       { assertion = ! (fileSystems' ? "cycle");
         message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";
       }
+      { assertion = ! (any notAutoResizable fileSystems);
+        message = let
+          fs = head (filter notAutoResizable fileSystems);
+        in
+          "Mountpoint '${fs.mountPoint}': 'autoResize = true' is not supported for 'fsType = \"${fs.fsType}\"':${if fs.fsType == "auto" then " fsType has to be explicitly set and" else ""} only the ext filesystems and f2fs support it.";
+      }
     ];
 
     # Export for use in other modules
diff --git a/nixos/modules/virtualisation/anbox.nix b/nixos/modules/virtualisation/anbox.nix
new file mode 100644
index 00000000000..9cb89e7b292
--- /dev/null
+++ b/nixos/modules/virtualisation/anbox.nix
@@ -0,0 +1,144 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.virtualisation.anbox;
+  kernelPackages = config.boot.kernelPackages;
+  addrOpts = v: addr: pref: name: {
+    address = mkOption {
+      default = addr;
+      type = types.str;
+      description = ''
+        IPv${toString v} ${name} address.
+      '';
+    };
+
+    prefixLength = mkOption {
+      default = pref;
+      type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128));
+      description = ''
+        Subnet mask of the ${name} address, specified as the number of
+        bits in the prefix (<literal>${if v == 4 then "24" else "64"}</literal>).
+      '';
+    };
+  };
+
+in
+
+{
+
+  options.virtualisation.anbox = {
+
+    enable = mkEnableOption "Anbox";
+
+    image = mkOption {
+      default = pkgs.anbox.image;
+      example = literalExample "pkgs.anbox.image";
+      type = types.package;
+      description = ''
+        Base android image for Anbox.
+      '';
+    };
+
+    extraInit = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        Extra shell commands to be run inside the container image during init.
+      '';
+    };
+
+    ipv4 = {
+      container = addrOpts 4 "192.168.250.2" 24 "Container";
+      gateway = addrOpts 4 "192.168.250.1" 24 "Host";
+
+      dns = mkOption {
+        default = "1.1.1.1";
+        type = types.string;
+        description = ''
+          Container DNS server.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    assertions = singleton {
+      assertion = versionAtLeast (getVersion config.boot.kernelPackages.kernel) "4.18";
+      message = "Anbox needs user namespace support to work properly";
+    };
+
+    environment.systemPackages = with pkgs; [ anbox ];
+
+    boot.kernelModules = [ "ashmem_linux" "binder_linux" ];
+    boot.extraModulePackages = [ kernelPackages.anbox ];
+
+    services.udev.extraRules = ''
+      KERNEL=="ashmem", NAME="%k", MODE="0666"
+      KERNEL=="binder*", NAME="%k", MODE="0666"
+    '';
+
+    virtualisation.lxc.enable = true;
+    networking.bridges.anbox0.interfaces = [];
+    networking.interfaces.anbox0.ipv4.addresses = [ cfg.ipv4.gateway ];
+
+    networking.nat = {
+      enable = true;
+      internalInterfaces = [ "anbox0" ];
+    };
+
+    systemd.services.anbox-container-manager = let
+      anboxloc = "/var/lib/anbox";
+    in {
+      description = "Anbox Container Management Daemon";
+
+      environment.XDG_RUNTIME_DIR="${anboxloc}";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "systemd-udev-settle.service" ];
+      preStart = let
+        initsh = let
+          ip = cfg.ipv4.container.address;
+          gw = cfg.ipv4.gateway.address;
+          dns = cfg.ipv4.dns;
+        in
+        pkgs.writeText "nixos-init" (''
+          #!/system/bin/sh
+          setprop nixos.version ${config.system.nixos.version}
+
+          # we don't have radio
+          setprop ro.radio.noril yes
+          stop ril-daemon
+
+          # speed up boot
+          setprop debug.sf.nobootanimation 1
+        '' + cfg.extraInit);
+        initshloc = "${anboxloc}/rootfs-overlay/system/etc/init.goldfish.sh";
+      in ''
+        mkdir -p ${anboxloc}
+        mkdir -p $(dirname ${initshloc})
+        [ -f ${initshloc} ] && rm ${initshloc}
+        cp ${initsh} ${initshloc}
+        chown 100000:100000 ${initshloc}
+        chmod +x ${initshloc}
+      '';
+
+      serviceConfig = {
+        ExecStart = ''
+          ${pkgs.anbox}/bin/anbox container-manager \
+            --data-path=${anboxloc} \
+            --android-image=${cfg.image} \
+            --container-network-address=${cfg.ipv4.container.address} \
+            --container-network-gateway=${cfg.ipv4.gateway.address} \
+            --container-network-dns-servers=${cfg.ipv4.dns} \
+            --use-rootfs-overlay \
+            --privileged
+        '';
+      };
+    };
+  };
+
+}
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index 7c9909ae278..d10c4feecb4 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -36,8 +36,9 @@ let
         #! ${pkgs.runtimeShell} -e
 
         # Initialise the container side of the veth pair.
-        if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ] || [ -n "$HOST_BRIDGE" ]; then
-
+        if [ -n "$HOST_ADDRESS" ]   || [ -n "$HOST_ADDRESS6" ]  ||
+           [ -n "$LOCAL_ADDRESS" ]  || [ -n "$LOCAL_ADDRESS6" ] ||
+           [ -n "$HOST_BRIDGE" ]; then
           ip link set host0 name eth0
           ip link set dev eth0 up
 
@@ -88,7 +89,8 @@ let
         extraFlags+=" --private-network"
       fi
 
-      if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ]; then
+      if [ -n "$HOST_ADDRESS" ]  || [ -n "$LOCAL_ADDRESS" ] ||
+         [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then
         extraFlags+=" --network-veth"
       fi
 
@@ -159,7 +161,8 @@ let
       # Clean up existing machined registration and interfaces.
       machinectl terminate "$INSTANCE" 2> /dev/null || true
 
-      if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ]; then
+      if [ -n "$HOST_ADDRESS" ]  || [ -n "$LOCAL_ADDRESS" ] ||
+         [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then
         ip link del dev "ve-$INSTANCE" 2> /dev/null || true
         ip link del dev "vb-$INSTANCE" 2> /dev/null || true
       fi
@@ -208,7 +211,8 @@ let
           '';
     in
       ''
-        if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ]; then
+        if [ -n "$HOST_ADDRESS" ]  || [ -n "$LOCAL_ADDRESS" ] ||
+           [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then
           if [ -z "$HOST_BRIDGE" ]; then
             ifaceHost=ve-$INSTANCE
             ip link set dev $ifaceHost up
diff --git a/nixos/modules/virtualisation/docker-containers.nix b/nixos/modules/virtualisation/docker-containers.nix
new file mode 100644
index 00000000000..c4e47bfa477
--- /dev/null
+++ b/nixos/modules/virtualisation/docker-containers.nix
@@ -0,0 +1,233 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.docker-containers;
+
+  dockerContainer =
+    { name, config, ... }: {
+
+      options = {
+
+        image = mkOption {
+          type = types.str;
+          description = "Docker image to run.";
+          example = "library/hello-world";
+        };
+
+        cmd = mkOption {
+          type =  with types; listOf str;
+          default = [];
+          description = "Commandline arguments to pass to the image's entrypoint.";
+          example = literalExample ''
+            ["--port=9000"]
+          '';
+        };
+
+        entrypoint = mkOption {
+          type = with types; nullOr str;
+          description = "Overwrite the default entrypoint of the image.";
+          default = null;
+          example = "/bin/my-app";
+        };
+
+        environment = mkOption {
+          type = with types; attrsOf str;
+          default = {};
+          description = "Environment variables to set for this container.";
+          example = literalExample ''
+            {
+              DATABASE_HOST = "db.example.com";
+              DATABASE_PORT = "3306";
+            }
+        '';
+        };
+
+        log-driver = mkOption {
+          type = types.str;
+          default = "none";
+          description = ''
+            Logging driver for the container.  The default of
+            <literal>"none"</literal> means that the container's logs will be
+            handled as part of the systemd unit.  Setting this to
+            <literal>"journald"</literal> will result in duplicate logging, but
+            the container's logs will be visible to the <command>docker
+            logs</command> command.
+
+            For more details and a full list of logging drivers, refer to the
+            <link xlink:href="https://docs.docker.com/engine/reference/run/#logging-drivers---log-driver">
+            Docker engine documentation</link>
+          '';
+        };
+
+        ports = mkOption {
+          type = with types; listOf str;
+          default = [];
+          description = ''
+            Network ports to publish from the container to the outer host.
+            </para>
+            <para>
+            Valid formats:
+            </para>
+            <itemizedlist>
+              <listitem>
+                <para>
+                  <literal>&lt;ip&gt;:&lt;hostPort&gt;:&lt;containerPort&gt;</literal>
+                </para>
+              </listitem>
+              <listitem>
+                <para>
+                  <literal>&lt;ip&gt;::&lt;containerPort&gt;</literal>
+                </para>
+              </listitem>
+              <listitem>
+                <para>
+                  <literal>&lt;hostPort&gt;:&lt;containerPort&gt;</literal>
+                </para>
+              </listitem>
+              <listitem>
+                <para>
+                  <literal>&lt;containerPort&gt;</literal>
+                </para>
+              </listitem>
+            </itemizedlist>
+            <para>
+            Both <literal>hostPort</literal> and
+            <literal>containerPort</literal> can be specified as a range of
+            ports.  When specifying ranges for both, the number of container
+            ports in the range must match the number of host ports in the
+            range.  Example: <literal>1234-1236:1234-1236/tcp</literal>
+            </para>
+            <para>
+            When specifying a range for <literal>hostPort</literal> only, the
+            <literal>containerPort</literal> must <emphasis>not</emphasis> be a
+            range.  In this case, the container port is published somewhere
+            within the specified <literal>hostPort</literal> range.  Example:
+            <literal>1234-1236:1234/tcp</literal>
+            </para>
+            <para>
+            Refer to the
+            <link xlink:href="https://docs.docker.com/engine/reference/run/#expose-incoming-ports">
+            Docker engine documentation</link> for full details.
+          '';
+          example = literalExample ''
+            [
+              "8080:9000"
+            ]
+          '';
+        };
+
+        user = mkOption {
+          type = with types; nullOr str;
+          default = null;
+          description = ''
+            Override the username or UID (and optionally groupname or GID) used
+            in the container.
+          '';
+          example = "nobody:nogroup";
+        };
+
+        volumes = mkOption {
+          type = with types; listOf str;
+          default = [];
+          description = ''
+            List of volumes to attach to this container.
+
+            Note that this is a list of <literal>"src:dst"</literal> strings to
+            allow for <literal>src</literal> to refer to
+            <literal>/nix/store</literal> paths, which would difficult with an
+            attribute set.  There are also a variety of mount options available
+            as a third field; please refer to the
+            <link xlink:href="https://docs.docker.com/engine/reference/run/#volume-shared-filesystems">
+            docker engine documentation</link> for details.
+          '';
+          example = literalExample ''
+            [
+              "volume_name:/path/inside/container"
+              "/path/on/host:/path/inside/container"
+            ]
+          '';
+        };
+
+        workdir = mkOption {
+          type = with types; nullOr str;
+          default = null;
+          description = "Override the default working directory for the container.";
+          example = "/var/lib/hello_world";
+        };
+
+        extraDockerOptions = mkOption {
+          type = with types; listOf str;
+          default = [];
+          description = "Extra options for <command>docker run</command>.";
+          example = literalExample ''
+            ["--network=host"]
+          '';
+        };
+      };
+    };
+
+  mkService = name: container: {
+    wantedBy = [ "multi-user.target" ];
+    after = [ "docker.service" "docker.socket" ];
+    requires = [ "docker.service" "docker.socket" ];
+    serviceConfig = {
+      ExecStart = concatStringsSep " \\\n  " ([
+        "${pkgs.docker}/bin/docker run"
+        "--rm"
+        "--name=%n"
+        "--log-driver=${container.log-driver}"
+      ] ++ optional (! isNull container.entrypoint)
+        "--entrypoint=${escapeShellArg container.entrypoint}"
+        ++ (mapAttrsToList (k: v: "-e ${escapeShellArg k}=${escapeShellArg v}") container.environment)
+        ++ map (p: "-p ${escapeShellArg p}") container.ports
+        ++ optional (! isNull container.user) "-u ${escapeShellArg container.user}"
+        ++ map (v: "-v ${escapeShellArg v}") container.volumes
+        ++ optional (! isNull container.workdir) "-w ${escapeShellArg container.workdir}"
+        ++ map escapeShellArg container.extraDockerOptions
+        ++ [container.image]
+        ++ map escapeShellArg container.cmd
+      );
+      ExecStartPre = "-${pkgs.docker}/bin/docker rm -f %n";
+      ExecStop = "${pkgs.docker}/bin/docker stop %n";
+      ExecStopPost = "-${pkgs.docker}/bin/docker rm -f %n";
+
+      ### There is no generalized way of supporting `reload` for docker
+      ### containers. Some containers may respond well to SIGHUP sent to their
+      ### init process, but it is not guaranteed; some apps have other reload
+      ### mechanisms, some don't have a reload signal at all, and some docker
+      ### images just have broken signal handling.  The best compromise in this
+      ### case is probably to leave ExecReload undefined, so `systemctl reload`
+      ### will at least result in an error instead of potentially undefined
+      ### behaviour.
+      ###
+      ### Advanced users can still override this part of the unit to implement
+      ### a custom reload handler, since the result of all this is a normal
+      ### systemd service from the perspective of the NixOS module system.
+      ###
+      # ExecReload = ...;
+      ###
+
+      TimeoutStartSec = 0;
+      TimeoutStopSec = 120;
+      Restart = "always";
+    };
+  };
+
+in {
+
+  options.docker-containers = mkOption {
+    default = {};
+    type = types.attrsOf (types.submodule dockerContainer);
+    description = "Docker containers to run as systemd services.";
+  };
+
+  config = mkIf (cfg != {}) {
+
+    systemd.services = mapAttrs' (n: v: nameValuePair "docker-${n}" (mkService n v)) cfg;
+
+    virtualisation.docker.enable = true;
+
+  };
+
+}
diff --git a/nixos/modules/virtualisation/openstack-config.nix b/nixos/modules/virtualisation/openstack-config.nix
index d5e862da0ea..c2da5d0d230 100644
--- a/nixos/modules/virtualisation/openstack-config.nix
+++ b/nixos/modules/virtualisation/openstack-config.nix
@@ -20,6 +20,7 @@ in
   config = {
     fileSystems."/" = {
       device = "/dev/disk/by-label/nixos";
+      fsType = "ext4";
       autoResize = true;
     };
 
diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix
index 037c0d2f0d8..903411799d3 100644
--- a/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixos/modules/virtualisation/virtualbox-image.nix
@@ -94,6 +94,7 @@ in {
     fileSystems."/" = {
       device = "/dev/disk/by-label/nixos";
       autoResize = true;
+      fsType = "ext4";
     };
 
     boot.growPartition = true;
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index 6c313f8dd3e..b9a9515f94e 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -64,6 +64,7 @@ in rec {
         #(all nixos.tests.containers)
         (all nixos.tests.containers-imperative)
         (all nixos.tests.containers-ipv4)
+        (all nixos.tests.containers-ipv6)
         nixos.tests.chromium.x86_64-linux or []
         (all nixos.tests.firefox)
         (all nixos.tests.firewall)
diff --git a/nixos/release-small.nix b/nixos/release-small.nix
index 4bfb9a423f7..b5b09dc38d0 100644
--- a/nixos/release-small.nix
+++ b/nixos/release-small.nix
@@ -33,6 +33,7 @@ in rec {
       inherit (nixos'.tests)
         containers-imperative
         containers-ipv4
+        containers-ipv6
         firewall
         ipv6
         login
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 69510c1420f..b366f019f6e 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -59,6 +59,7 @@ in
   dhparams = handleTest ./dhparams.nix {};
   dnscrypt-proxy = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy.nix {};
   docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
+  docker-containers = handleTestOn ["x86_64-linux"] ./docker-containers.nix {};
   docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
   docker-preloader = handleTestOn ["x86_64-linux"] ./docker-preloader.nix {};
   docker-registry = handleTest ./docker-registry.nix {};
@@ -113,10 +114,11 @@ in
   ipv6 = handleTest ./ipv6.nix {};
   jackett = handleTest ./jackett.nix {};
   jenkins = handleTest ./jenkins.nix {};
-  #kafka = handleTest ./kafka.nix {}; # broken since openjdk: 8u181 -> 8u192
+  kafka = handleTest ./kafka.nix {};
   kerberos = handleTest ./kerberos/default.nix {};
   kernel-latest = handleTest ./kernel-latest.nix {};
   kernel-lts = handleTest ./kernel-lts.nix {};
+  kernel-testing = handleTest ./kernel-testing.nix {};
   keymap = handleTest ./keymap.nix {};
   knot = handleTest ./knot.nix {};
   kubernetes.dns = handleTestOn ["x86_64-linux"] ./kubernetes/dns.nix {};
@@ -130,6 +132,7 @@ in
   #lightdm = handleTest ./lightdm.nix {};
   login = handleTest ./login.nix {};
   #logstash = handleTest ./logstash.nix {};
+  mailcatcher = handleTest ./mailcatcher.nix {};
   mathics = handleTest ./mathics.nix {};
   matrix-synapse = handleTest ./matrix-synapse.nix {};
   memcached = handleTest ./memcached.nix {};
@@ -219,6 +222,8 @@ in
   switchTest = handleTest ./switch-test.nix {};
   syncthing-relay = handleTest ./syncthing-relay.nix {};
   systemd = handleTest ./systemd.nix {};
+  systemd-confinement = handleTest ./systemd-confinement.nix {};
+  pdns-recursor = handleTest ./pdns-recursor.nix {};
   taskserver = handleTest ./taskserver.nix {};
   telegraf = handleTest ./telegraf.nix {};
   tomcat = handleTest ./tomcat.nix {};
@@ -228,6 +233,7 @@ in
   upnp = handleTest ./upnp.nix {};
   vault = handleTest ./vault.nix {};
   virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
+  wireguard = handleTest ./wireguard {};
   wordpress = handleTest ./wordpress.nix {};
   xautolock = handleTest ./xautolock.nix {};
   xdg-desktop-portal = handleTest ./xdg-desktop-portal.nix {};
diff --git a/nixos/tests/buildbot.nix b/nixos/tests/buildbot.nix
index 210ad8e91df..f5c8c4863b6 100644
--- a/nixos/tests/buildbot.nix
+++ b/nixos/tests/buildbot.nix
@@ -5,116 +5,109 @@
 
 with import ../lib/testing.nix { inherit system pkgs; };
 
-let
-  # Test ensures buildbot master comes up correctly and workers can connect
-  mkBuildbotTest = python: makeTest {
-    name = "buildbot";
-
-    nodes = {
-      bbmaster = { pkgs, ... }: {
-        services.buildbot-master = {
-          enable = true;
-          package = python.pkgs.buildbot-full;
-
-          # NOTE: use fake repo due to no internet in hydra ci
-          factorySteps = [
-            "steps.Git(repourl='git://gitrepo/fakerepo.git', mode='incremental')"
-            "steps.ShellCommand(command=['bash', 'fakerepo.sh'])"
-          ];
-          changeSource = [
-            "changes.GitPoller('git://gitrepo/fakerepo.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)"
-          ];
-        };
-        networking.firewall.allowedTCPPorts = [ 8010 8011 9989 ];
-        environment.systemPackages = with pkgs; [ git python.pkgs.buildbot-full ];
-      };
-
-      bbworker = { pkgs, ... }: {
-        services.buildbot-worker = {
-          enable = true;
-          masterUrl = "bbmaster:9989";
-        };
-        environment.systemPackages = with pkgs; [ git python.pkgs.buildbot-worker ];
+# Test ensures buildbot master comes up correctly and workers can connect
+makeTest {
+  name = "buildbot";
+
+  nodes = {
+    bbmaster = { pkgs, ... }: {
+      services.buildbot-master = {
+        enable = true;
+
+        # NOTE: use fake repo due to no internet in hydra ci
+        factorySteps = [
+          "steps.Git(repourl='git://gitrepo/fakerepo.git', mode='incremental')"
+          "steps.ShellCommand(command=['bash', 'fakerepo.sh'])"
+        ];
+        changeSource = [
+          "changes.GitPoller('git://gitrepo/fakerepo.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)"
+        ];
       };
+      networking.firewall.allowedTCPPorts = [ 8010 8011 9989 ];
+      environment.systemPackages = with pkgs; [ git python3Packages.buildbot-full ];
+    };
 
-      gitrepo = { pkgs, ... }: {
-        services.openssh.enable = true;
-        networking.firewall.allowedTCPPorts = [ 22 9418 ];
-        environment.systemPackages = with pkgs; [ git ];
+    bbworker = { pkgs, ... }: {
+      services.buildbot-worker = {
+        enable = true;
+        masterUrl = "bbmaster:9989";
       };
+      environment.systemPackages = with pkgs; [ git python3Packages.buildbot-worker ];
     };
 
-    testScript = ''
-      #Start up and populate fake repo
-      $gitrepo->waitForUnit("multi-user.target");
-      print($gitrepo->execute(" \
-        git config --global user.name 'Nobody Fakeuser' && \
-        git config --global user.email 'nobody\@fakerepo.com' && \
-        rm -rvf /srv/repos/fakerepo.git /tmp/fakerepo && \
-        mkdir -pv /srv/repos/fakerepo ~/.ssh && \
-        ssh-keyscan -H gitrepo > ~/.ssh/known_hosts && \
-        cat ~/.ssh/known_hosts && \
-        cd /srv/repos/fakerepo && \
-        git init && \
-        echo -e '#!/bin/sh\necho fakerepo' > fakerepo.sh && \
-        cat fakerepo.sh && \
-        touch .git/git-daemon-export-ok && \
-        git add fakerepo.sh .git/git-daemon-export-ok && \
-        git commit -m fakerepo && \
-        git daemon --verbose --export-all --base-path=/srv/repos --reuseaddr & \
-      "));
-
-      # Test gitrepo
-      $bbmaster->waitForUnit("network-online.target");
-      #$bbmaster->execute("nc -z gitrepo 9418");
-      print($bbmaster->execute(" \
-        rm -rfv /tmp/fakerepo && \
-        git clone git://gitrepo/fakerepo /tmp/fakerepo && \
-        pwd && \
-        ls -la && \
-        ls -la /tmp/fakerepo \
-      "));
-
-      # Test start master and connect worker
-      $bbmaster->waitForUnit("buildbot-master.service");
-      $bbmaster->waitUntilSucceeds("curl -s --head http://bbmaster:8010") =~ /200 OK/;
-      $bbworker->waitForUnit("network-online.target");
-      $bbworker->execute("nc -z bbmaster 8010");
-      $bbworker->execute("nc -z bbmaster 9989");
-      $bbworker->waitForUnit("buildbot-worker.service");
-      print($bbworker->execute("ls -la /home/bbworker/worker"));
-
-
-      # Test stop buildbot master and worker
-      print($bbmaster->execute(" \
-        systemctl -l --no-pager status buildbot-master && \
-        systemctl stop buildbot-master \
-      "));
-      $bbworker->fail("nc -z bbmaster 8010");
-      $bbworker->fail("nc -z bbmaster 9989");
-      print($bbworker->execute(" \
-        systemctl -l --no-pager status buildbot-worker && \
-        systemctl stop buildbot-worker && \
-        ls -la /home/bbworker/worker \
-      "));
-
-
-      # Test buildbot daemon mode
-      $bbmaster->execute("buildbot create-master /tmp");
-      $bbmaster->execute("mv -fv /tmp/master.cfg.sample /tmp/master.cfg");
-      $bbmaster->execute("sed -i 's/8010/8011/' /tmp/master.cfg");
-      $bbmaster->execute("buildbot start /tmp");
-      $bbworker->execute("nc -z bbmaster 8011");
-      $bbworker->waitUntilSucceeds("curl -s --head http://bbmaster:8011") =~ /200 OK/;
-      $bbmaster->execute("buildbot stop /tmp");
-      $bbworker->fail("nc -z bbmaster 8011");
-
-    '';
-
-    meta.maintainers = with pkgs.stdenv.lib.maintainers; [ nand0p ];
-
+    gitrepo = { pkgs, ... }: {
+      services.openssh.enable = true;
+      networking.firewall.allowedTCPPorts = [ 22 9418 ];
+      environment.systemPackages = with pkgs; [ git ];
+    };
   };
-in {
-  python2 = mkBuildbotTest pkgs.python2;
-  python3 = mkBuildbotTest pkgs.python3;
+
+  testScript = ''
+    #Start up and populate fake repo
+    $gitrepo->waitForUnit("multi-user.target");
+    print($gitrepo->execute(" \
+      git config --global user.name 'Nobody Fakeuser' && \
+      git config --global user.email 'nobody\@fakerepo.com' && \
+      rm -rvf /srv/repos/fakerepo.git /tmp/fakerepo && \
+      mkdir -pv /srv/repos/fakerepo ~/.ssh && \
+      ssh-keyscan -H gitrepo > ~/.ssh/known_hosts && \
+      cat ~/.ssh/known_hosts && \
+      cd /srv/repos/fakerepo && \
+      git init && \
+      echo -e '#!/bin/sh\necho fakerepo' > fakerepo.sh && \
+      cat fakerepo.sh && \
+      touch .git/git-daemon-export-ok && \
+      git add fakerepo.sh .git/git-daemon-export-ok && \
+      git commit -m fakerepo && \
+      git daemon --verbose --export-all --base-path=/srv/repos --reuseaddr & \
+    "));
+
+    # Test gitrepo
+    $bbmaster->waitForUnit("network-online.target");
+    #$bbmaster->execute("nc -z gitrepo 9418");
+    print($bbmaster->execute(" \
+      rm -rfv /tmp/fakerepo && \
+      git clone git://gitrepo/fakerepo /tmp/fakerepo && \
+      pwd && \
+      ls -la && \
+      ls -la /tmp/fakerepo \
+    "));
+
+    # Test start master and connect worker
+    $bbmaster->waitForUnit("buildbot-master.service");
+    $bbmaster->waitUntilSucceeds("curl -s --head http://bbmaster:8010") =~ /200 OK/;
+    $bbworker->waitForUnit("network-online.target");
+    $bbworker->execute("nc -z bbmaster 8010");
+    $bbworker->execute("nc -z bbmaster 9989");
+    $bbworker->waitForUnit("buildbot-worker.service");
+    print($bbworker->execute("ls -la /home/bbworker/worker"));
+
+
+    # Test stop buildbot master and worker
+    print($bbmaster->execute(" \
+      systemctl -l --no-pager status buildbot-master && \
+      systemctl stop buildbot-master \
+    "));
+    $bbworker->fail("nc -z bbmaster 8010");
+    $bbworker->fail("nc -z bbmaster 9989");
+    print($bbworker->execute(" \
+      systemctl -l --no-pager status buildbot-worker && \
+      systemctl stop buildbot-worker && \
+      ls -la /home/bbworker/worker \
+    "));
+
+
+    # Test buildbot daemon mode
+    $bbmaster->execute("buildbot create-master /tmp");
+    $bbmaster->execute("mv -fv /tmp/master.cfg.sample /tmp/master.cfg");
+    $bbmaster->execute("sed -i 's/8010/8011/' /tmp/master.cfg");
+    $bbmaster->execute("buildbot start /tmp");
+    $bbworker->execute("nc -z bbmaster 8011");
+    $bbworker->waitUntilSucceeds("curl -s --head http://bbmaster:8011") =~ /200 OK/;
+    $bbmaster->execute("buildbot stop /tmp");
+    $bbworker->fail("nc -z bbmaster 8011");
+
+  '';
+
+  meta.maintainers = with pkgs.stdenv.lib.maintainers; [ nand0p ];
 }
diff --git a/nixos/tests/common/letsencrypt/default.nix b/nixos/tests/common/letsencrypt/default.nix
index 73aac51a012..8fe59bf4e70 100644
--- a/nixos/tests/common/letsencrypt/default.nix
+++ b/nixos/tests/common/letsencrypt/default.nix
@@ -381,7 +381,7 @@ in {
       enableACME = false;
       sslCertificate = siteCertFile;
       sslCertificateKey = siteKeyFile;
-      locations.${tosPath}.extraConfig = "alias ${tosFile};";
+      locations."= ${tosPath}".alias = tosFile;
     };
 
     systemd.services = {
diff --git a/nixos/tests/common/webroot/news-rss.xml b/nixos/tests/common/webroot/news-rss.xml
index 28e6fa7da1f..b8099bf0364 100644
--- a/nixos/tests/common/webroot/news-rss.xml
+++ b/nixos/tests/common/webroot/news-rss.xml
@@ -1,10 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" version="2.0"><channel><title>NixOS News</title><link>https://nixos.org</link><description>News for NixOS, the purely functional Linux distribution.</description><image><title>NixOS</title><url>https://nixos.org/logo/nixos-logo-only-hires.png</url><link>https://nixos.org/</link></image><item><title>
-      NixOS 18.09 released
-    </title><link>https://nixos.org/news.html</link><description>
-      <a href="https://github.com/NixOS/nixos-artwork/blob/master/releases/18.09-jellyfish/jellyfish.png">
-        <img class="inline" src="logo/nixos-logo-18.09-jellyfish-lores.png" alt="18.09 Jellyfish logo" with="100" height="87"/>
-      </a>
+<rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" version="2.0">
+ <channel>
+  <title>NixOS News</title><link>https://nixos.org</link>
+  <description>News for NixOS, the purely functional Linux distribution.</description>
+  <image>
+   <title>NixOS</title>
+   <url>https://nixos.org/logo/nixos-logo-only-hires.png</url><link>https://nixos.org/</link>
+  </image>
+  <item>
+   <title>NixOS 18.09 released</title><link>https://nixos.org/news.html</link>
+   <description>
+    <a href="https://github.com/NixOS/nixos-artwork/blob/master/releases/18.09-jellyfish/jellyfish.png">
+     <img class="inline" src="logo/nixos-logo-18.09-jellyfish-lores.png" alt="18.09 Jellyfish logo" with="100" height="87"/>
+    </a>
       NixOS 18.09 “Jellyfish” has been released, the tenth stable release branch.
       See the <a href="/nixos/manual/release-notes.html#sec-release-18.09">release notes</a>
       for details. You can get NixOS 18.09 ISOs and VirtualBox appliances
@@ -12,4 +20,8 @@
       For information on how to upgrade from older release branches
       to 18.09, check out the
       <a href="/nixos/manual/index.html#sec-upgrading">manual section on upgrading</a>.
-    </description><pubDate>Sat Oct 06 2018 00:00:00 GMT</pubDate></item></channel></rss>
+    </description>
+   <pubDate>Sat Oct 06 2018 00:00:00 GMT</pubDate>
+  </item>
+ </channel>
+</rss>
diff --git a/nixos/tests/docker-containers.nix b/nixos/tests/docker-containers.nix
new file mode 100644
index 00000000000..97255273520
--- /dev/null
+++ b/nixos/tests/docker-containers.nix
@@ -0,0 +1,29 @@
+# Test Docker containers as systemd units
+
+import ./make-test.nix ({ pkgs, lib, ... }: {
+  name = "docker-containers";
+  meta = {
+    maintainers = with lib.maintainers; [ benley ];
+  };
+
+  nodes = {
+    docker = { pkgs, ... }:
+      {
+        virtualisation.docker.enable = true;
+
+        virtualisation.dockerPreloader.images = [ pkgs.dockerTools.examples.nginx ];
+
+        docker-containers.nginx = {
+          image = "nginx-container";
+          ports = ["8181:80"];
+        };
+      };
+  };
+
+  testScript = ''
+    startAll;
+    $docker->waitForUnit("docker-nginx.service");
+    $docker->waitForOpenPort(8181);
+    $docker->waitUntilSucceeds("curl http://localhost:8181|grep Hello");
+  '';
+})
diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix
index 399e4d4e428..502b537ed68 100644
--- a/nixos/tests/docker-tools.nix
+++ b/nixos/tests/docker-tools.nix
@@ -34,8 +34,8 @@ import ./make-test.nix ({ pkgs, ... }: {
 
       # To test the pullImage tool
       $docker->succeed("docker load --input='${pkgs.dockerTools.examples.nixFromDockerHub}'");
-      $docker->succeed("docker run --rm nixos/nix:2.2.1 nix-store --version");
-      $docker->succeed("docker rmi nixos/nix:2.2.1");
+      $docker->succeed("docker run --rm nix:2.2.1 nix-store --version");
+      $docker->succeed("docker rmi nix:2.2.1");
 
       # To test runAsRoot and entry point
       $docker->succeed("docker load --input='${pkgs.dockerTools.examples.nginx}'");
diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix
index 8def0a6f9b9..6b53914fd85 100644
--- a/nixos/tests/home-assistant.nix
+++ b/nixos/tests/home-assistant.nix
@@ -33,11 +33,13 @@ in {
               longitude = "0.0";
               elevation = 0;
               auth_providers = [
-                { type = "legacy_api_password"; }
+                {
+                  type = "legacy_api_password";
+                  api_password = apiPassword;
+                }
               ];
             };
             frontend = { };
-            http.api_password = apiPassword;
             mqtt = { # Use hbmqtt as broker
               password = mqttPassword;
             };
diff --git a/nixos/tests/kafka.nix b/nixos/tests/kafka.nix
index 72f91f6428a..f526d18befe 100644
--- a/nixos/tests/kafka.nix
+++ b/nixos/tests/kafka.nix
@@ -72,4 +72,5 @@ in with pkgs; {
   kafka_1_1  = makeKafkaTest "kafka_1_1"  apacheKafka_1_1;
   kafka_2_0  = makeKafkaTest "kafka_2_0"  apacheKafka_2_0;
   kafka_2_1  = makeKafkaTest "kafka_2_1"  apacheKafka_2_1;
+  kafka_2_2  = makeKafkaTest "kafka_2_2"  apacheKafka_2_2;
 }
diff --git a/nixos/tests/kernel-testing.nix b/nixos/tests/kernel-testing.nix
new file mode 100644
index 00000000000..276d2de12bb
--- /dev/null
+++ b/nixos/tests/kernel-testing.nix
@@ -0,0 +1,17 @@
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "kernel-testing";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ nequissimus ];
+  };
+
+  machine = { pkgs, ... }:
+    {
+      boot.kernelPackages = pkgs.linuxPackages_testing;
+    };
+
+  testScript =
+    ''
+      $machine->succeed("uname -s | grep 'Linux'");
+      $machine->succeed("uname -a | grep '${pkgs.linuxPackages_testing.kernel.modDirVersion}'");
+    '';
+})
diff --git a/nixos/tests/ldap.nix b/nixos/tests/ldap.nix
index b3fd42e7588..fe859876ed2 100644
--- a/nixos/tests/ldap.nix
+++ b/nixos/tests/ldap.nix
@@ -28,20 +28,19 @@ let
       users.ldap.daemon = {
         enable = useDaemon;
         rootpwmoddn = "cn=admin,${dbSuffix}";
-        rootpwmodpw = "/etc/nslcd.rootpwmodpw";
+        rootpwmodpwFile = "/etc/nslcd.rootpwmodpw";
       };
-      # NOTE: password stored in clear in Nix's store, but this is a test.
-      environment.etc."nslcd.rootpwmodpw".source = pkgs.writeText "rootpwmodpw" dbAdminPwd;
       users.ldap.loginPam = true;
       users.ldap.nsswitch = true;
       users.ldap.server = "ldap://server";
       users.ldap.base = "ou=posix,${dbSuffix}";
       users.ldap.bind = {
         distinguishedName = "cn=admin,${dbSuffix}";
-        password = "/etc/ldap/bind.password";
+        passwordFile = "/etc/ldap/bind.password";
       };
-      # NOTE: password stored in clear in Nix's store, but this is a test.
+      # NOTE: passwords stored in clear in Nix's store, but this is a test.
       environment.etc."ldap/bind.password".source = pkgs.writeText "password" dbAdminPwd;
+      environment.etc."nslcd.rootpwmodpw".source = pkgs.writeText "rootpwmodpw" dbAdminPwd;
     };
 in
 
diff --git a/nixos/tests/mailcatcher.nix b/nixos/tests/mailcatcher.nix
new file mode 100644
index 00000000000..d45b5d4edfc
--- /dev/null
+++ b/nixos/tests/mailcatcher.nix
@@ -0,0 +1,26 @@
+import ./make-test.nix ({ lib, ... }:
+
+{
+  name = "mailcatcher";
+  meta.maintainers = [ lib.maintainers.aanderse ];
+
+  machine =
+    { pkgs, ... }:
+    {
+      services.mailcatcher.enable = true;
+
+      networking.defaultMailServer.directDelivery = true;
+      networking.defaultMailServer.hostName = "localhost:1025";
+
+      environment.systemPackages = [ pkgs.mailutils ];
+    };
+
+  testScript = ''
+    startAll;
+
+    $machine->waitForUnit('mailcatcher.service');
+    $machine->waitForOpenPort('1025');
+    $machine->succeed('echo "this is the body of the email" | mail -s "subject" root@example.org');
+    $machine->succeed('curl http://localhost:1080/messages/1.source') =~ /this is the body of the email/ or die;
+  '';
+})
diff --git a/nixos/tests/minio.nix b/nixos/tests/minio.nix
index 40a59954665..f1218b53771 100644
--- a/nixos/tests/minio.nix
+++ b/nixos/tests/minio.nix
@@ -1,4 +1,24 @@
-import ./make-test.nix ({ pkgs, ...} : {
+import ./make-test.nix ({ pkgs, ...} :
+let
+    accessKey = "BKIKJAA5BMMU2RHO6IBB";
+    secretKey = "V7f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12";
+    minioPythonScript = pkgs.writeScript "minio-test.py" ''
+      #! ${pkgs.python3.withPackages(ps: [ ps.minio ])}/bin/python
+      import io
+      import os
+      from minio import Minio
+      minioClient = Minio('localhost:9000',
+                    access_key='${accessKey}',
+                    secret_key='${secretKey}',
+                    secure=False)
+      sio = io.BytesIO()
+      sio.write(b'Test from Python')
+      sio.seek(0, os.SEEK_END)
+      sio_len = sio.tell()
+      sio.seek(0)
+      minioClient.put_object('test-bucket', 'test.txt', sio, sio_len, content_type='text/plain')
+    '';
+  in {
   name = "minio";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ bachp ];
@@ -8,8 +28,7 @@ import ./make-test.nix ({ pkgs, ...} : {
     machine = { pkgs, ... }: {
       services.minio = {
         enable = true;
-        accessKey = "BKIKJAA5BMMU2RHO6IBB";
-        secretKey = "V7f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12";
+        inherit accessKey secretKey;
       };
       environment.systemPackages = [ pkgs.minio-client ];
 
@@ -25,9 +44,11 @@ import ./make-test.nix ({ pkgs, ...} : {
       $machine->waitForOpenPort(9000);
 
       # Create a test bucket on the server
-      $machine->succeed("mc config host add minio http://localhost:9000 BKIKJAA5BMMU2RHO6IBB V7f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12 S3v4");
+      $machine->succeed("mc config host add minio http://localhost:9000 ${accessKey} ${secretKey} S3v4");
       $machine->succeed("mc mb minio/test-bucket");
+      $machine->succeed("${minioPythonScript}");
       $machine->succeed("mc ls minio") =~ /test-bucket/ or die;
+      $machine->succeed("mc cat minio/test-bucket/test.txt") =~ /Test from Python/ or die;
       $machine->shutdown;
 
     '';
diff --git a/nixos/tests/mysql.nix b/nixos/tests/mysql.nix
index 1a611779366..fedc7f0ab1f 100644
--- a/nixos/tests/mysql.nix
+++ b/nixos/tests/mysql.nix
@@ -5,7 +5,7 @@ import ./make-test.nix ({ pkgs, ...} : {
   };
 
   nodes = {
-    master =
+    mysql =
       { pkgs, ... }:
 
       {
@@ -13,12 +13,34 @@ import ./make-test.nix ({ pkgs, ...} : {
         services.mysql.initialDatabases = [ { name = "testdb"; schema = ./testdb.sql; } ];
         services.mysql.package = pkgs.mysql;
       };
+
+    mariadb =
+      { pkgs, ... }:
+
+      {
+        users.users.testuser = { };
+        services.mysql.enable = true;
+        services.mysql.ensureDatabases = [ "testdb" ];
+        services.mysql.ensureUsers = [{
+          name = "testuser";
+          ensurePermissions = {
+            "testdb.*" = "ALL PRIVILEGES";
+          };
+        }];
+        services.mysql.package = pkgs.mariadb;
+      };
+
   };
 
   testScript = ''
     startAll;
 
-    $master->waitForUnit("mysql");
-    $master->succeed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
+    $mysql->waitForUnit("mysql");
+    $mysql->succeed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
+
+    $mariadb->waitForUnit("mysql");
+    $mariadb->succeed("echo 'use testdb; create table tests (test_id INT, PRIMARY KEY (test_id));' | sudo -u testuser mysql -u testuser");
+    $mariadb->succeed("echo 'use testdb; insert into tests values (42);' | sudo -u testuser mysql -u testuser");
+    $mariadb->succeed("echo 'use testdb; select test_id from tests' | sudo -u testuser mysql -u testuser -N | grep 42");
   '';
 })
diff --git a/nixos/tests/openldap.nix b/nixos/tests/openldap.nix
index 1eaf87a8eaa..3ef90e18347 100644
--- a/nixos/tests/openldap.nix
+++ b/nixos/tests/openldap.nix
@@ -4,16 +4,12 @@ import ./make-test.nix {
   machine = { pkgs, ... }: {
     services.openldap = {
       enable = true;
-      extraConfig = ''
-        include ${pkgs.openldap}/etc/schema/core.schema
-        include ${pkgs.openldap}/etc/schema/cosine.schema
-        include ${pkgs.openldap}/etc/schema/inetorgperson.schema
-        include ${pkgs.openldap}/etc/schema/nis.schema
-        database bdb
-        suffix dc=example
+      suffix = "dc=example";
+      rootdn = "cn=root,dc=example";
+      rootpw = "notapassword";
+      database = "bdb";
+      extraDatabaseConfig = ''
         directory /var/db/openldap
-        rootdn cn=root,dc=example
-        rootpw notapassword
       '';
       declarativeContents = ''
         dn: dc=example
diff --git a/nixos/tests/pdns-recursor.nix b/nixos/tests/pdns-recursor.nix
new file mode 100644
index 00000000000..bf6e6093d69
--- /dev/null
+++ b/nixos/tests/pdns-recursor.nix
@@ -0,0 +1,12 @@
+import ./make-test.nix ({ pkgs, ... }: {
+  name = "powerdns";
+
+  nodes.server = { ... }: {
+    services.pdns-recursor.enable = true;
+  };
+
+  testScript = ''
+    $server->waitForUnit("pdns-recursor");
+    $server->waitForOpenPort("53");
+  '';
+})
diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix
index 8306abb8c42..85047f66f23 100644
--- a/nixos/tests/predictable-interface-names.nix
+++ b/nixos/tests/predictable-interface-names.nix
@@ -20,8 +20,7 @@ in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: {
 
     testScript = ''
       print $machine->succeed("ip link");
-      $machine->succeed("ip link show ${if predictable then "ens3" else "eth0"}");
-      $machine->fail("ip link show ${if predictable then "eth0" else "ens3"}");
+      $machine->${if predictable then "fail" else "succeed"}("ip link show eth0 ");
     '';
   };
 }) [[true false] [true false]])
diff --git a/nixos/tests/slurm.nix b/nixos/tests/slurm.nix
index b4458d8d095..720c36d472e 100644
--- a/nixos/tests/slurm.nix
+++ b/nixos/tests/slurm.nix
@@ -108,6 +108,8 @@ in {
   # cluster in the database before slurmctld is restarted
   subtest "add_account", sub {
     $control->succeed("sacctmgr -i add cluster default");
+    # check for cluster entry
+    $control->succeed("sacctmgr list cluster | awk '{ print \$1 }' | grep default");
   };
 
   subtest "can_start_slurmctld", sub {
@@ -133,6 +135,7 @@ in {
 
   subtest "check_slurm_dbd", sub {
     # find the srun job from above in the database
+    sleep 2;
     $submit->succeed("sacct | grep hostname");
   };
   '';
diff --git a/nixos/tests/systemd-confinement.nix b/nixos/tests/systemd-confinement.nix
new file mode 100644
index 00000000000..b7b10fb36aa
--- /dev/null
+++ b/nixos/tests/systemd-confinement.nix
@@ -0,0 +1,168 @@
+import ./make-test.nix {
+  name = "systemd-confinement";
+
+  machine = { pkgs, lib, ... }: let
+    testServer = pkgs.writeScript "testserver.sh" ''
+      #!${pkgs.stdenv.shell}
+      export PATH=${lib.escapeShellArg "${pkgs.coreutils}/bin"}
+      ${lib.escapeShellArg pkgs.stdenv.shell} 2>&1
+      echo "exit-status:$?"
+    '';
+
+    testClient = pkgs.writeScriptBin "chroot-exec" ''
+      #!${pkgs.stdenv.shell} -e
+      output="$(echo "$@" | nc -NU "/run/test$(< /teststep).sock")"
+      ret="$(echo "$output" | sed -nre '$s/^exit-status:([0-9]+)$/\1/p')"
+      echo "$output" | head -n -1
+      exit "''${ret:-1}"
+    '';
+
+    mkTestStep = num: { description, config ? {}, testScript }: {
+      systemd.sockets."test${toString num}" = {
+        description = "Socket for Test Service ${toString num}";
+        wantedBy = [ "sockets.target" ];
+        socketConfig.ListenStream = "/run/test${toString num}.sock";
+        socketConfig.Accept = true;
+      };
+
+      systemd.services."test${toString num}@" = {
+        description = "Confined Test Service ${toString num}";
+        confinement = (config.confinement or {}) // { enable = true; };
+        serviceConfig = (config.serviceConfig or {}) // {
+          ExecStart = testServer;
+          StandardInput = "socket";
+        };
+      } // removeAttrs config [ "confinement" "serviceConfig" ];
+
+      __testSteps = lib.mkOrder num ''
+        subtest '${lib.escape ["\\" "'"] description}', sub {
+          $machine->succeed('echo ${toString num} > /teststep');
+          ${testScript}
+        };
+      '';
+    };
+
+  in {
+    imports = lib.imap1 mkTestStep [
+      { description = "chroot-only confinement";
+        config.confinement.mode = "chroot-only";
+        testScript = ''
+          $machine->succeed(
+            'test "$(chroot-exec ls -1 / | paste -sd,)" = bin,nix',
+            'test "$(chroot-exec id -u)" = 0',
+            'chroot-exec chown 65534 /bin',
+          );
+        '';
+      }
+      { description = "full confinement with APIVFS";
+        testScript = ''
+          $machine->fail(
+            'chroot-exec ls -l /etc',
+            'chroot-exec ls -l /run',
+            'chroot-exec chown 65534 /bin',
+          );
+          $machine->succeed(
+            'test "$(chroot-exec id -u)" = 0',
+            'chroot-exec chown 0 /bin',
+          );
+        '';
+      }
+      { description = "check existence of bind-mounted /etc";
+        config.serviceConfig.BindReadOnlyPaths = [ "/etc" ];
+        testScript = ''
+          $machine->succeed('test -n "$(chroot-exec cat /etc/passwd)"');
+        '';
+      }
+      { description = "check if User/Group really runs as non-root";
+        config.serviceConfig.User = "chroot-testuser";
+        config.serviceConfig.Group = "chroot-testgroup";
+        testScript = ''
+          $machine->succeed('chroot-exec ls -l /dev');
+          $machine->succeed('test "$(chroot-exec id -u)" != 0');
+          $machine->fail('chroot-exec touch /bin/test');
+        '';
+      }
+      (let
+        symlink = pkgs.runCommand "symlink" {
+          target = pkgs.writeText "symlink-target" "got me\n";
+        } "ln -s \"$target\" \"$out\"";
+      in {
+        description = "check if symlinks are properly bind-mounted";
+        config.confinement.packages = lib.singleton symlink;
+        testScript = ''
+          $machine->fail('chroot-exec test -e /etc');
+          $machine->succeed('chroot-exec cat ${symlink} >&2');
+          $machine->succeed('test "$(chroot-exec cat ${symlink})" = "got me"');
+        '';
+      })
+      { description = "check if StateDirectory works";
+        config.serviceConfig.User = "chroot-testuser";
+        config.serviceConfig.Group = "chroot-testgroup";
+        config.serviceConfig.StateDirectory = "testme";
+        testScript = ''
+          $machine->succeed('chroot-exec touch /tmp/canary');
+          $machine->succeed('chroot-exec "echo works > /var/lib/testme/foo"');
+          $machine->succeed('test "$(< /var/lib/testme/foo)" = works');
+          $machine->succeed('test ! -e /tmp/canary');
+        '';
+      }
+      { description = "check if /bin/sh works";
+        testScript = ''
+          $machine->succeed(
+            'chroot-exec test -e /bin/sh',
+            'test "$(chroot-exec \'/bin/sh -c "echo bar"\')" = bar',
+          );
+        '';
+      }
+      { description = "check if suppressing /bin/sh works";
+        config.confinement.binSh = null;
+        testScript = ''
+          $machine->succeed(
+            'chroot-exec test ! -e /bin/sh',
+            'test "$(chroot-exec \'/bin/sh -c "echo foo"\')" != foo',
+          );
+        '';
+      }
+      { description = "check if we can set /bin/sh to something different";
+        config.confinement.binSh = "${pkgs.hello}/bin/hello";
+        testScript = ''
+          $machine->succeed(
+            'chroot-exec test -e /bin/sh',
+            'test "$(chroot-exec /bin/sh -g foo)" = foo',
+          );
+        '';
+      }
+      { description = "check if only Exec* dependencies are included";
+        config.environment.FOOBAR = pkgs.writeText "foobar" "eek\n";
+        testScript = ''
+          $machine->succeed('test "$(chroot-exec \'cat "$FOOBAR"\')" != eek');
+        '';
+      }
+      { description = "check if all unit dependencies are included";
+        config.environment.FOOBAR = pkgs.writeText "foobar" "eek\n";
+        config.confinement.fullUnit = true;
+        testScript = ''
+          $machine->succeed('test "$(chroot-exec \'cat "$FOOBAR"\')" = eek');
+        '';
+      }
+    ];
+
+    options.__testSteps = lib.mkOption {
+      type = lib.types.lines;
+      description = "All of the test steps combined as a single script.";
+    };
+
+    config.environment.systemPackages = lib.singleton testClient;
+
+    config.users.groups.chroot-testgroup = {};
+    config.users.users.chroot-testuser = {
+      description = "Chroot Test User";
+      group = "chroot-testgroup";
+    };
+  };
+
+  testScript = { nodes, ... }: ''
+    $machine->waitForUnit('multi-user.target');
+    ${nodes.machine.config.__testSteps}
+  '';
+}
diff --git a/nixos/tests/wireguard/default.nix b/nixos/tests/wireguard/default.nix
new file mode 100644
index 00000000000..b0797b96323
--- /dev/null
+++ b/nixos/tests/wireguard/default.nix
@@ -0,0 +1,97 @@
+let
+  wg-snakeoil-keys = import ./snakeoil-keys.nix;
+in
+
+import ../make-test.nix ({ pkgs, ...} : {
+  name = "wireguard";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ ma27 ];
+  };
+
+  nodes = {
+    peer0 = { lib, ... }: {
+      boot.kernel.sysctl = {
+        "net.ipv6.conf.all.forwarding" = "1";
+        "net.ipv6.conf.default.forwarding" = "1";
+        "net.ipv4.ip_forward" = "1";
+      };
+
+      networking.useDHCP = false;
+      networking.interfaces.eth1 = {
+        ipv4.addresses = lib.singleton {
+          address = "192.168.0.1";
+          prefixLength = 24;
+        };
+        ipv6.addresses = lib.singleton {
+          address = "fd00::1";
+          prefixLength = 64;
+        };
+      };
+
+      networking.firewall.allowedUDPPorts = [ 23542 ];
+      networking.wireguard.interfaces.wg0 = {
+        ips = [ "10.23.42.1/32" "fc00::1/128" ];
+        listenPort = 23542;
+
+        inherit (wg-snakeoil-keys.peer0) privateKey;
+
+        peers = lib.singleton {
+          allowedIPs = [ "10.23.42.2/32" "fc00::2/128" ];
+
+          inherit (wg-snakeoil-keys.peer1) publicKey;
+        };
+      };
+    };
+
+    peer1 = { pkgs, lib, ... }: {
+      boot.kernel.sysctl = {
+        "net.ipv6.conf.all.forwarding" = "1";
+        "net.ipv6.conf.default.forwarding" = "1";
+        "net.ipv4.ip_forward" = "1";
+      };
+
+      networking.useDHCP = false;
+      networking.interfaces.eth1 = {
+        ipv4.addresses = lib.singleton {
+          address = "192.168.0.2";
+          prefixLength = 24;
+        };
+        ipv6.addresses = lib.singleton {
+          address = "fd00::2";
+          prefixLength = 64;
+        };
+      };
+
+      networking.wireguard.interfaces.wg0 = {
+        ips = [ "10.23.42.2/32" "fc00::2/128" ];
+        listenPort = 23542;
+        allowedIPsAsRoutes = false;
+
+        inherit (wg-snakeoil-keys.peer1) privateKey;
+
+        peers = lib.singleton {
+          allowedIPs = [ "0.0.0.0/0" "::/0" ];
+          endpoint = "192.168.0.1:23542";
+          persistentKeepalive = 25;
+
+          inherit (wg-snakeoil-keys.peer0) publicKey;
+        };
+
+        postSetup = let inherit (pkgs) iproute; in ''
+          ${iproute}/bin/ip route replace 10.23.42.1/32 dev wg0
+          ${iproute}/bin/ip route replace fc00::1/128 dev wg0
+        '';
+      };
+    };
+  };
+
+  testScript = ''
+    startAll;
+
+    $peer0->waitForUnit("wireguard-wg0.service");
+    $peer1->waitForUnit("wireguard-wg0.service");
+
+    $peer1->succeed("ping -c5 fc00::1");
+    $peer1->succeed("ping -c5 10.23.42.1")
+  '';
+})
diff --git a/nixos/tests/wireguard/snakeoil-keys.nix b/nixos/tests/wireguard/snakeoil-keys.nix
new file mode 100644
index 00000000000..55ad582d405
--- /dev/null
+++ b/nixos/tests/wireguard/snakeoil-keys.nix
@@ -0,0 +1,11 @@
+{
+  peer0 = {
+    privateKey = "OPuVRS2T0/AtHDp3PXkNuLQYDiqJaBEEnYe42BSnJnQ=";
+    publicKey = "IujkG119YPr2cVQzJkSLYCdjpHIDjvr/qH1w1tdKswY=";
+  };
+
+  peer1 = {
+    privateKey = "uO8JVo/sanx2DOM0L9GUEtzKZ82RGkRnYgpaYc7iXmg=";
+    publicKey = "Ks9yRJIi/0vYgRmn14mIOQRwkcUGBujYINbMpik2SBI=";
+  };
+}