summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
authorFrederik Rietdijk <fridh@fridh.nl>2019-08-27 16:36:47 +0200
committerFrederik Rietdijk <fridh@fridh.nl>2019-08-27 16:36:47 +0200
commit98640fd48212f8e6552517f667bba1901f5936d4 (patch)
tree0b5f895f31f16b47e8f837c1d3ac87da1f2884eb /nixos/modules
parent70c1c856d4c96fb37b6e507db4acb125656f992d (diff)
parentb40ee8268515d78b419f53fb22a9fad49b985de8 (diff)
downloadnixpkgs-98640fd48212f8e6552517f667bba1901f5936d4.tar
nixpkgs-98640fd48212f8e6552517f667bba1901f5936d4.tar.gz
nixpkgs-98640fd48212f8e6552517f667bba1901f5936d4.tar.bz2
nixpkgs-98640fd48212f8e6552517f667bba1901f5936d4.tar.lz
nixpkgs-98640fd48212f8e6552517f667bba1901f5936d4.tar.xz
nixpkgs-98640fd48212f8e6552517f667bba1901f5936d4.tar.zst
nixpkgs-98640fd48212f8e6552517f667bba1901f5936d4.zip
Merge master into staging-next
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/update-users-groups.pl1
-rw-r--r--nixos/modules/misc/ids.nix6
-rw-r--r--nixos/modules/module-list.nix3
-rw-r--r--nixos/modules/rename.nix4
-rw-r--r--nixos/modules/services/databases/memcached.nix1
-rw-r--r--nixos/modules/services/mail/rmilter.nix252
-rw-r--r--nixos/modules/services/misc/zoneminder.nix5
-rw-r--r--nixos/modules/services/networking/dnschain.nix14
-rw-r--r--nixos/modules/services/networking/jormungandr.nix2
-rw-r--r--nixos/modules/services/networking/pdns-recursor.nix83
-rw-r--r--nixos/modules/services/networking/unifi.nix1
-rw-r--r--nixos/modules/services/torrent/transmission.nix36
-rw-r--r--nixos/modules/services/web-apps/matomo.nix2
-rw-r--r--nixos/modules/services/web-apps/moodle.nix300
-rw-r--r--nixos/modules/services/web-servers/darkhttpd.nix77
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix309
-rw-r--r--nixos/modules/system/boot/systemd.nix6
17 files changed, 685 insertions, 417 deletions
diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl
index ef5e6346f02..59cea51c611 100644
--- a/nixos/modules/config/update-users-groups.pl
+++ b/nixos/modules/config/update-users-groups.pl
@@ -267,6 +267,7 @@ foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow") : ()) {
     next if !defined $u;
     $hashedPassword = "!" if !$spec->{mutableUsers};
     $hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
+    chomp $hashedPassword;
     push @shadowNew, join(":", $name, $hashedPassword, @rest) . "\n";
     $shadowSeen{$name} = 1;
 }
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 1047df95cdf..efd8544d6a2 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -251,7 +251,7 @@
       gale = 223;
       matrix-synapse = 224;
       rspamd = 225;
-      rmilter = 226;
+      # rmilter = 226; # unused, removed 2019-08-22
       cfdyndns = 227;
       gammu-smsd = 228;
       pdnsd = 229;
@@ -340,6 +340,7 @@
       cockroachdb = 313;
       zoneminder = 314;
       paperless = 315;
+      mailman = 316;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -559,7 +560,7 @@
       gale = 223;
       matrix-synapse = 224;
       rspamd = 225;
-      rmilter = 226;
+      # rmilter = 226; # unused, removed 2019-08-22
       cfdyndns = 227;
       pdnsd = 229;
       octoprint = 230;
@@ -640,6 +641,7 @@
       cockroachdb = 313;
       zoneminder = 314;
       paperless = 315;
+      mailman = 316;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 388f4788b59..6331e76c648 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -387,7 +387,6 @@
   ./services/mail/spamassassin.nix
   ./services/mail/rspamd.nix
   ./services/mail/rss2email.nix
-  ./services/mail/rmilter.nix
   ./services/mail/roundcube.nix
   ./services/mail/nullmailer.nix
   ./services/misc/airsonic.nix
@@ -790,6 +789,7 @@
   ./services/web-apps/mattermost.nix
   ./services/web-apps/mediawiki.nix
   ./services/web-apps/miniflux.nix
+  ./services/web-apps/moodle.nix
   ./services/web-apps/nextcloud.nix
   ./services/web-apps/nexus.nix
   ./services/web-apps/pgpkeyserver-lite.nix
@@ -803,6 +803,7 @@
   ./services/web-apps/zabbix.nix
   ./services/web-servers/apache-httpd/default.nix
   ./services/web-servers/caddy.nix
+  ./services/web-servers/darkhttpd.nix
   ./services/web-servers/fcgiwrap.nix
   ./services/web-servers/hitch/default.nix
   ./services/web-servers/hydron.nix
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 65014b4beed..348ad094e5a 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -72,8 +72,8 @@ with lib;
     # PAM
     (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
 
-    (mkRemovedOptionModule [ "services" "rmilter" "bindInetSockets" ] "Use services.rmilter.bindSocket.* instead")
-    (mkRemovedOptionModule [ "services" "rmilter" "bindUnixSockets" ] "Use services.rmilter.bindSocket.* instead")
+    # rmilter/rspamd
+    (mkRemovedOptionModule [ "services" "rmilter" ] "Use services.rspamd.* instead to set up milter service")
 
     # Xsession script
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "logsXsession" ] [ "services" "xserver" "displayManager" "job" "logToFile" ])
diff --git a/nixos/modules/services/databases/memcached.nix b/nixos/modules/services/databases/memcached.nix
index f9e403dfc0c..84d2c8674f4 100644
--- a/nixos/modules/services/databases/memcached.nix
+++ b/nixos/modules/services/databases/memcached.nix
@@ -103,7 +103,6 @@ in
         LockPersonality = true;
         RestrictRealtime = true;
         PrivateMounts = true;
-        PrivateUsers = true;
         MemoryDenyWriteExecute = true;
       };
     };
