summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/man-nixos-install.xml2
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh16
-rw-r--r--nixos/modules/misc/version.nix5
-rw-r--r--nixos/modules/module-list.nix3
-rw-r--r--nixos/modules/programs/gnupg.nix2
-rw-r--r--nixos/modules/programs/sway.nix3
-rw-r--r--nixos/modules/programs/traceroute.nix26
-rw-r--r--nixos/modules/rename.nix5
-rw-r--r--nixos/modules/services/continuous-integration/buildkite-agent.nix31
-rw-r--r--nixos/modules/services/desktops/gnome3/at-spi2-core.nix3
-rw-r--r--nixos/modules/services/mail/roundcube.nix79
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager.nix21
-rw-r--r--nixos/modules/services/networking/knot.nix2
-rw-r--r--nixos/modules/services/networking/kresd.nix34
-rw-r--r--nixos/modules/services/networking/matterbridge.nix2
-rw-r--r--nixos/modules/services/networking/syncthing.nix18
-rw-r--r--nixos/modules/services/networking/zerotierone.nix10
-rw-r--r--nixos/modules/services/security/vault.nix1
-rw-r--r--nixos/modules/services/web-apps/dokuwiki.nix272
-rw-r--r--nixos/modules/services/web-servers/unit/default.nix8
-rw-r--r--nixos/modules/services/x11/hardware/multitouch.nix94
-rw-r--r--nixos/modules/system/boot/networkd.nix40
-rw-r--r--nixos/modules/virtualisation/amazon-init.nix11
-rw-r--r--nixos/release.nix3
-rw-r--r--nixos/tests/all-tests.nix2
-rw-r--r--nixos/tests/buildkite-agent.nix36
-rw-r--r--nixos/tests/corerad.nix3
-rw-r--r--nixos/tests/dokuwiki.nix29
28 files changed, 594 insertions, 167 deletions
diff --git a/nixos/doc/manual/man-nixos-install.xml b/nixos/doc/manual/man-nixos-install.xml
index 0752c397182..9255ce763ef 100644
--- a/nixos/doc/manual/man-nixos-install.xml
+++ b/nixos/doc/manual/man-nixos-install.xml
@@ -210,7 +210,7 @@
       The closure must be an appropriately configured NixOS system, with boot
       loader and partition configuration that fits the target host. Such a
       closure is typically obtained with a command such as <command>nix-build
-      -I nixos-config=./configuration.nix '&lt;nixos&gt;' -A system
+      -I nixos-config=./configuration.nix '&lt;nixpkgs/nixos&gt;' -A system
       --no-out-link</command>
      </para>
     </listitem>
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
index c53dc1000c4..61b4af11027 100644
--- a/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -22,7 +22,7 @@ repair=
 profile=/nix/var/nix/profiles/system
 buildHost=
 targetHost=
-maybeSudo=
+maybeSudo=()
 
 while [ "$#" -gt 0 ]; do
     i="$1"; shift 1
@@ -92,7 +92,7 @@ while [ "$#" -gt 0 ]; do
         ;;
       --use-remote-sudo)
         # note the trailing space
-        maybeSudo="sudo "
+        maybeSudo=(sudo --)
         shift 1
         ;;
       *)
@@ -102,6 +102,10 @@ while [ "$#" -gt 0 ]; do
     esac
 done
 
+if [ -n "$SUDO_USER" ]; then
+    maybeSudo=(sudo --)
+fi
+
 if [ -z "$buildHost" -a -n "$targetHost" ]; then
     buildHost="$targetHost"
 fi
@@ -116,17 +120,17 @@ buildHostCmd() {
     if [ -z "$buildHost" ]; then
         "$@"
     elif [ -n "$remoteNix" ]; then
-        ssh $SSHOPTS "$buildHost" env PATH="$remoteNix:$PATH" "$maybeSudo$@"
+        ssh $SSHOPTS "$buildHost" env PATH="$remoteNix:$PATH" "${maybeSudo[@]}" "$@"
     else
-        ssh $SSHOPTS "$buildHost" "$maybeSudo$@"
+        ssh $SSHOPTS "$buildHost" "${maybeSudo[@]}" "$@"
     fi
 }
 
 targetHostCmd() {
     if [ -z "$targetHost" ]; then
-        "$@"
+        "${maybeSudo[@]}" "$@"
     else
-        ssh $SSHOPTS "$targetHost" "$maybeSudo$@"
+        ssh $SSHOPTS "$targetHost" "${maybeSudo[@]}" "$@"
     fi
 }
 
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix
index ddbd3963cc5..8a85035ceb7 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -6,6 +6,7 @@ let
   cfg = config.system.nixos;
 
   gitRepo      = "${toString pkgs.path}/.git";
+  gitRepoValid = lib.pathIsGitRepo gitRepo;
   gitCommitId  = lib.substring 0 7 (commitIdFromGitRepo gitRepo);
 in
 
@@ -91,8 +92,8 @@ in
       # These defaults are set here rather than up there so that
       # changing them would not rebuild the manual
       version = mkDefault (cfg.release + cfg.versionSuffix);
-      revision      = mkIf (pathExists gitRepo) (mkDefault            gitCommitId);
-      versionSuffix = mkIf (pathExists gitRepo) (mkDefault (".git." + gitCommitId));
+      revision      = mkIf gitRepoValid (mkDefault            gitCommitId);
+      versionSuffix = mkIf gitRepoValid (mkDefault (".git." + gitCommitId));
     };
 
     # Generate /etc/os-release.  See
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index aaff8dcb330..176b62f6cb5 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -153,6 +153,7 @@
   ./programs/system-config-printer.nix
   ./programs/thefuck.nix
   ./programs/tmux.nix
+  ./programs/traceroute.nix
   ./programs/tsm-client.nix
   ./programs/udevil.nix
   ./programs/usbtop.nix
