diff options
Diffstat (limited to 'nixos/modules/services')
23 files changed, 597 insertions, 201 deletions
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix index 697732426cc..35fb49f709a 100644 --- a/nixos/modules/services/amqp/rabbitmq.nix +++ b/nixos/modules/services/amqp/rabbitmq.nix @@ -165,7 +165,10 @@ in { after = [ "network.target" "epmd.socket" ]; wants = [ "network.target" "epmd.socket" ]; - path = [ cfg.package pkgs.procps ]; + path = [ + cfg.package + pkgs.coreutils # mkdir/chown/chmod for preStart + ]; environment = { RABBITMQ_MNESIA_BASE = "${cfg.dataDir}/mnesia"; diff --git a/nixos/modules/services/cluster/kubernetes/pki.nix b/nixos/modules/services/cluster/kubernetes/pki.nix index 733479e24c9..4275563f1a3 100644 --- a/nixos/modules/services/cluster/kubernetes/pki.nix +++ b/nixos/modules/services/cluster/kubernetes/pki.nix @@ -20,6 +20,7 @@ let size = 2048; }; CN = top.masterAddress; + hosts = cfg.cfsslAPIExtraSANs; }); cfsslAPITokenBaseName = "apitoken.secret"; @@ -66,6 +67,15 @@ in type = bool; }; + cfsslAPIExtraSANs = mkOption { + description = '' + Extra x509 Subject Alternative Names to be added to the cfssl API webserver TLS cert. + ''; + default = []; + example = [ "subdomain.example.com" ]; + type = listOf str; + }; + genCfsslAPIToken = mkOption { description = '' Whether to automatically generate cfssl API-token secret, diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix index 32f361454bc..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; }; @@ -74,13 +74,12 @@ in ''; }; - meta-data = mkOption { - type = types.str; - default = ""; - example = "queue=default,docker=true,ruby2=true"; + tags = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { queue = "default"; docker = "true"; ruby2 ="true"; }; description = '' - Meta data for the agent. This is a comma-separated list of - <code>key=value</code> pairs. + Tags for the agent. ''; }; @@ -93,26 +92,20 @@ in ''; }; - openssh = - { privateKeyPath = mkOption { - type = types.path; - description = '' - Private agent key. + privateSshKeyPath = mkOption { + 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; - A run-time path to the key file, which is supposed to be provisioned - outside of Nix store. - ''; - }; - publicKeyPath = mkOption { - type = types.path; - description = '' - Public agent key. - - A run-time path to the key file, which is supposed to be provisioned - outside of Nix store. - ''; - }; - }; + description = '' + OpenSSH private key + + A run-time path to the key file, which is supposed to be provisioned + outside of Nix store. + ''; + }; hooks = mkHookOptions [ { name = "checkout"; @@ -181,18 +174,26 @@ in instead. ''; }; + + shell = mkOption { + type = types.str; + default = "${pkgs.bash}/bin/bash -e -c"; + description = '' + Command that buildkite-agent 3 will execute when it spawns a shell. + ''; + }; }; }; 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 ]; @@ -210,17 +211,18 @@ in ## don't end up in the Nix store. preStart = let 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" - cp -f "${toString cfg.openssh.publicKeyPath}" "${sshDir}/id_rsa.pub" - 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}" - meta-data="${cfg.meta-data}" + shell="${cfg.shell}" + tags="${tagStr}" build-path="${cfg.dataDir}/builds" hooks-path="${cfg.hooksPath}" ${cfg.extraConfig} @@ -228,11 +230,14 @@ in ''; serviceConfig = - { ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg"; + { ExecStart = "${cfg.package}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg"; User = "buildkite-agent"; RestartSec = 5; Restart = "on-failure"; TimeoutSec = 10; + # set a long timeout to give buildkite-agent a chance to finish current builds + TimeoutStopSec = "2 min"; + KillMode = "mixed"; }; }; @@ -246,8 +251,11 @@ in ]; }; imports = [ - (mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ]) - (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKey" ] [ "services" "buildkite-agent" "openssh" "privateKeyPath" ]) - (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "publicKey" ] [ "services" "buildkite-agent" "openssh" "publicKeyPath" ]) + (mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ]) + (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKey" ] [ "services" "buildkite-agent" "privateSshKeyPath" ]) + (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKeyPath" ] [ "services" "buildkite-agent" "privateSshKeyPath" ]) + (mkRemovedOptionModule [ "services" "buildkite-agent" "openssh" "publicKey" ] "SSH public keys aren't necessary to clone private repos.") + (mkRemovedOptionModule [ "services" "buildkite-agent" "openssh" "publicKeyPath" ] "SSH public keys aren't necessary to clone private repos.") + (mkRenamedOptionModule [ "services" "buildkite-agent" "meta-data"] [ "services" "buildkite-agent" "tags" ]) ]; } diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix index 30c5550f71c..8b56207590a 100644 --- a/nixos/modules/services/continuous-integration/hydra/default.nix +++ b/nixos/modules/services/continuous-integration/hydra/default.nix @@ -167,7 +167,7 @@ in buildMachinesFiles = mkOption { type = types.listOf types.path; - default = [ "/etc/nix/machines" ]; + default = optional (config.nix.buildMachines != []) "/etc/nix/machines"; example = [ "/etc/nix/machines" "/var/lib/hydra/provisioner/machines" ]; description = "List of files containing build machines."; }; @@ -333,7 +333,7 @@ in IN_SYSTEMD = "1"; # to get log severity levels }; serviceConfig = - { ExecStart = "@${cfg.package}/bin/hydra-queue-runner hydra-queue-runner -v --option build-use-substitutes ${boolToString cfg.useSubstitutes}"; + { ExecStart = "@${cfg.package}/bin/hydra-queue-runner hydra-queue-runner -v"; ExecStopPost = "${cfg.package}/bin/hydra-queue-runner --unlock"; User = "hydra-queue-runner"; Restart = "always"; 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/corerad.nix b/nixos/modules/services/networking/corerad.nix new file mode 100644 index 00000000000..1a2c4aec665 --- /dev/null +++ b/nixos/modules/services/networking/corerad.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.corerad; +in { + meta = { + maintainers = with maintainers; [ mdlayher ]; + }; + + options.services.corerad = { + enable = mkEnableOption "CoreRAD IPv6 NDP RA daemon"; + + configFile = mkOption { + type = types.path; + example = literalExample "\"\${pkgs.corerad}/etc/corerad/corerad.toml\""; + description = "Path to CoreRAD TOML configuration file."; + }; + + package = mkOption { + default = pkgs.corerad; + defaultText = literalExample "pkgs.corerad"; + type = types.package; + description = "CoreRAD package to use."; + }; + }; + + config = mkIf cfg.enable { + systemd.services.corerad = { + description = "CoreRAD IPv6 NDP RA daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + LimitNPROC = 512; + LimitNOFILE = 1048576; + CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW"; + AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW"; + NoNewPrivileges = true; + DynamicUser = true; + ExecStart = "${getBin cfg.package}/bin/corerad -c=${cfg.configFile}"; + Restart = "on-failure"; + }; + }; + }; +} 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/search/solr.nix b/nixos/modules/services/search/solr.nix index b2176225493..a8615a20a1c 100644 --- a/nixos/modules/services/search/solr.nix +++ b/nixos/modules/services/search/solr.nix @@ -13,19 +13,11 @@ in services.solr = { enable = mkEnableOption "Solr"; - # default to the 8.x series not forcing major version upgrade of those on the 7.x series package = mkOption { type = types.package; - default = if versionAtLeast config.system.stateVersion "19.09" - then pkgs.solr_8 - else pkgs.solr_7 - ; + default = pkgs.solr; defaultText = "pkgs.solr"; - description = '' - Which Solr package to use. This defaults to version 7.x if - <literal>system.stateVersion < 19.09</literal> and version 8.x - otherwise. - ''; + description = "Which Solr package to use."; }; port = mkOption { 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/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 4460f89ec5c..fd17e4b54f0 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -629,6 +629,9 @@ in environment.systemPackages = [httpd]; + # required for "apachectl configtest" + environment.etc."httpd/httpd.conf".source = httpdConf; + services.httpd.phpOptions = '' ; Needed for PHP's mail() function. diff --git a/nixos/modules/services/web-servers/nginx/gitweb.nix b/nixos/modules/services/web-servers/nginx/gitweb.nix index 272fd148018..f7fb07bb797 100644 --- a/nixos/modules/services/web-servers/nginx/gitweb.nix +++ b/nixos/modules/services/web-servers/nginx/gitweb.nix @@ -3,8 +3,9 @@ with lib; let - cfg = config.services.gitweb; - package = pkgs.gitweb.override (optionalAttrs cfg.gitwebTheme { + cfg = config.services.nginx.gitweb; + gitwebConfig = config.services.gitweb; + package = pkgs.gitweb.override (optionalAttrs gitwebConfig.gitwebTheme { gitwebTheme = true; }); @@ -17,13 +18,45 @@ in default = false; type = types.bool; description = '' - If true, enable gitweb in nginx. Access it at http://yourserver/gitweb + If true, enable gitweb in nginx. + ''; + }; + + location = mkOption { + default = "/gitweb"; + type = types.str; + description = '' + Location to serve gitweb on. + ''; + }; + + user = mkOption { + default = "nginx"; + type = types.str; + description = '' + Existing user that the CGI process will belong to. (Default almost surely will do.) + ''; + }; + + group = mkOption { + default = "nginx"; + type = types.str; + description = '' + Group that the CGI process will belong to. (Set to <literal>config.services.gitolite.group</literal> if you are using gitolite.) + ''; + }; + + virtualHost = mkOption { + default = "_"; + type = types.str; + description = '' + VirtualHost to serve gitweb on. Default is catch-all. ''; }; }; - config = mkIf config.services.nginx.gitweb.enable { + config = mkIf cfg.enable { systemd.services.gitweb = { description = "GitWeb service"; @@ -32,22 +65,22 @@ in FCGI_SOCKET_PATH = "/run/gitweb/gitweb.sock"; }; serviceConfig = { - User = "nginx"; - Group = "nginx"; + User = cfg.user; + Group = cfg.group; RuntimeDirectory = [ "gitweb" ]; }; wantedBy = [ "multi-user.target" ]; }; services.nginx = { - virtualHosts.default = { - locations."/gitweb/static/" = { + virtualHosts.${cfg.virtualHost} = { + locations."${cfg.location}/static/" = { alias = "${package}/static/"; }; - locations."/gitweb/" = { + locations."${cfg.location}/" = { extraConfig = '' include ${pkgs.nginx}/conf/fastcgi_params; - fastcgi_param GITWEB_CONFIG ${cfg.gitwebConfigFile}; + fastcgi_param GITWEB_CONFIG ${gitwebConfig.gitwebConfigFile}; fastcgi_pass unix:/run/gitweb/gitweb.sock; ''; }; 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/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index 6d9bd284bc7..ba9906072b3 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -144,7 +144,7 @@ in services.gnome3.core-shell.enable = true; services.gnome3.core-utilities.enable = mkDefault true; - services.xserver.displayManager.sessionPackages = [ pkgs.gnome3.gnome-session ]; + services.xserver.displayManager.sessionPackages = [ pkgs.gnome3.gnome-session.sessions ]; environment.extraInit = '' ${concatMapStrings (p: '' @@ -249,11 +249,17 @@ in services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true)); services.telepathy.enable = mkDefault true; - systemd.packages = with pkgs.gnome3; [ vino gnome-session ]; + systemd.packages = with pkgs.gnome3; [ + gnome-session + gnome-shell + vino + ]; services.avahi.enable = mkDefault true; - xdg.portal.extraPortals = [ pkgs.gnome3.gnome-shell ]; + xdg.portal.extraPortals = [ + pkgs.gnome3.gnome-shell + ]; services.geoclue2.enable = mkDefault true; services.geoclue2.enableDemoAgent = false; # GNOME has its own geoclue agent diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index 2f8c8cc9013..325023f4121 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -174,6 +174,10 @@ in "f /run/gdm/.config/gnome-initial-setup-done 0711 gdm gdm - yes" ]; + # Otherwise GDM will not be able to start correctly and display Wayland sessions + systemd.packages = with pkgs.gnome3; [ gnome-session gnome-shell ]; + environment.systemPackages = [ pkgs.gnome3.adwaita-icon-theme ]; + systemd.services.display-manager.wants = [ # Because sd_login_monitor_new requires /run/systemd/machines "systemd-machined.service" 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/services/x11/unclutter.nix b/nixos/modules/services/x11/unclutter.nix index 2478aaabb79..c0868604a68 100644 --- a/nixos/modules/services/x11/unclutter.nix +++ b/nixos/modules/services/x11/unclutter.nix @@ -32,7 +32,7 @@ in { default = 1; }; - threeshold = mkOption { + threshold = mkOption { description = "Minimum number of pixels considered cursor movement"; type = types.int; default = 1; @@ -72,6 +72,11 @@ in { }; }; + imports = [ + (mkRenamedOptionModule [ "services" "unclutter" "threeshold" ] + [ "services" "unclutter" "threshold" ]) + ]; + meta.maintainers = with lib.maintainers; [ rnhmjoj ]; } |