diff --git a/nixos/modules/services/mail/rmilter.nix b/nixos/modules/services/mail/rmilter.nix
deleted file mode 100644
index 466365b6b30..00000000000
--- a/nixos/modules/services/mail/rmilter.nix
+++ /dev/null
@@ -1,252 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  rspamdCfg = config.services.rspamd;
-  postfixCfg = config.services.postfix;
-  cfg = config.services.rmilter;
-
-  inetSocket = addr: port: "inet:${addr}:${toString port}";
-  unixSocket = sock: "unix:${sock}";
-
-  systemdSocket = if cfg.bindSocket.type == "unix" then cfg.bindSocket.path
-    else "${cfg.bindSocket.address}:${toString cfg.bindSocket.port}";
-  rmilterSocket = if cfg.bindSocket.type == "unix" then unixSocket cfg.bindSocket.path
-    else inetSocket cfg.bindSocket.address cfg.bindSocket.port;
-
-  rmilterConf = ''
-    pidfile = /run/rmilter/rmilter.pid;
-    bind_socket = ${if cfg.socketActivation then "fd:3" else rmilterSocket};
-    tempdir = /tmp;
-  '' + (with cfg.rspamd; if enable then ''
-    spamd {
-      servers = ${concatStringsSep ", " servers};
-      connect_timeout = 1s;
-      results_timeout = 20s;
-      error_time = 10;
-      dead_time = 300;
-      maxerrors = 10;
-      reject_message = "${rejectMessage}";
-      ${optionalString (length whitelist != 0)  "whitelist = ${concatStringsSep ", " whitelist};"}
-
-      # rspamd_metric - metric for using with rspamd
-      # Default: "default"
-      rspamd_metric = "default";
-      ${extraConfig}
-    };
-  '' else "") + cfg.extraConfig;
-
-  rmilterConfigFile = pkgs.writeText "rmilter.conf" rmilterConf;
-
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.rmilter = {
-
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to run the rmilter daemon.";
-      };
-
-      debug = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to run the rmilter daemon in debug mode.";
-      };
-
-      user = mkOption {
-        type = types.string;
-        default = "rmilter";
-        description = ''
-          User to use when no root privileges are required.
-        '';
-       };
-
-      group = mkOption {
-        type = types.string;
-        default = "rmilter";
-        description = ''
-          Group to use when no root privileges are required.
-        '';
-       };
-
-      bindSocket.type = mkOption {
-        type = types.enum [ "unix" "inet" ];
-        default = "unix";
-        description = ''
-          What kind of socket rmilter should listen on. Either "unix"
-          for an Unix domain socket or "inet" for a TCP socket.
-        '';
-      };
-
-      bindSocket.path = mkOption {
-       type = types.str;
-       default = "/run/rmilter.sock";
-       description = ''
-          Path to Unix domain socket to listen on.
-        '';
-      };
-
-      bindSocket.address = mkOption {
-        type = types.str;
-        default = "[::1]";
-        example = "0.0.0.0";
-        description = ''
-          Inet address to listen on.
-        '';
-      };
-
-      bindSocket.port = mkOption {
-        type = types.int;
-        default = 11990;
-        description = ''
-          Inet port to listen on.
-        '';
-      };
-
-      socketActivation = mkOption {
-        type = types.bool;
-        default = true;
-        description = ''
-          Enable systemd socket activation for rmilter.
-
-          Disabling socket activation is not recommended when a Unix
-          domain socket is used and could lead to incorrect
-          permissions.
-        '';
-      };
-
-      rspamd = {
-        enable = mkOption {
-          type = types.bool;
-          default = rspamdCfg.enable;
-          description = "Whether to use rspamd to filter mails";
-        };
-
-        servers = mkOption {
-          type = types.listOf types.str;
-          default = ["r:/run/rspamd/rspamd.sock"];
-          description = ''
-            Spamd socket definitions.
-            Is server name is prefixed with r: it is rspamd server.
-          '';
-        };
-
-        whitelist = mkOption {
-          type = types.listOf types.str;
-          default = [ ];
-          description = "list of ips or nets that should be not checked with spamd";
-        };
-
-        rejectMessage = mkOption {
-          type = types.str;
-          default = "Spam message rejected; If this is not spam contact abuse";
-          description = "reject message for spam";
-        };
-
-        extraConfig = mkOption {
-          type = types.lines;
-          default = "";
-          description = "Custom snippet to append to end of `spamd' section";
-        };
-      };
-
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Custom snippet to append to rmilter config";
-      };
-
-      postfix = {
-        enable = mkOption {
-          type = types.bool;
-          default = false;
-          description = "Add rmilter to postfix main.conf";
-        };
-
-        configFragment = mkOption {
-          type = types.str;
-          description = "Addon to postfix configuration";
-          default = ''
-            smtpd_milters = ${rmilterSocket}
-            milter_protocol = 6
-            milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
-          '';
-        };
-      };
-
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = mkMerge [
-
-    (mkIf cfg.enable {
-      warnings = [
-        ''`config.services.rmilter' is deprecated, `rmilter' deprecated and unsupported by upstream, and will be removed from next releases. Use built-in rspamd milter instead.''
-      ];
-
-      users.users = singleton {
-        name = cfg.user;
-        description = "rmilter daemon";
-        uid = config.ids.uids.rmilter;
-        group = cfg.group;
-      };
-
-      users.groups = singleton {
-        name = cfg.group;
-        gid = config.ids.gids.rmilter;
-      };
-
-      systemd.services.rmilter = {
-        description = "Rmilter Service";
-
-        wantedBy = [ "multi-user.target" ];
-        after = [ "network.target" ];
-
-        serviceConfig = {
-          ExecStart = "${pkgs.rmilter}/bin/rmilter ${optionalString cfg.debug "-d"} -n -c ${rmilterConfigFile}";
-          ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
-          User = cfg.user;
-          Group = cfg.group;
-          PermissionsStartOnly = true;
-          Restart = "always";
-          RuntimeDirectory = "rmilter";
-          RuntimeDirectoryMode = "0750";
-        };
-
-      };
-
-      systemd.sockets.rmilter = mkIf cfg.socketActivation {
-        description = "Rmilter service socket";
-        wantedBy = [ "sockets.target" ];
-        socketConfig = {
-          ListenStream = systemdSocket;
-          SocketUser = cfg.user;
-          SocketGroup = cfg.group;
-          SocketMode = "0660";
-        };
-      };
-    })
-
-    (mkIf (cfg.enable && cfg.rspamd.enable && rspamdCfg.enable) {
-      users.users.${cfg.user}.extraGroups = [ rspamdCfg.group ];
-    })
-
-    (mkIf (cfg.enable && cfg.postfix.enable) {
-      services.postfix.extraConfig = cfg.postfix.configFragment;
-      users.users.${postfixCfg.user}.extraGroups = [ cfg.group ];
-    })
-  ];
-}
diff --git a/nixos/modules/services/misc/zoneminder.nix b/nixos/modules/services/misc/zoneminder.nix
index 6e83d47df1c..bf38b9ad7a2 100644
--- a/nixos/modules/services/misc/zoneminder.nix
+++ b/nixos/modules/services/misc/zoneminder.nix
@@ -200,7 +200,10 @@ in {
       "zoneminder/80-nixos.conf".source    = configFile;
     };
 