@@ -804,6 +805,7 @@
   ./services/web-apps/codimd.nix
   ./services/web-apps/cryptpad.nix
   ./services/web-apps/documize.nix
+  ./services/web-apps/dokuwiki.nix
   ./services/web-apps/frab.nix
   ./services/web-apps/gotify-server.nix
   ./services/web-apps/icingaweb2/icingaweb2.nix
@@ -871,7 +873,6 @@
   ./services/x11/display-managers/xpra.nix
   ./services/x11/fractalart.nix
   ./services/x11/hardware/libinput.nix
-  ./services/x11/hardware/multitouch.nix
   ./services/x11/hardware/synaptics.nix
   ./services/x11/hardware/wacom.nix
   ./services/x11/hardware/digimend.nix
diff --git a/nixos/modules/programs/gnupg.nix b/nixos/modules/programs/gnupg.nix
index 2d262d90657..7a3cb588ee7 100644
--- a/nixos/modules/programs/gnupg.nix
+++ b/nixos/modules/programs/gnupg.nix
@@ -96,7 +96,7 @@ in
     # This overrides the systemd user unit shipped with the gnupg package
     systemd.user.services.gpg-agent = mkIf (cfg.agent.pinentryFlavor != null) {
       serviceConfig.ExecStart = [ "" ''
-        ${pkgs.gnupg}/bin/gpg-agent --supervised \
+        ${cfg.package}/bin/gpg-agent --supervised \
           --pinentry-program ${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry
       '' ];
     };
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index 33e252be45f..7e646f8737d 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -87,7 +87,8 @@ in {
       type = with types; listOf package;
       default = with pkgs; [
         swaylock swayidle
-        xwayland rxvt_unicode dmenu
+        xwayland alacritty dmenu
+        rxvt_unicode # For backward compatibility (old default terminal)
       ];
       defaultText = literalExample ''
         with pkgs; [ swaylock swayidle xwayland rxvt_unicode dmenu ];
diff --git a/nixos/modules/programs/traceroute.nix b/nixos/modules/programs/traceroute.nix
new file mode 100644
index 00000000000..4eb0be3f0e0
--- /dev/null
+++ b/nixos/modules/programs/traceroute.nix
@@ -0,0 +1,26 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.traceroute;
+in {
+  options = {
+    programs.traceroute = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to configure a setcap wrapper for traceroute.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    security.wrappers.traceroute = {
+      source = "${pkgs.traceroute}/bin/traceroute";
+      capabilities = "cap_net_raw+p";
+    };
+  };
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 94b5530192e..26de8a18d92 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -29,6 +29,11 @@ with lib;
     (mkRemovedOptionModule [ "services.fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed")
     (mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " +
       "https://way-cooler.org/blog/2020/01/09/way-cooler-post-mortem.html"))
+    (mkRemovedOptionModule [ "services" "xserver" "multitouch" ] ''
+      services.xserver.multitouch (which uses xf86_input_mtrack) has been removed
+      as the underlying package isn't being maintained. Working alternatives are
+      libinput and synaptics.
+    '')
 
     # Do NOT add any option renames here, see top of the file
   ];
diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix
index 3c9c92bf052..58bce654941 100644
--- a/nixos/modules/services/continuous-integration/buildkite-agent.nix
+++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix
@@ -50,8 +50,8 @@ in
       };
 
       runtimePackages = mkOption {
-        default = [ pkgs.bash pkgs.nix ];
-        defaultText = "[ pkgs.bash pkgs.nix ]";
+        default = [ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ];
+        defaultText = "[ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]";
         description = "Add programs to the buildkite-agent environment";
         type = types.listOf types.package;
       };
@@ -93,7 +93,8 @@ in
       };
 
       privateSshKeyPath = mkOption {
-        type = types.path;
+        type = types.nullOr types.path;
+        default = null;
         ## maximum care is taken so that secrets (ssh keys and the CI token)
         ## don't end up in the Nix store.
         apply = final: if final == null then null else toString final;
@@ -185,14 +186,14 @@ in
   };
 
   config = mkIf config.services.buildkite-agent.enable {
-    users.users.buildkite-agent =
-      { name = "buildkite-agent";
-        home = cfg.dataDir;
-        createHome = true;
-        description = "Buildkite agent user";
-        extraGroups = [ "keys" ];
-        isSystemUser = true;
-      };
+    users.users.buildkite-agent = {
+      name = "buildkite-agent";
+      home = cfg.dataDir;
+      createHome = true;
+      description = "Buildkite agent user";
+      extraGroups = [ "keys" ];
+      isSystemUser = true;
+    };
 
     environment.systemPackages = [ cfg.package ];
 
@@ -212,11 +213,11 @@ in
           sshDir = "${cfg.dataDir}/.ssh";
           tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags);
         in
-          ''
+          optionalString (cfg.privateSshKeyPath != null) ''
             mkdir -m 0700 -p "${sshDir}"
-            cp -f "${toString cfg.openssh.privateKeyPath}" "${sshDir}/id_rsa"
-            chmod 600 "${sshDir}"/id_rsa*
-
+            cp -f "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa"
+            chmod 600 "${sshDir}"/id_rsa
+          '' + ''
             cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF
             token="$(cat ${toString cfg.tokenPath})"
             name="${cfg.name}"
diff --git a/nixos/modules/services/desktops/gnome3/at-spi2-core.nix b/nixos/modules/services/desktops/gnome3/at-spi2-core.nix
index cca98c43dc7..8fa108c4f9d 100644
--- a/nixos/modules/services/desktops/gnome3/at-spi2-core.nix
+++ b/nixos/modules/services/desktops/gnome3/at-spi2-core.nix
@@ -18,6 +18,9 @@ with lib;
         description = ''
           Whether to enable at-spi2-core, a service for the Assistive Technologies
           available on the GNOME platform.
+
+          Enable this if you get the error or warning
+          <literal>The name org.a11y.Bus was not provided by any .service files</literal>.
         '';
       };
 
diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix
index 36dda619ad0..0bb0eaedad5 100644
--- a/nixos/modules/services/mail/roundcube.nix
+++ b/nixos/modules/services/mail/roundcube.nix
@@ -5,6 +5,8 @@ with lib;
 let
   cfg = config.services.roundcube;
   fpm = config.services.phpfpm.pools.roundcube;
+  localDB = cfg.database.host == "localhost";
+  user = cfg.database.username;
 in
 {
   options.services.roundcube = {
@@ -44,7 +46,10 @@ in
       username = mkOption {
         type = types.str;
         default = "roundcube";
-        description = "Username for the postgresql connection";
+        description = ''
+          Username for the postgresql connection.
+          If <literal>database.host</literal> is set to <literal>localhost</literal>, a unix user and group of the same name will be created as well.
+        '';
       };
       host = mkOption {
         type = types.str;
@@ -58,7 +63,12 @@ in
       };
       password = mkOption {
         type = types.str;
-        description = "Password for the postgresql connection";
+        description = "Password for the postgresql connection. Do not use: the password will be stored world readable in the store; use <literal>passwordFile</literal> instead.";
+        default = "";
+      };
+      passwordFile = mkOption {
+        type = types.str;
+        description = "Password file for the postgresql connection. Must be readable by user <literal>nginx</literal>. Ignored if <literal>database.host</literal> is set to <literal>localhost</literal>, as peer authentication will be used.";
       };
       dbname = mkOption {
         type = types.str;
@@ -83,14 +93,22 @@ in
   };
 
   config = mkIf cfg.enable {
+    # backward compatibility: if password is set but not passwordFile, make one.
+    services.roundcube.database.passwordFile = mkIf (!localDB && cfg.database.password != "") (mkDefault ("${pkgs.writeText "roundcube-password" cfg.database.password}"));
+    warnings = lib.optional (!localDB && cfg.database.password != "") "services.roundcube.database.password is deprecated and insecure; use services.roundcube.database.passwordFile instead";
+
     environment.etc."roundcube/config.inc.php".text = ''
       <?php
 
+      ${lib.optionalString (!localDB) "$password = file_get_contents('${cfg.database.passwordFile}');"}
+
       $config = array();
-      $config['db_dsnw'] = 'pgsql://${cfg.database.username}:${cfg.database.password}@${cfg.database.host}/${cfg.database.dbname}';
+      $config['db_dsnw'] = 'pgsql://${cfg.database.username}${lib.optionalString (!localDB) ":' . $password . '"}@${if localDB then "unix(/run/postgresql)" else cfg.database.host}/${cfg.database.dbname}';
       $config['log_driver'] = 'syslog';
       $config['max_message_size'] = '25M';
       $config['plugins'] = [${concatMapStringsSep "," (p: "'${p}'") cfg.plugins}];
+      $config['des_key'] = file_get_contents('/var/lib/roundcube/des_key');
+      $config['mime_types'] = '${pkgs.nginx}/conf/mime.types';
       ${cfg.extraConfig}
     '';
 
@@ -116,12 +134,26 @@ in
       };
     };
 
-    services.postgresql = mkIf (cfg.database.host == "localhost") {
+    services.postgresql = mkIf localDB {
       enable = true;
+      ensureDatabases = [ cfg.database.dbname ];
+      ensureUsers = [ {
+        name = cfg.database.username;
+        ensurePermissions = {
+          "DATABASE ${cfg.database.username}" = "ALL PRIVILEGES";
+        };
+      } ];
+    };
+
+    users.users.${user} = mkIf localDB {
+      group = user;
+      isSystemUser = true;
+      createHome = false;
     };
+    users.groups.${user} = mkIf localDB {};
 
     services.phpfpm.pools.roundcube = {
-      user = "nginx";
+      user = if localDB then user else "nginx";
       phpOptions = ''
         error_log = 'stderr'
         log_errors = on
@@ -143,9 +175,7 @@ in
     };
     systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ];
 
-    systemd.services.roundcube-setup = let
-      pgSuperUser = config.services.postgresql.superUser;
-    in mkMerge [
+    systemd.services.roundcube-setup = mkMerge [
       (mkIf (cfg.database.host == "localhost") {
         requires = [ "postgresql.service" ];
         after = [ "postgresql.service" ];
@@ -153,22 +183,31 @@ in
       })
       {
         wantedBy = [ "multi-user.target" ];
-        script = ''
-          mkdir -p /var/lib/roundcube
-          if [ ! -f /var/lib/roundcube/db-created ]; then
-            if [ "${cfg.database.host}" = "localhost" ]; then
-              ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create role ${cfg.database.username} with login password '${cfg.database.password}'";
-              ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create database ${cfg.database.dbname} with owner ${cfg.database.username}";
-            fi
-            PGPASSWORD="${cfg.database.password}" ${pkgs.postgresql}/bin/psql -U ${cfg.database.username} \
-              -f ${cfg.package}/SQL/postgres.initial.sql \
-              -h ${cfg.database.host} ${cfg.database.dbname}
-            touch /var/lib/roundcube/db-created
+        script = let
+          psql = "${lib.optionalString (!localDB) "PGPASSFILE=${cfg.database.passwordFile}"} ${pkgs.postgresql}/bin/psql ${lib.optionalString (!localDB) "-h ${cfg.database.host} -U ${cfg.database.username} "} ${cfg.database.dbname}";
+        in
+        ''
+          version="$(${psql} -t <<< "select value from system where name = 'roundcube-version';" || true)"
+          if ! (grep -E '[a-zA-Z0-9]' <<< "$version"); then
+            ${psql} -f ${cfg.package}/SQL/postgres.initial.sql
+          fi
+
+          if [ ! -f /var/lib/roundcube/des_key ]; then
+            base64 /dev/urandom | head -c 24 > /var/lib/roundcube/des_key;
+            # we need to log out everyone in case change the des_key
+            # from the default when upgrading from nixos 19.09
+            ${psql} <<< 'TRUNCATE TABLE session;'
           fi
 
           ${pkgs.php}/bin/php ${cfg.package}/bin/update.sh
         '';
-        serviceConfig.Type = "oneshot";
+        serviceConfig = {
+          Type = "oneshot";
+          StateDirectory = "roundcube";
+          User = if localDB then user else "nginx";
+          # so that the des_key is not world readable
+          StateDirectoryMode = "0700";
+        };
       }
     ];
   };
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
index 9af6b1d94f3..2e8433fbc88 100644
--- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -18,7 +18,7 @@ let
     in checkedConfig yml;
 
   cmdlineArgs = cfg.extraFlags ++ [
-    "--config.file ${alertmanagerYml}"
+    "--config.file /tmp/alert-manager-substituted.yaml"
     "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}"
     "--log.level ${cfg.logLevel}"
     ] ++ (optional (cfg.webExternalUrl != null)
@@ -127,6 +127,18 @@ in {
           Extra commandline options when launching the Alertmanager.
         '';
       };
+
+      environmentFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/root/alertmanager.env";
+        description = ''
+          File to load as environment file. Environment variables
+          from this file will be interpolated into the config file
+          using envsubst with this syntax:
+          <literal>$ENVIRONMENT ''${VARIABLE}</literal>
+        '';
+      };
     };
   };
 