-    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ];
+    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [
+      cfg.port
+      6802 # zmtrigger
+    ];
 
     services = {
       fcgiwrap = lib.mkIf useNginx {
diff --git a/nixos/modules/services/networking/dnschain.nix b/nixos/modules/services/networking/dnschain.nix
index 0c2add424ba..5b58ea9b0c9 100644
--- a/nixos/modules/services/networking/dnschain.nix
+++ b/nixos/modules/services/networking/dnschain.nix
@@ -136,10 +136,16 @@ in
         "/.dns/127.0.0.1#${toString cfg.dns.port}"
       ];
 
-    services.pdns-recursor.forwardZones = mkIf cfgs.pdns-recursor.resolveDNSChainQueries
-      { bit = "127.0.0.1:${toString cfg.dns.port}";
-        dns = "127.0.0.1:${toString cfg.dns.port}";
-      };
+    services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveDNSChainQueries {
+      forwardZones =
+        { bit = "127.0.0.1:${toString cfg.dns.port}";
+          dns = "127.0.0.1:${toString cfg.dns.port}";
+        };
+      luaConfig =''
+        addNTA("bit", "namecoin doesn't support DNSSEC")
+        addNTA("dns", "namecoin doesn't support DNSSEC")
+      '';
+    };
 
     users.users = singleton {
       name = username;
diff --git a/nixos/modules/services/networking/jormungandr.nix b/nixos/modules/services/networking/jormungandr.nix
index c1a16a316b7..0c66b85fe8a 100644
--- a/nixos/modules/services/networking/jormungandr.nix
+++ b/nixos/modules/services/networking/jormungandr.nix
@@ -13,7 +13,7 @@ let
   configSettings = {
     storage = dataDir;
     p2p = {
-      public_address = "/ip4/127.0.0.1/tcp/8606";
+      public_address = "/ip4/127.0.0.1/tcp/8299";
       messages = "high";
       blocks = "high";
     };
diff --git a/nixos/modules/services/networking/pdns-recursor.nix b/nixos/modules/services/networking/pdns-recursor.nix
index d07deb9dcc6..ec69cc838da 100644
--- a/nixos/modules/services/networking/pdns-recursor.nix
+++ b/nixos/modules/services/networking/pdns-recursor.nix
@@ -6,25 +6,27 @@ let
   dataDir  = "/var/lib/pdns-recursor";
   username = "pdns-recursor";
 
-  cfg   = config.services.pdns-recursor;
-  zones = mapAttrsToList (zone: uri: "${zone}.=${uri}") cfg.forwardZones;
+  cfg = config.services.pdns-recursor;
 
-  configFile = pkgs.writeText "recursor.conf" ''
-    local-address=${cfg.dns.address}
-    local-port=${toString cfg.dns.port}
-    allow-from=${concatStringsSep "," cfg.dns.allowFrom}
+  oneOrMore  = type: with types; either type (listOf type);
+  valueType  = with types; oneOf [ int str bool path ];
+  configType = with types; attrsOf (nullOr (oneOrMore valueType));
 
-    webserver-address=${cfg.api.address}
-    webserver-port=${toString cfg.api.port}
-    webserver-allow-from=${concatStringsSep "," cfg.api.allowFrom}
+  toBool    = val: if val then "yes" else "no";
+  serialize = val: with types;
+         if str.check       val then val
+    else if int.check       val then toString val
+    else if path.check      val then toString val
+    else if bool.check      val then toBool val
+    else if builtins.isList val then (concatMapStringsSep "," serialize val)
+    else "";
 
-    forward-zones=${concatStringsSep "," zones}
-    export-etc-hosts=${if cfg.exportHosts then "yes" else "no"}
-    dnssec=${cfg.dnssecValidation}
-    serve-rfc1918=${if cfg.serveRFC1918 then "yes" else "no"}
+  configFile = pkgs.writeText "recursor.conf"
+    (concatStringsSep "\n"
+      (flip mapAttrsToList cfg.settings
+        (name: val: "${name}=${serialize val}")));
 
-    ${cfg.extraConfig}
-  '';
+  mkDefaultAttrs = mapAttrs (n: v: mkDefault v);
 
 in {
   options.services.pdns-recursor = {
@@ -117,17 +119,55 @@ in {
       '';
     };
 
-    extraConfig = mkOption {
+    settings = mkOption {
+      type = configType;
+      default = { };
+      example = literalExample ''
+        {
+          loglevel = 8;
+          log-common-errors = true;
+        }
+      '';
+      description = ''
+        PowerDNS Recursor settings. Use this option to configure Recursor
+        settings not exposed in a NixOS option or to bypass one.
+        See the full documentation at
+        <link xlink:href="https://doc.powerdns.com/recursor/settings.html"/>
+        for the available options.
+      '';
+    };
+
+    luaConfig = mkOption {
       type = types.lines;
       default = "";
       description = ''
-        Extra options to be appended to the configuration file.
+        The content Lua configuration file for PowerDNS Recursor. See
+        <link xlink:href="https://doc.powerdns.com/recursor/lua-config/index.html"/>.
       '';
     };
   };
 
   config = mkIf cfg.enable {
 
+    services.pdns-recursor.settings = mkDefaultAttrs {
+      local-address = cfg.dns.address;
+      local-port    = cfg.dns.port;
+      allow-from    = cfg.dns.allowFrom;
+
+      webserver-address    = cfg.api.address;
+      webserver-port       = cfg.api.port;
+      webserver-allow-from = cfg.api.allowFrom;
+
+      forward-zones    = mapAttrsToList (zone: uri: "${zone}.=${uri}") cfg.forwardZones;
+      export-etc-hosts = cfg.exportHosts;
+      dnssec           = cfg.dnssecValidation;
+      serve-rfc1918    = cfg.serveRFC1918;
+      lua-config-file  = pkgs.writeText "recursor.lua" cfg.luaConfig;
+
+      log-timestamp  = false;
+      disable-syslog = true;
+    };
+
     users.users."${username}" = {
       home = dataDir;
       createHome = true;
@@ -150,8 +190,7 @@ in {
         AmbientCapabilities = "cap_net_bind_service";
         ExecStart = ''${pkgs.pdns-recursor}/bin/pdns_recursor \
           --config-dir=${dataDir} \
-          --socket-dir=${dataDir} \
-          --disable-syslog
+          --socket-dir=${dataDir}
         '';
       };
 
@@ -165,4 +204,10 @@ in {
       '';
     };
   };
+
+  imports = [
+   (mkRemovedOptionModule [ "services" "pdns-recursor" "extraConfig" ]
+     "To change extra Recursor settings use services.pdns-recursor.settings instead.")
+  ];
+
 }
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
index 6239c88b7e4..c922ba15960 100644
--- a/nixos/modules/services/networking/unifi.nix
+++ b/nixos/modules/services/networking/unifi.nix
@@ -176,6 +176,7 @@ in
         Type = "simple";
         ExecStart = "${(removeSuffix "\n" cmd)} start";
         ExecStop = "${(removeSuffix "\n" cmd)} stop";
+        Restart = "on-failure";
         User = "unifi";
         UMask = "0077";
         WorkingDirectory = "${stateDir}";
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index f544928fb6b..a94a471361e 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -84,6 +84,18 @@ in
           The directory where transmission will create files.
         '';
       };
+
+      user = mkOption {
+        type = types.str;
+        default = "transmission";
+        description = "User account under which Transmission runs.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "transmission";
+        description = "Group account under which Transmission runs.";
+      };
     };
   };
 
@@ -99,7 +111,8 @@ in
       serviceConfig.ExecStartPre = preStart;
       serviceConfig.ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f --port ${toString config.services.transmission.port}";
       serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-      serviceConfig.User = "transmission";
+      serviceConfig.User = cfg.user;
+      serviceConfig.Group = cfg.group;
       # NOTE: transmission has an internal umask that also must be set (in settings.json)
       serviceConfig.UMask = "0002";
     };
@@ -107,14 +120,19 @@ in
     # It's useful to have transmission in path, e.g. for remote control
     environment.systemPackages = [ pkgs.transmission ];
 
-    users.groups.transmission.gid = config.ids.gids.transmission;
-    users.users.transmission = {
-      group = "transmission";
-      uid = config.ids.uids.transmission;
-      description = "Transmission BitTorrent user";
-      home = homeDir;
-      createHome = true;
-    };
+    users.users = optionalAttrs (cfg.user == "transmission") (singleton
+      { name = "transmission";
+        group = cfg.group;
+        uid = config.ids.uids.transmission;
+        description = "Transmission BitTorrent user";
+        home = homeDir;
+        createHome = true;
+      });
+
+    users.groups = optionalAttrs (cfg.group == "transmission") (singleton
+      { name = "transmission";
+        gid = config.ids.gids.transmission;
+      });
 
     # AppArmor profile
     security.apparmor.profiles = mkIf apparmor [
diff --git a/nixos/modules/services/web-apps/matomo.nix b/nixos/modules/services/web-apps/matomo.nix
index bf8b9dbcc21..d9f840408cc 100644
--- a/nixos/modules/services/web-apps/matomo.nix
+++ b/nixos/modules/services/web-apps/matomo.nix
@@ -176,7 +176,7 @@ in {
             # Use User-Private Group scheme to protect Matomo data, but allow administration / backup via 'matomo' group
             # Copy config folder
             chmod g+s "${dataDir}"
-            cp -r "${cfg.package}/config" "${dataDir}/"
+            cp -r "${cfg.package}/share/config" "${dataDir}/"
             chmod -R u+rwX,g+rwX,o-rwx "${dataDir}"
 
             # check whether user setup has already been done
diff --git a/nixos/modules/services/web-apps/moodle.nix b/nixos/modules/services/web-apps/moodle.nix
new file mode 100644
index 00000000000..f2516c67c6b
--- /dev/null
+++ b/nixos/modules/services/web-apps/moodle.nix
@@ -0,0 +1,300 @@
+{ config, lib, pkgs, ... }:
+
+let
+  inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
+  inherit (lib) concatStringsSep literalExample mapAttrsToList optional optionalString;
+
+  cfg = config.services.moodle;
+  fpm = config.services.phpfpm.pools.moodle;
+
+  user = "moodle";
+  group = config.services.httpd.group;
+  stateDir = "/var/lib/moodle";
+
+  moodleConfig = pkgs.writeText "config.php" ''
+  <?php  // Moodle configuration file
+
+  unset($CFG);
+  global $CFG;
+  $CFG = new stdClass();
+
+  $CFG->dbtype    = '${ { "mysql" = "mariadb"; "pgsql" = "pgsql"; }.${cfg.database.type} }';
+  $CFG->dblibrary = 'native';
+  $CFG->dbhost    = '${cfg.database.host}';
+  $CFG->dbname    = '${cfg.database.name}';
+  $CFG->dbuser    = '${cfg.database.user}';
+  ${optionalString (cfg.database.passwordFile != null) "$CFG->dbpass = file_get_contents('${cfg.database.passwordFile}');"}
+  $CFG->prefix    = 'mdl_';
+  $CFG->dboptions = array (
+    'dbpersist' => 0,
+    'dbport' => '${toString cfg.database.port}',
+    ${optionalString (cfg.database.socket != null) "'dbsocket' => '${cfg.database.socket}',"}
+    'dbcollation' => 'utf8mb4_unicode_ci',
+  );
+
+  $CFG->wwwroot   = '${if cfg.virtualHost.enableSSL then "https" else "http"}://${cfg.virtualHost.hostName}';
+  $CFG->dataroot  = '${stateDir}';
+  $CFG->admin     = 'admin';
+
+  $CFG->directorypermissions = 02777;
+  $CFG->disableupdateautodeploy = true;
+
+  $CFG->pathtogs = '${pkgs.ghostscript}/bin/gs';
+  $CFG->pathtophp = '${pkgs.php}/bin/php';
+  $CFG->pathtodu = '${pkgs.coreutils}/bin/du';
+  $CFG->aspellpath = '${pkgs.aspell}/bin/aspell';
+  $CFG->pathtodot = '${pkgs.graphviz}/bin/dot';
+
+  require_once('${cfg.package}/share/moodle/lib/setup.php');
+
+  // There is no php closing tag in this file,
+  // it is intentional because it prevents trailing whitespace problems!
+  '';
+
+  mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql";
+  pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql";
+in
+{
+  # interface
+  options.services.moodle = {
+    enable = mkEnableOption "Moodle web application";
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.moodle;
+      defaultText = "pkgs.moodle";
+      description = "The Moodle package to use.";
+    };
+
+    initialPassword = mkOption {
+      type = types.str;
+      example = "correcthorsebatterystaple";
+      description = ''
+        Specifies the initial password for the admin, i.e. the password assigned if the user does not already exist.
+        The password specified here is world-readable in the Nix store, so it should be changed promptly.
+      '';
+    };
+
+    database = {
+      type = mkOption {
+        type = types.enum [ "mysql" "pgsql" ];
+        default = "mysql";
+        description = ''Database engine to use.'';
+      };
+
+      host = mkOption {
+        type = types.str;
+        default = "localhost";
+        description = "Database host address.";
+      };
+
+      port = mkOption {
+        type = types.int;
+        description = "Database host port.";
+        default = {
+          "mysql" = 3306;
+          "pgsql" = 5432;
+        }.${cfg.database.type};
+        defaultText = "3306";
+      };
+
+      name = mkOption {
+        type = types.str;
+        default = "moodle";
+        description = "Database name.";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "moodle";
+        description = "Database user.";
+      };
+
+      passwordFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/run/keys/moodle-dbpassword";
+        description = ''
+          A file containing the password corresponding to
+          <option>database.user</option>.
+        '';
+      };
+
+      socket = mkOption {
+        type = types.nullOr types.path;
+        default =
+          if mysqlLocal then "/run/mysqld/mysqld.sock"
+          else if pgsqlLocal then "/run/postgresql"
+          else null;
+        defaultText = "/run/mysqld/mysqld.sock";
+        description = "Path to the unix socket file to use for authentication.";
+      };
+
+      createLocally = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Create the database and database user locally.";
+      };
+    };
+
+    virtualHost = mkOption {
+      type = types.submodule ({
+        options = import ../web-servers/apache-httpd/per-server-options.nix {
+          inherit lib;
+          forMainServer = false;
+        };
+      });
+      example = {
+        hostName = "moodle.example.org";
+        enableSSL = true;
+        adminAddr = "webmaster@example.org";
+        sslServerCert = "/var/lib/acme/moodle.example.org/full.pem";
+        sslServerKey = "/var/lib/acme/moodle.example.org/key.pem";
+      };
+      description = ''
+        Apache configuration can be done by adapting <option>services.httpd.virtualHosts</option>.
+        See <xref linkend="opt-services.httpd.virtualHosts"/> for further information.
+      '';
+    };
+
+    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 Moodle PHP pool. See the documentation on <literal>php-fpm.conf</literal>
+        for details on configuration directives.
+      '';
+    };
+  };
+
+  # implementation
+  config = mkIf cfg.enable {
+
+    assertions = [
+      { assertion = cfg.database.createLocally -> cfg.database.user == user;
+        message = "services.moodle.database.user must be set to ${user} if services.moodle.database.createLocally is set true";
+      }
+      { assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
+        message = "a password cannot be specified if services.moodle.database.createLocally is set to true";
+      }
+    ];
+
+    services.mysql = mkIf mysqlLocal {
+      enable = true;
+      package = mkDefault pkgs.mariadb;
+      ensureDatabases = [ cfg.database.name ];
+      ensureUsers = [
+        { name = cfg.database.user;
+          ensurePermissions = {
+            "${cfg.database.name}.*" = "SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER";
+          };
+        }
+      ];
+    };
+
+    services.postgresql = mkIf pgsqlLocal {
+      enable = true;
+      ensureDatabases = [ cfg.database.name ];
+      ensureUsers = [
+        { name = cfg.database.user;
+          ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
+        }
+      ];
+    };
+
+    services.phpfpm.pools.moodle = {
+      inherit user group;
+      phpEnv.MOODLE_CONFIG = "${moodleConfig}";
+      phpOptions = ''
+        zend_extension = opcache.so
+        opcache.enable = 1
+      '';
+      settings = {
+        "listen.owner" = config.services.httpd.user;
+        "listen.group" = config.services.httpd.group;
+      } // cfg.poolConfig;
+    };
+
+    services.httpd = {
+      enable = true;
+      adminAddr = mkDefault cfg.virtualHost.adminAddr;
+      extraModules = [ "proxy_fcgi" ];
+      virtualHosts = [ (mkMerge [
+        cfg.virtualHost {
+          documentRoot = mkForce "${cfg.package}/share/moodle";
+          extraConfig = ''
+            <Directory "${cfg.package}/share/moodle">
+              <FilesMatch "\.php$">
+                <If "-f %{REQUEST_FILENAME}">
+                  SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
+                </If>
+              </FilesMatch>
+              Options -Indexes
+              DirectoryIndex index.php
+            </Directory>
+          '';
+        }
+      ]) ];
+    };
+
+    systemd.tmpfiles.rules = [
+      "d '${stateDir}' 0750 ${user} ${group} - -"
+    ];
+
+    systemd.services.moodle-init = {
+      wantedBy = [ "multi-user.target" ];
+      before = [ "phpfpm-moodle.service" ];
+      after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
+      environment.MOODLE_CONFIG = moodleConfig;
+      script = ''
+        ${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/check_database_schema.php && rc=$? || rc=$?
+
+        [ "$rc" == 1 ] && ${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/upgrade.php \
+          --non-interactive \
+          --allow-unstable
+
+        [ "$rc" == 2 ] && ${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/install_database.php \
+          --agree-license \
+          --adminpass=${cfg.initialPassword}
+
+        true
+      '';
+      serviceConfig = {
+        User = user;
+        Group = group;
+        Type = "oneshot";
+      };
+    };
+
+    systemd.services.moodle-cron = {
+      description = "Moodle cron service";
+      after = [ "moodle-init.service" ];
+      environment.MOODLE_CONFIG = moodleConfig;
+      serviceConfig = {
+        User = user;
+        Group = group;
+        ExecStart = "${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/cron.php";
+      };
+    };
+
+    systemd.timers.moodle-cron = {
+      description = "Moodle cron timer";
+      wantedBy = [ "timers.target" ];
+      timerConfig = {
+        OnCalendar = "minutely";
+      };
+    };
+
+    systemd.services.httpd.after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
+
+    users.users."${user}".group = group;
+
+  };
+}
diff --git a/nixos/modules/services/web-servers/darkhttpd.nix b/nixos/modules/services/web-servers/darkhttpd.nix
new file mode 100644
index 00000000000..80870118c33
--- /dev/null
+++ b/nixos/modules/services/web-servers/darkhttpd.nix
@@ -0,0 +1,77 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.darkhttpd;
+
+  args = concatStringsSep " " ([
+    cfg.rootDir
+    "--port ${toString cfg.port}"
+    "--addr ${cfg.address}"
+  ] ++ cfg.extraArgs
+    ++ optional cfg.hideServerId             "--no-server-id"
+    ++ optional config.networking.enableIPv6 "--ipv6");
+
+in {
+  options.services.darkhttpd = with types; {
+    enable = mkEnableOption "DarkHTTPd web server";
+
+    port = mkOption {
+      default = 80;
+      type = ints.u16;
+      description = ''
+        Port to listen on.
+        Pass 0 to let the system choose any free port for you.
+      '';
+    };
+
+    address = mkOption {
+      default = "127.0.0.1";
+      type = str;
+      description = ''
+        Address to listen on.
+        Pass `all` to listen on all interfaces.
+      '';
+    };
+
+    rootDir = mkOption {
+      type = path;
+      description = ''
+        Path from which to serve files.
+      '';
+    };
+
+    hideServerId = mkOption {
+      type = bool;
+      default = true;
+      description = ''
+        Don't identify the server type in headers or directory listings.
+      '';
+    };
+
+    extraArgs = mkOption {
+      type = listOf str;
+      default = [];
+      description = ''
+        Additional configuration passed to the executable.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.darkhttpd = {
+      description = "Dark HTTPd";
+      wants = [ "network.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        DynamicUser = true;
+        ExecStart = "${cfg.package}/bin/darkhttpd ${args}";
+        AmbientCapabilities = lib.mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
+        Restart = "on-failure";
+        RestartSec = "2s";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index b18d06a095d..0caa93ad217 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -3,7 +3,9 @@
 with lib;
 
 let
+
   cfg = config.services.xserver.desktopManager.gnome3;
+  serviceCfg = config.services.gnome3;
 
   # Prioritize nautilus by default when opening directories
   mimeAppsList = pkgs.writeTextFile {
@@ -45,10 +47,19 @@ let
 
   flashbackEnabled = cfg.flashback.enableMetacity || length cfg.flashback.customSessions > 0;
 
-in {
+in
+
+{
 
   options = {
 
+    services.gnome3 = {
+      core-os-services.enable = mkEnableOption "essential services for GNOME3";
+      core-shell.enable = mkEnableOption "GNOME Shell services";
+      core-utilities.enable = mkEnableOption "GNOME core utilities";
+      games.enable = mkEnableOption "GNOME games";
+    };
+
     services.xserver.desktopManager.gnome3 = {
       enable = mkOption {
         default = false;
@@ -121,138 +132,194 @@ in {
 
   };
 
-  config = mkIf cfg.enable {
-
-    # Enable helpful DBus services.
-    security.polkit.enable = true;
-    services.udisks2.enable = true;
-    services.accounts-daemon.enable = true;
-    services.dleyna-renderer.enable = mkDefault true;
-    services.dleyna-server.enable = mkDefault true;
-    services.gnome3.at-spi2-core.enable = true;
-    services.gnome3.evolution-data-server.enable = true;
-    services.gnome3.glib-networking.enable = true;
-    services.gnome3.gnome-keyring.enable = true;
-    services.gnome3.gnome-online-accounts.enable = mkDefault true;
-    services.gnome3.gnome-remote-desktop.enable = mkDefault true;
-    services.gnome3.gnome-settings-daemon.enable = true;
-    services.gnome3.gnome-user-share.enable = mkDefault true;
-    services.gvfs.enable = true;
-    services.gnome3.rygel.enable = mkDefault true;
-    services.gnome3.seahorse.enable = mkDefault true;
-    services.gnome3.sushi.enable = mkDefault true;
-    services.gnome3.tracker.enable = mkDefault true;
-    services.gnome3.tracker-miners.enable = mkDefault true;
-    hardware.pulseaudio.enable = mkDefault true;
-    services.telepathy.enable = mkDefault true;
-    networking.networkmanager.enable = mkDefault true;
-    services.upower.enable = config.powerManagement.enable;
-    services.dbus.packages =
-      optional config.services.printing.enable pkgs.system-config-printer ++
-      optional flashbackEnabled pkgs.gnome3.gnome-screensaver;
-    services.colord.enable = mkDefault true;
-    services.packagekit.enable = mkDefault true;
-    hardware.bluetooth.enable = mkDefault true;
-    services.hardware.bolt.enable = mkDefault true;
-    services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center
-    systemd.packages = [ pkgs.gnome3.vino ];
-    xdg.portal.enable = true;
-    xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
-
-    # Enable default programs
-    programs.dconf.enable = true;
-    programs.evince.enable = mkDefault true;
-    programs.file-roller.enable = mkDefault true;
-    programs.gnome-disks.enable = mkDefault true;
-    programs.gnome-documents.enable = mkDefault true;
-    programs.gnome-terminal.enable = mkDefault true;
-
-    # If gnome3 is installed, build vim for gtk3 too.
-    nixpkgs.config.vim.gui = "gtk3";
-
-    fonts.fonts = [
-      pkgs.dejavu_fonts pkgs.cantarell-fonts
-      pkgs.source-sans-pro
-      pkgs.source-code-pro # Default monospace font in 3.32
-    ];
-
-    services.xserver.displayManager.extraSessionFilePackages = [ pkgs.gnome3.gnome-session ]
-      ++ map
-        (wm: pkgs.gnome3.gnome-flashback.mkSessionForWm {
-          inherit (wm) wmName wmLabel wmCommand;
-        }) (optional cfg.flashback.enableMetacity {
-              wmName = "metacity";
-              wmLabel = "Metacity";
-              wmCommand = "${pkgs.gnome3.metacity}/bin/metacity";
-            } ++ cfg.flashback.customSessions);
-
-    environment.extraInit = ''
-      ${concatMapStrings (p: ''
-        if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
-          export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
-        fi
-
-        if [ -d "${p}/lib/girepository-1.0" ]; then
-          export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0
-          export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
-        fi
-      '') cfg.sessionPath}
-    '';
+  config = mkMerge [
+    (mkIf (cfg.enable || flashbackEnabled) {
+      services.gnome3.core-os-services.enable = true;
+      services.gnome3.core-shell.enable = true;
+      services.gnome3.core-utilities.enable = mkDefault true;
 
+      services.xserver.displayManager.extraSessionFilePackages = [ pkgs.gnome3.gnome-session ];
 
-    services.geoclue2.enable = mkDefault true;
-    # GNOME should have its own geoclue agent
-    services.geoclue2.enableDemoAgent = false;
+      environment.extraInit = ''
+        ${concatMapStrings (p: ''
+          if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
+            export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
+          fi
 
-    services.geoclue2.appConfig."gnome-datetime-panel" = {
-      isAllowed = true;
-      isSystem = true;
-    };
-    services.geoclue2.appConfig."gnome-color-panel" = {
-      isAllowed = true;
-      isSystem = true;
-    };
-    services.geoclue2.appConfig."org.gnome.Shell" = {
-      isAllowed = true;
-      isSystem = true;
-    };
+          if [ -d "${p}/lib/girepository-1.0" ]; then
+            export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0
+            export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
+          fi
+        '') cfg.sessionPath}
+      '';
 
-    environment.variables.GNOME_SESSION_DEBUG = optionalString cfg.debug "1";
+      environment.systemPackages = cfg.sessionPath;
 
-    # Override default mimeapps
-    environment.variables.XDG_DATA_DIRS = [ "${mimeAppsList}/share" ];
+      environment.variables.GNOME_SESSION_DEBUG = mkIf cfg.debug "1";
 
-    # Override GSettings schemas
-    environment.variables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
+      # Override GSettings schemas
+      environment.variables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
 
-    # Let nautilus find extensions
-    # TODO: Create nautilus-with-extensions package
-    environment.variables.NAUTILUS_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-3.0";
+       # If gnome3 is installed, build vim for gtk3 too.
+      nixpkgs.config.vim.gui = "gtk3";
+    })
 
-    services.xserver.updateDbusEnvironment = true;
+    (mkIf flashbackEnabled {
+      services.xserver.displayManager.extraSessionFilePackages =  map
+        (wm: pkgs.gnome3.gnome-flashback.mkSessionForWm {
+          inherit (wm) wmName wmLabel wmCommand;
+        }) (optional cfg.flashback.enableMetacity {
+              wmName = "metacity";
+              wmLabel = "Metacity";
+              wmCommand = "${pkgs.gnome3.metacity}/bin/metacity";
+            } ++ cfg.flashback.customSessions);
 
-    environment.systemPackages = pkgs.gnome3.corePackages ++ cfg.sessionPath
-      ++ (pkgs.gnome3.removePackagesByName pkgs.gnome3.optionalPackages config.environment.gnome3.excludePackages) ++ [
-      pkgs.xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
-    ];
+      security.pam.services.gnome-screensaver = {
+        enableGnomeKeyring = true;
+      };
 
-    # Use the correct gnome3 packageSet
-    networking.networkmanager.basePackages =
-      { inherit (pkgs) networkmanager modemmanager wpa_supplicant crda;
+      services.dbus.packages = [
+        pkgs.gnome3.gnome-screensaver
+      ];
+    })
+
+    (mkIf serviceCfg.core-os-services.enable {
+      hardware.bluetooth.enable = mkDefault true;
+      hardware.pulseaudio.enable = mkDefault true;
+      programs.dconf.enable = true;
+      security.polkit.enable = true;
+      services.accounts-daemon.enable = true;
+      services.dleyna-renderer.enable = mkDefault true;
+      services.dleyna-server.enable = mkDefault true;
+      services.gnome3.at-spi2-core.enable = true;
+      services.gnome3.evolution-data-server.enable = true;
+      services.gnome3.gnome-keyring.enable = true;
+      services.gnome3.gnome-online-accounts.enable = mkDefault true;
+      services.gnome3.gnome-online-miners.enable = true;
+      services.gnome3.tracker-miners.enable = mkDefault true;
+      services.gnome3.tracker.enable = mkDefault true;
+      services.hardware.bolt.enable = mkDefault true;
+      services.packagekit.enable = mkDefault true;
+      services.udisks2.enable = true;
+      services.upower.enable = config.powerManagement.enable;
+      services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center
+
+      xdg.portal.enable = true;
+      xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
+
+      networking.networkmanager.enable = mkDefault true;
+
+      # Use the correct gnome3 packageSet
+      networking.networkmanager.basePackages = {
+        inherit (pkgs) networkmanager modemmanager wpa_supplicant crda;
         inherit (pkgs.gnome3) networkmanager-openvpn networkmanager-vpnc
-                              networkmanager-openconnect networkmanager-fortisslvpn
-                              networkmanager-iodine networkmanager-l2tp; };
-
-    # Needed for themes and backgrounds
-    environment.pathsToLink = [
-      "/share"
-      "/share/nautilus-python/extensions"
-    ];
+        networkmanager-openconnect networkmanager-fortisslvpn
+        networkmanager-iodine networkmanager-l2tp;
+      };
 
-    security.pam.services.gnome-screensaver = mkIf flashbackEnabled {
-      enableGnomeKeyring = true;
-    };
-  };
+      services.xserver.updateDbusEnvironment = true;
+
+      # Needed for themes and backgrounds
+      environment.pathsToLink = [
+        "/share" # TODO: https://github.com/NixOS/nixpkgs/issues/47173
+      ];
+    })
+
+    (mkIf serviceCfg.core-shell.enable {
+      services.colord.enable = mkDefault true;
+      services.gnome3.glib-networking.enable = true;
+      services.gnome3.gnome-remote-desktop.enable = mkDefault true;
+      services.gnome3.gnome-settings-daemon.enable = true;
+      services.gnome3.gnome-user-share.enable = mkDefault true;
+      services.gnome3.rygel.enable = mkDefault true;
+      services.gvfs.enable = true;
+      services.telepathy.enable = mkDefault true;
+      systemd.packages = [ pkgs.gnome3.vino ];
+      services.dbus.packages =
+        optional config.services.printing.enable pkgs.system-config-printer;
+
+      services.geoclue2.enable = mkDefault true;
+      services.geoclue2.enableDemoAgent = false; # GNOME has its own geoclue agent
+
+      services.geoclue2.appConfig."gnome-datetime-panel" = {
+        isAllowed = true;
+        isSystem = true;
+      };
+      services.geoclue2.appConfig."gnome-color-panel" = {
+        isAllowed = true;
+        isSystem = true;
+      };
+      services.geoclue2.appConfig."org.gnome.Shell" = {
+        isAllowed = true;
+        isSystem = true;
+      };
 
+      fonts.fonts = with pkgs; [
+        cantarell-fonts
+        dejavu_fonts
+        source-code-pro # Default monospace font in 3.32
+        source-sans-pro
+      ];
+
+      environment.systemPackages = with pkgs.gnome3; [
+        adwaita-icon-theme
+        gnome-backgrounds
+        gnome-bluetooth
+        gnome-control-center
+        gnome-getting-started-docs
+        gnome-shell
+        gnome-shell-extensions
+        gnome-themes-extra
+        gnome-user-docs
+        pkgs.glib # for gsettings
+        pkgs.gnome-menus
+        pkgs.gtk3.out # for gtk-launch
+        pkgs.hicolor-icon-theme
+        pkgs.shared-mime-info # for update-mime-database
+        pkgs.xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
+        vino
+      ];
+    })
+
+    (mkIf serviceCfg.core-utilities.enable {
+      environment.systemPackages = (with pkgs.gnome3; removePackagesByName [
+        baobab eog epiphany evince gucharmap nautilus totem yelp gnome-calculator
+        gnome-contacts gnome-font-viewer gnome-screenshot gnome-system-monitor simple-scan
+        gnome-terminal evolution file-roller gedit gnome-clocks gnome-music gnome-tweaks
+        pkgs.gnome-photos nautilus-sendto dconf-editor vinagre gnome-weather gnome-logs
+        gnome-maps gnome-characters gnome-calendar accerciser gnome-nettool gnome-packagekit
+        gnome-software gnome-power-manager gnome-todo pkgs.gnome-usage
+      ] config.environment.gnome3.excludePackages);
+
+      # Enable default programs
+      programs.evince.enable = mkDefault true;
+      programs.file-roller.enable = mkDefault true;
+      programs.gnome-disks.enable = mkDefault true;
+      programs.gnome-documents.enable = mkDefault true;
+      programs.gnome-terminal.enable = mkDefault true;
+      services.gnome3.seahorse.enable = mkDefault true;
+      services.gnome3.sushi.enable = mkDefault true;
+
+      # Let nautilus find extensions
+      # TODO: Create nautilus-with-extensions package
+      environment.variables.NAUTILUS_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-3.0";
+
+      # Override default mimeapps for nautilus
+      environment.variables.XDG_DATA_DIRS = [ "${mimeAppsList}/share" ];
+
+      environment.pathsToLink = [
+        "/share/nautilus-python/extensions"
+      ];
+    })
+
+    (mkIf serviceCfg.games.enable {
+      environment.systemPackages = (with pkgs.gnome3; removePackagesByName [
+        aisleriot atomix five-or-more four-in-a-row gnome-chess gnome-klotski
+        gnome-mahjongg gnome-mines gnome-nibbles gnome-robots gnome-sudoku
+        gnome-taquin gnome-tetravex hitori iagno lightsoff quadrapassel
+        swell-foop tali
+      ] config.environment.gnome3.excludePackages);
+    })
+  ];
 
 }
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 23a2dd45d49..2a0360b12cb 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -537,7 +537,7 @@ in
     };
 
     systemd.enableCgroupAccounting = mkOption {
-      default = false;
+      default = true;
       type = types.bool;
       description = ''
         Whether to enable cgroup accounting.
@@ -804,10 +804,10 @@ in
         [Manager]
         ${optionalString config.systemd.enableCgroupAccounting ''
           DefaultCPUAccounting=yes
+          DefaultBlockIOAccounting=yes
           DefaultIOAccounting=yes
           DefaultBlockIOAccounting=yes
-          DefaultMemoryAccounting=yes
-          DefaultTasksAccounting=yes
+          DefaultIPAccounting=yes
         ''}
         DefaultLimitCORE=infinity
         ${config.systemd.extraConfig}