@@ -144,9 +156,14 @@ in {
       systemd.services.alertmanager = {
         wantedBy = [ "multi-user.target" ];
         after    = [ "network.target" ];
+        preStart = ''
+           ${lib.getBin pkgs.envsubst}/bin/envsubst -o /tmp/alert-manager-substituted.yaml" \
+                                                    -i ${alertmanagerYml}"
+        '';
         serviceConfig = {
           Restart  = "always";
-          DynamicUser = true;
+          DynamicUser = true; # implies PrivateTmp
+          EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
           WorkingDirectory = "/tmp";
           ExecStart = "${cfg.package}/bin/alertmanager" +
             optionalString (length cmdlineArgs != 0) (" \\\n  " +
diff --git a/nixos/modules/services/networking/knot.nix b/nixos/modules/services/networking/knot.nix
index 1cc1dd3f2f6..47364ecb846 100644
--- a/nixos/modules/services/networking/knot.nix
+++ b/nixos/modules/services/networking/knot.nix
@@ -56,6 +56,7 @@ in {
       package = mkOption {
         type = types.package;
         default = pkgs.knot-dns;
+        defaultText = "pkgs.knot-dns";
         description = ''
           Which Knot DNS package to use
         '';
@@ -92,4 +93,3 @@ in {
     environment.systemPackages = [ knot-cli-wrappers ];
   };
 }
-
diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix
index 5eb50a13ca9..bb941e93e15 100644
--- a/nixos/modules/services/networking/kresd.nix
+++ b/nixos/modules/services/networking/kresd.nix
@@ -5,12 +5,15 @@ with lib;
 let
 
   cfg = config.services.kresd;
-  package = pkgs.knot-resolver;
+  configFile = pkgs.writeText "kresd.conf" ''
+    ${optionalString (cfg.listenDoH != []) "modules.load('http')"}
+    ${cfg.extraConfig};
+  '';
 
-  configFile = pkgs.writeText "kresd.conf" cfg.extraConfig;
-in
-
-{
+  package = pkgs.knot-resolver.override {
+    extraFeatures = cfg.listenDoH != [];
+  };
+in {
   meta.maintainers = [ maintainers.vcunat /* upstream developer */ ];
 
   imports = [
@@ -67,6 +70,15 @@ in
         For detailed syntax see ListenStream in man systemd.socket.
       '';
     };
+    listenDoH = mkOption {
+      type = with types; listOf str;
+      default = [];
+      example = [ "198.51.100.1:443" "[2001:db8::1]:443" "443" ];
+      description = ''
+        Addresses and ports on which kresd should provide DNS over HTTPS (see RFC 7858).
+        For detailed syntax see ListenStream in man systemd.socket.
+      '';
+    };
     # TODO: perhaps options for more common stuff like cache size or forwarding
   };
 
@@ -104,6 +116,18 @@ in
       };
     };
 
+    systemd.sockets.kresd-doh = mkIf (cfg.listenDoH != []) rec {
+      wantedBy = [ "sockets.target" ];
+      before = wantedBy;
+      partOf = [ "kresd.socket" ];
+      listenStreams = cfg.listenDoH;
+      socketConfig = {
+        FileDescriptorName = "doh";
+        FreeBind = true;
+        Service = "kresd.service";
+      };
+    };
+
     systemd.sockets.kresd-control = rec {
       wantedBy = [ "sockets.target" ];
       before = wantedBy;
diff --git a/nixos/modules/services/networking/matterbridge.nix b/nixos/modules/services/networking/matterbridge.nix
index bad35133459..b8b4f37c84a 100644
--- a/nixos/modules/services/networking/matterbridge.nix
+++ b/nixos/modules/services/networking/matterbridge.nix
@@ -111,7 +111,7 @@ in
       serviceConfig = {
         User = cfg.user;
         Group = cfg.group;
-        ExecStart = "${pkgs.matterbridge.bin}/bin/matterbridge -conf ${matterbridgeConfToml}";
+        ExecStart = "${pkgs.matterbridge}/bin/matterbridge -conf ${matterbridgeConfToml}";
         Restart = "always";
         RestartSec = "10";
       };
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index 47b10e408c0..5b3eb6f04b4 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -484,6 +484,24 @@ in {
               -gui-address=${cfg.guiAddress} \
               -home=${cfg.configDir}
           '';
+          MemoryDenyWriteExecute = true;
+          NoNewPrivileges = true;
+          PrivateDevices = true;
+          PrivateMounts = true;
+          PrivateTmp = true;
+          PrivateUsers = true;
+          ProtectControlGroups = true;
+          ProtectHostname = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          CapabilityBoundingSet = [
+            "~CAP_SYS_PTRACE" "~CAP_SYS_ADMIN"
+            "~CAP_SETGID" "~CAP_SETUID" "~CAP_SETPCAP"
+            "~CAP_SYS_TIME" "~CAP_KILL"
+          ];
         };
       };
       syncthing-init = mkIf (
diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix
index 764af3846fe..069e15a909b 100644
--- a/nixos/modules/services/networking/zerotierone.nix
+++ b/nixos/modules/services/networking/zerotierone.nix
@@ -38,10 +38,13 @@ in
   config = mkIf cfg.enable {
     systemd.services.zerotierone = {
       description = "ZeroTierOne";
-      path = [ cfg.package ];
-      bindsTo = [ "network-online.target" ];
-      after = [ "network-online.target" ];
+
       wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      wants = [ "network-online.target" ];
+
+      path = [ cfg.package ];
+
       preStart = ''
         mkdir -p /var/lib/zerotier-one/networks.d
         chmod 700 /var/lib/zerotier-one
@@ -53,6 +56,7 @@ in
         ExecStart = "${cfg.package}/bin/zerotier-one -p${toString cfg.port}";
         Restart = "always";
         KillMode = "process";
+        TimeoutStopSec = 5;
       };
     };
 
diff --git a/nixos/modules/services/security/vault.nix b/nixos/modules/services/security/vault.nix
index b0ab8fadcbe..6a8a3a93327 100644
--- a/nixos/modules/services/security/vault.nix
+++ b/nixos/modules/services/security/vault.nix
@@ -135,6 +135,7 @@ in
         User = "vault";
         Group = "vault";
         ExecStart = "${cfg.package}/bin/vault server -config ${configFile}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
         PrivateDevices = true;
         PrivateTmp = true;
         ProtectSystem = "full";
diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix
new file mode 100644
index 00000000000..07af7aa0dfe
--- /dev/null
+++ b/nixos/modules/services/web-apps/dokuwiki.nix
@@ -0,0 +1,272 @@
+{ config, lib, pkgs, ... }:
+
+let
+
+  inherit (lib) mkEnableOption mkForce mkIf mkMerge mkOption optionalAttrs recursiveUpdate types;
+
+  cfg = config.services.dokuwiki;
+
+  user = config.services.nginx.user;
+  group = config.services.nginx.group;
+
+  dokuwikiAclAuthConfig = pkgs.writeText "acl.auth.php" ''
+    # acl.auth.php
+    # <?php exit()?>
+    #
+    # Access Control Lists
+    #
+    ${toString cfg.acl}
+  '';
+
+  dokuwikiLocalConfig = pkgs.writeText "local.php" ''
+    <?php
+    $conf['savedir'] = '${cfg.stateDir}';
+    $conf['superuser'] = '${toString cfg.superUser}';
+    $conf['useacl'] = '${toString cfg.aclUse}';
+    ${toString cfg.extraConfig}
+  '';
+
+  dokuwikiPluginsLocalConfig = pkgs.writeText "plugins.local.php" ''
+    <?php
+    ${cfg.pluginsConfig}
+  '';
+
+in
+{
+  options.services.dokuwiki = {
+    enable = mkEnableOption "DokuWiki web application.";
+
+    hostName = mkOption {
+      type = types.str;
+      default = "localhost";
+      description = "FQDN for the instance.";
+    };
+
+    stateDir = mkOption {
+      type = types.path;
+      default = "/var/lib/dokuwiki/data";
+      description = "Location of the dokuwiki state directory.";
+    };
+
+    acl = mkOption {
+      type = types.nullOr types.lines;
+      default = null;
+      example = "*               @ALL               8";
+      description = ''
+        Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
+        Mutually exclusive with services.dokuwiki.aclFile
+        Set this to a value other than null to take precedence over aclFile option.
+      '';
+    };
+
+    aclFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
+        Mutually exclusive with services.dokuwiki.acl which is preferred.
+        Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
+        Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
+      '';
+    };
+
+    aclUse = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Necessary for users to log in into the system.
+        Also limits anonymous users. When disabled,
+        everyone is able to create and edit content.
+      '';
+    };
+
+    pluginsConfig = mkOption {
+      type = types.lines;
+      default = ''
+        $plugins['authad'] = 0;
+        $plugins['authldap'] = 0;
+        $plugins['authmysql'] = 0;
+        $plugins['authpgsql'] = 0;
+      '';
+      description = ''
+        List of the dokuwiki (un)loaded plugins.
+      '';
+    };
+
+    superUser = mkOption {
+      type = types.nullOr types.str;
+      default = "@admin";
+      description = ''
+        You can set either a username, a list of usernames (“admin1,admin2”), 
+        or the name of a group by prepending an @ char to the groupname
+        Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
+      '';
+    };
+
+    usersFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        Location of the dokuwiki users file. List of users. Format:
+        login:passwordhash:Real Name:email:groups,comma,separated 
+        Create passwordHash easily by using:$ mkpasswd -5 password `pwgen 8 1`
+        Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/users.auth.php.dist"/>
+        '';
+    };
+
+    extraConfig = mkOption {
+      type = types.nullOr types.lines;
+      default = null;
+      example = ''
+        $conf['title'] = 'My Wiki';
+        $conf['userewrite'] = 1;
+      '';
+      description = ''
+        DokuWiki configuration. Refer to
+        <link xlink:href="https://www.dokuwiki.org/config"/>
+        for details on supported values.
+      '';
+    };
+
+    poolConfig = mkOption {
+      type = with types; attrsOf (oneOf [ str int bool ]);
+      default = {
+        "pm" = "dynamic";
+        "pm.max_children" = 32;
+        "pm.start_servers" = 2;
+        "pm.min_spare_servers" = 2;
+        "pm.max_spare_servers" = 4;
+        "pm.max_requests" = 500;
+      };
+      description = ''
+        Options for the dokuwiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
+        for details on configuration directives.
+      '';
+    };
+
+    nginx = mkOption {
+      type = types.submodule (
+        recursiveUpdate
+          (import ../web-servers/nginx/vhost-options.nix { inherit config lib; })
+          {
+            # Enable encryption by default,
+            options.forceSSL.default = true;
+            options.enableACME.default = true;
+          }
+      );
+      default = {forceSSL = true; enableACME = true;};
+      example = {
+        serverAliases = [
+          "wiki.\${config.networking.domain}"
+        ];
+        enableACME = false;
+      };
+      description = ''
+        With this option, you can customize the nginx virtualHost which already has sensible defaults for DokuWiki.
+      '';
+    };
+  };
+
+  # implementation
+
+  config = mkIf cfg.enable {
+
+    warnings = mkIf (cfg.superUser == null) ["Not setting services.dokuwiki.superUser will impair your ability to administer DokuWiki"];
+
+    assertions = [ 
+      {
+        assertion = cfg.aclUse -> (cfg.acl != null || cfg.aclFile != null);
+        message = "Either services.dokuwiki.acl or services.dokuwiki.aclFile is mandatory when aclUse is true";
+      }
+      {
+        assertion = cfg.usersFile != null -> cfg.aclUse != false;
+        message = "services.dokuwiki.aclUse must be true when usersFile is not null";
+      }
+    ];
+
+    services.phpfpm.pools.dokuwiki = {
+      inherit user;
+      inherit group;
+      phpEnv = {        
+        DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig}";
+        DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig}";
+      } //optionalAttrs (cfg.usersFile != null) {
+        DOKUWIKI_USERS_AUTH_CONFIG = "${cfg.usersFile}";
+      } //optionalAttrs (cfg.aclUse) {
+        DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig}" else "${toString cfg.aclFile}";
+      };
+      
+      settings = {
+        "listen.mode" = "0660";
+        "listen.owner" = user;
+        "listen.group" = group;
+      } // cfg.poolConfig;
+    };
+
+    services.nginx = {
+      enable = true;
+      
+       virtualHosts = {
+        ${cfg.hostName} = mkMerge [ cfg.nginx {
+          root = mkForce "${pkgs.dokuwiki}/share/dokuwiki/";
+          extraConfig = "fastcgi_param HTTPS on;";
+
+          locations."~ /(conf/|bin/|inc/|install.php)" = {
+            extraConfig = "deny all;";
+          };
+
+          locations."~ ^/data/" = {
+            root = "${cfg.stateDir}";
+            extraConfig = "internal;";
+          };
+
+          locations."~ ^/lib.*\.(js|css|gif|png|ico|jpg|jpeg)$" = {
+            extraConfig = "expires 365d;";
+          };
+
+          locations."/" = {
+            priority = 1;
+            index = "doku.php";
+            extraConfig = ''try_files $uri $uri/ @dokuwiki;'';
+          };
+
+          locations."@dokuwiki" = {
+            extraConfig = ''
+              # rewrites "doku.php/" out of the URLs if you set the userwrite setting to .htaccess in dokuwiki config page
+              rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
+              rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
+              rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
+              rewrite ^/(.*) /doku.php?id=$1&$args last;
+            '';
+          };
+
+          locations."~ \.php$" = {
+            extraConfig = ''
+              try_files $uri $uri/ /doku.php;
+              include ${pkgs.nginx}/conf/fastcgi_params;
+              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+              fastcgi_param REDIRECT_STATUS 200;
+              fastcgi_pass unix:${config.services.phpfpm.pools.dokuwiki.socket};
+              fastcgi_param HTTPS on;
+            '';
+          };
+        }];
+      };
+
+    };
+
+    systemd.tmpfiles.rules = [
+      "d ${cfg.stateDir}/attic 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/cache 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/index 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/locks 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/media 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/media_attic 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/media_meta 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/meta 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/pages 0750 ${user} ${group} - -"
+      "d ${cfg.stateDir}/tmp 0750 ${user} ${group} - -"
+    ];
+
+  };
+}
diff --git a/nixos/modules/services/web-servers/unit/default.nix b/nixos/modules/services/web-servers/unit/default.nix
index 2303dfa9540..f8a18954fc9 100644
--- a/nixos/modules/services/web-servers/unit/default.nix
+++ b/nixos/modules/services/web-servers/unit/default.nix
@@ -111,7 +111,7 @@ in {
         AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SETGID" "CAP_SETUID" ];
         # Security
         NoNewPrivileges = true;
-        # Sanboxing
+        # Sandboxing
         ProtectSystem = "full";
         ProtectHome = true;
         RuntimeDirectory = "unit";
@@ -130,8 +130,10 @@ in {
     };
 
     users.users = optionalAttrs (cfg.user == "unit") {
-      unit.group = cfg.group;
-      isSystemUser = true;
+      unit = {
+        group = cfg.group;
+        isSystemUser = true;
+      };
     };
 
     users.groups = optionalAttrs (cfg.group == "unit") {
diff --git a/nixos/modules/services/x11/hardware/multitouch.nix b/nixos/modules/services/x11/hardware/multitouch.nix
deleted file mode 100644
index c03bb3b494f..00000000000
--- a/nixos/modules/services/x11/hardware/multitouch.nix
+++ /dev/null
@@ -1,94 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let cfg = config.services.xserver.multitouch;
-    disabledTapConfig = ''
-      Option "MaxTapTime" "0"
-      Option "MaxTapMove" "0"
-      Option "TapButton1" "0"
-      Option "TapButton2" "0"
-      Option "TapButton3" "0"
-    '';
-in {
-
-  options = {
-
-    services.xserver.multitouch = {
-
-      enable = mkOption {
-        default = false;
-        description = "Whether to enable multitouch touchpad support.";
-      };
-
-      invertScroll = mkOption {
-        default = false;
-        type = types.bool;
-        description = "Whether to invert scrolling direction à la OSX Lion";
-      };
-
-      ignorePalm = mkOption {
-        default = false;
-        type = types.bool;
-        description = "Whether to ignore touches detected as being the palm (i.e when typing)";
-      };
-
-      tapButtons = mkOption {
-        type = types.bool;
-        default = true;
-        description = "Whether to enable tap buttons.";
-      };
-
-      buttonsMap = mkOption {
-        type = types.listOf types.int;
-        default = [3 2 0];
-        example = [1 3 2];
-        description = "Remap touchpad buttons.";
-        apply = map toString;
-      };
-
-      additionalOptions = mkOption {
-        type = types.str;
-        default = "";
-        example = ''
-          Option "ScaleDistance" "50"
-          Option "RotateDistance" "60"
-        '';
-        description = ''
-          Additional options for mtrack touchpad driver.
-        '';
-      };
-
-    };
-
-  };
-
-  config = mkIf cfg.enable {
-
-    services.xserver.modules = [ pkgs.xf86_input_mtrack ];
-
-    services.xserver.config =
-      ''
-        # Automatically enable the multitouch driver
-        Section "InputClass"
-          MatchIsTouchpad "on"
-          Identifier "Touchpads"
-          Driver "mtrack"
-          Option "IgnorePalm" "${boolToString cfg.ignorePalm}"
-          Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}"
-          Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}"
-          Option "ClickFinger3" "${builtins.elemAt cfg.buttonsMap 2}"
-          ${optionalString (!cfg.tapButtons) disabledTapConfig}
-          ${optionalString cfg.invertScroll ''
-            Option "ScrollUpButton" "5"
-            Option "ScrollDownButton" "4"
-            Option "ScrollLeftButton" "7"
-            Option "ScrollRightButton" "6"
-          ''}
-          ${cfg.additionalOptions}
-        EndSection
-      '';
-
-  };
-
-}
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 3e289a63139..56a9d6b1138 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -49,7 +49,7 @@ let
     (assertValueOneOf "Kind" [
       "bond" "bridge" "dummy" "gre" "gretap" "ip6gre" "ip6tnl" "ip6gretap" "ipip"
       "ipvlan" "macvlan" "macvtap" "sit" "tap" "tun" "veth" "vlan" "vti" "vti6"
-      "vxlan" "geneve" "vrf" "vcan" "vxcan" "wireguard" "netdevsim"
+      "vxlan" "geneve" "vrf" "vcan" "vxcan" "wireguard" "netdevsim" "xfrm"
     ])
     (assertByteFormat "MTUBytes")
     (assertMacAddress "MACAddress")
@@ -172,6 +172,14 @@ let
     (assertValueOneOf "AllSlavesActive" boolValues)
   ];
 
+  checkXfrm = checkUnitConfig "Xfrm" [
+    (assertOnlyFields [
+      "InterfaceId" "Independent"
+    ])
+    (assertRange "InterfaceId" 1 4294967295)
+    (assertValueOneOf "Independent" boolValues)
+  ];
+
   checkNetwork = checkUnitConfig "Network" [
     (assertOnlyFields [
       "Description" "DHCP" "DHCPServer" "LinkLocalAddressing" "IPv4LLRoute"
@@ -182,7 +190,7 @@ let
       "IPv6HopLimit" "IPv4ProxyARP" "IPv6ProxyNDP" "IPv6ProxyNDPAddress"
       "IPv6PrefixDelegation" "IPv6MTUBytes" "Bridge" "Bond" "VRF" "VLAN"
       "IPVLAN" "MACVLAN" "VXLAN" "Tunnel" "ActiveSlave" "PrimarySlave"
-      "ConfigureWithoutCarrier"
+      "ConfigureWithoutCarrier" "Xfrm"
     ])
     # Note: For DHCP the values both, none, v4, v6 are deprecated
     (assertValueOneOf "DHCP" ["yes" "no" "ipv4" "ipv6" "both" "none" "v4" "v6"])
@@ -477,6 +485,18 @@ let
       '';
     };
 
+    xfrmConfig = mkOption {
+      default = {};
+      example = { InterfaceId = 1; };
+      type = types.addCheck (types.attrsOf unitOption) checkXfrm;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Xfrm]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
   };
 
   addressOptions = {
@@ -712,6 +732,16 @@ let
       '';
     };
 
+    xfrm = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of xfrm interfaces to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
     addresses = mkOption {
       default = [ ];
       type = with types; listOf (submodule addressOptions);
@@ -810,6 +840,11 @@ let
             ${attrsToSection def.bondConfig}
 
           ''}
+          ${optionalString (def.xfrmConfig != { }) ''
+            [Xfrm]
+            ${attrsToSection def.xfrmConfig}
+
+          ''}
           ${optionalString (def.wireguardConfig != { }) ''
             [WireGuard]
             ${attrsToSection def.wireguardConfig}
@@ -847,6 +882,7 @@ let
           ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)}
           ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)}
           ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)}
+          ${concatStringsSep "\n" (map (s: "Xfrm=${s}") def.xfrm)}
 
           ${optionalString (def.dhcpConfig != { }) ''
             [DHCP]
diff --git a/nixos/modules/virtualisation/amazon-init.nix b/nixos/modules/virtualisation/amazon-init.nix
index 8032b2c6d7c..8c12e0e49bf 100644
--- a/nixos/modules/virtualisation/amazon-init.nix
+++ b/nixos/modules/virtualisation/amazon-init.nix
@@ -7,8 +7,8 @@ let
     echo "attempting to fetch configuration from EC2 user data..."
 
     export HOME=/root
-    export PATH=${pkgs.lib.makeBinPath [ config.nix.package pkgs.systemd pkgs.gnugrep pkgs.gnused config.system.build.nixos-rebuild]}:$PATH
-    export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels
+    export PATH=${pkgs.lib.makeBinPath [ config.nix.package pkgs.systemd pkgs.gnugrep pkgs.git pkgs.gnutar pkgs.gzip pkgs.gnused config.system.build.nixos-rebuild]}:$PATH
+    export NIX_PATH=nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels
 
     userData=/etc/ec2-metadata/user-data
 
@@ -18,9 +18,9 @@ let
       # that as the channel.
       if sed '/^\(#\|SSH_HOST_.*\)/d' < "$userData" | grep -q '\S'; then
         channels="$(grep '^###' "$userData" | sed 's|###\s*||')"
-        printf "%s" "$channels" | while read channel; do
+        while IFS= read -r channel; do
           echo "writing channel: $channel"
-        done
+        done < <(printf "%s\n" "$channels")
 
         if [[ -n "$channels" ]]; then
           printf "%s" "$channels" > /root/.nix-channels
@@ -48,7 +48,7 @@ in {
     wantedBy = [ "multi-user.target" ];
     after = [ "multi-user.target" ];
     requires = [ "network-online.target" ];
- 
+
     restartIfChanged = false;
     unitConfig.X-StopOnRemoval = false;
 
@@ -58,4 +58,3 @@ in {
     };
   };
 }
-
diff --git a/nixos/release.nix b/nixos/release.nix
index f40b5fa9bd7..9109f5751eb 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -209,7 +209,8 @@ in rec {
     hydraJob ((import lib/eval-config.nix {
       inherit system;
       modules =
-        [ versionModule
+        [ configuration
+          versionModule
           ./maintainers/scripts/ec2/amazon-image.nix
         ];
     }).config.system.build.amazonImage)
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index ceeab2c21d9..8c11464f9d6 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -33,6 +33,7 @@ in
   bind = handleTest ./bind.nix {};
   bittorrent = handleTest ./bittorrent.nix {};
   #blivet = handleTest ./blivet.nix {};   # broken since 2017-07024
+  buildkite-agent = handleTest ./buildkite-agent.nix {};
   boot = handleTestOn ["x86_64-linux"] ./boot.nix {}; # syslinux is unsupported on aarch64
   boot-stage1 = handleTest ./boot-stage1.nix {};
   borgbackup = handleTest ./borgbackup.nix {};
@@ -74,6 +75,7 @@ in
   docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
   docker-tools-overlay = handleTestOn ["x86_64-linux"] ./docker-tools-overlay.nix {};
   documize = handleTest ./documize.nix {};
+  dokuwiki = handleTest ./dokuwiki.nix {};
   dovecot = handleTest ./dovecot.nix {};
   # ec2-config doesn't work in a sandbox as the simulated ec2 instance needs network access
   #ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
diff --git a/nixos/tests/buildkite-agent.nix b/nixos/tests/buildkite-agent.nix
new file mode 100644
index 00000000000..3c824c9aedf
--- /dev/null
+++ b/nixos/tests/buildkite-agent.nix
@@ -0,0 +1,36 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+
+{
+  name = "buildkite-agent";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ flokli ];
+  };
+
+  nodes = {
+    node1 = { pkgs, ... }: {
+      services.buildkite-agent = {
+        enable = true;
+        privateSshKeyPath = (import ./ssh-keys.nix pkgs).snakeOilPrivateKey;
+        tokenPath = (pkgs.writeText "my-token" "5678");
+      };
+    };
+    # don't configure ssh key, run as a separate user
+    node2 = { pkgs, ...}: {
+      services.buildkite-agent = {
+        enable = true;
+        tokenPath = (pkgs.writeText "my-token" "1234");
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+    # we can't wait on the unit to start up, as we obviously can't connect to buildkite,
+    # but we can look whether files are set up correctly
+
+    node1.wait_for_file("/var/lib/buildkite-agent/buildkite-agent.cfg")
+    node1.wait_for_file("/var/lib/buildkite-agent/.ssh/id_rsa")
+
+    node2.wait_for_file("/var/lib/buildkite-agent/buildkite-agent.cfg")
+  '';
+})
diff --git a/nixos/tests/corerad.nix b/nixos/tests/corerad.nix
index 68b698857b4..950c9abc899 100644
--- a/nixos/tests/corerad.nix
+++ b/nixos/tests/corerad.nix
@@ -18,8 +18,7 @@ import ./make-test-python.nix (
               [[interfaces]]
               name = "eth1"
               send_advertisements = true
-                [[interfaces.plugins]]
-                name = "prefix"
+                [[interfaces.prefix]]
                 prefix = "::/64"
             '';
           };
diff --git a/nixos/tests/dokuwiki.nix b/nixos/tests/dokuwiki.nix
new file mode 100644
index 00000000000..38bde10f47e
--- /dev/null
+++ b/nixos/tests/dokuwiki.nix
@@ -0,0 +1,29 @@
+import ./make-test-python.nix ({ lib, ... }:
+
+with lib;
+
+{
+  name = "dokuwiki";
+  meta.maintainers = with maintainers; [ maintainers."1000101" ];
+
+  nodes.machine =
+    { pkgs, ... }:
+    { services.dokuwiki = {
+        enable = true;
+        acl = " ";
+        superUser = null;
+        nginx = {
+          forceSSL = false;
+          enableACME = false;
+        };
+      }; 
+    };
+
+  testScript = ''
+    machine.start()
+    machine.wait_for_unit("phpfpm-dokuwiki.service")
+    machine.wait_for_unit("nginx.service")
+    machine.wait_for_open_port(80)
+    machine.succeed("curl -sSfL http://localhost/ | grep 'DokuWiki'")
+  '';
+})