diff options
Diffstat (limited to 'nixpkgs/nixos/modules/services')
20 files changed, 679 insertions, 82 deletions
diff --git a/nixpkgs/nixos/modules/services/backup/bacula.nix b/nixpkgs/nixos/modules/services/backup/bacula.nix index 0acbf1b3eabb..5a75a46e5259 100644 --- a/nixpkgs/nixos/modules/services/backup/bacula.nix +++ b/nixpkgs/nixos/modules/services/backup/bacula.nix @@ -15,16 +15,16 @@ let Client { Name = "${fd_cfg.name}"; FDPort = ${toString fd_cfg.port}; - WorkingDirectory = "${libDir}"; - Pid Directory = "/run"; + WorkingDirectory = ${libDir}; + Pid Directory = /run; ${fd_cfg.extraClientConfig} } ${concatStringsSep "\n" (mapAttrsToList (name: value: '' Director { Name = "${name}"; - Password = "${value.password}"; - Monitor = "${value.monitor}"; + Password = ${value.password}; + Monitor = ${value.monitor}; } '') fd_cfg.director)} @@ -41,8 +41,8 @@ let Storage { Name = "${sd_cfg.name}"; SDPort = ${toString sd_cfg.port}; - WorkingDirectory = "${libDir}"; - Pid Directory = "/run"; + WorkingDirectory = ${libDir}; + Pid Directory = /run; ${sd_cfg.extraStorageConfig} } @@ -50,8 +50,8 @@ let Autochanger { Name = "${name}"; Device = ${concatStringsSep ", " (map (a: "\"${a}\"") value.devices)}; - Changer Device = "${value.changerDevice}"; - Changer Command = "${value.changerCommand}"; + Changer Device = ${value.changerDevice}; + Changer Command = ${value.changerCommand}; ${value.extraAutochangerConfig} } '') sd_cfg.autochanger)} @@ -59,8 +59,8 @@ let ${concatStringsSep "\n" (mapAttrsToList (name: value: '' Device { Name = "${name}"; - Archive Device = "${value.archiveDevice}"; - Media Type = "${value.mediaType}"; + Archive Device = ${value.archiveDevice}; + Media Type = ${value.mediaType}; ${value.extraDeviceConfig} } '') sd_cfg.device)} @@ -68,8 +68,8 @@ let ${concatStringsSep "\n" (mapAttrsToList (name: value: '' Director { Name = "${name}"; - Password = "${value.password}"; - Monitor = "${value.monitor}"; + Password = ${value.password}; + Monitor = ${value.monitor}; } '') sd_cfg.director)} @@ -85,18 +85,18 @@ let '' Director { Name = "${dir_cfg.name}"; - Password = "${dir_cfg.password}"; + Password = ${dir_cfg.password}; DirPort = ${toString dir_cfg.port}; - Working Directory = "${libDir}"; - Pid Directory = "/run/"; - QueryFile = "${pkgs.bacula}/etc/query.sql"; + Working Directory = ${libDir}; + Pid Directory = /run/; + QueryFile = ${pkgs.bacula}/etc/query.sql; ${dir_cfg.extraDirectorConfig} } Catalog { - Name = "PostgreSQL"; - dbname = "bacula"; - user = "bacula"; + Name = PostgreSQL; + dbname = bacula; + user = bacula; } Messages { @@ -533,7 +533,7 @@ in { }; }; - services.postgresql.enable = dir_cfg.enable == true; + services.postgresql.enable = lib.mkIf dir_cfg.enable true; systemd.services.bacula-dir = mkIf dir_cfg.enable { after = [ "network.target" "postgresql.service" ]; diff --git a/nixpkgs/nixos/modules/services/databases/ferretdb.nix b/nixpkgs/nixos/modules/services/databases/ferretdb.nix index 45f822d64691..ab55e22bf214 100644 --- a/nixpkgs/nixos/modules/services/databases/ferretdb.nix +++ b/nixpkgs/nixos/modules/services/databases/ferretdb.nix @@ -30,7 +30,7 @@ in }; description = '' Additional configuration for FerretDB, see - <https://docs.ferretdb.io/flags/> + <https://docs.ferretdb.io/configuration/flags/> for supported values. ''; }; diff --git a/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix b/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix index d18e303891e4..4f680eabbe15 100644 --- a/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix +++ b/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix @@ -42,6 +42,6 @@ in services.dbus.packages = [ pkgs.gnome-browser-connector ]; - programs.firefox.wrapperConfig.enableGnomeExtensions = true; + programs.firefox.nativeMessagingHosts.packages = [ pkgs.gnome-browser-connector ]; }; } diff --git a/nixpkgs/nixos/modules/services/home-automation/esphome.nix b/nixpkgs/nixos/modules/services/home-automation/esphome.nix index d7dbb6f0b90e..080c8876382f 100644 --- a/nixpkgs/nixos/modules/services/home-automation/esphome.nix +++ b/nixpkgs/nixos/modules/services/home-automation/esphome.nix @@ -112,7 +112,7 @@ in ProtectKernelModules = true; ProtectKernelTunables = true; ProtectProc = "invisible"; - ProcSubset = "pid"; + ProcSubset = "all"; # Using "pid" breaks bwrap ProtectSystem = "strict"; #RemoveIPC = true; # Implied by DynamicUser RestrictAddressFamilies = [ diff --git a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix index 99bac86a8e9a..0e6fa65667af 100644 --- a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix @@ -12,7 +12,7 @@ let # We post-process the result to add support for YAML functions, like secrets or includes, see e.g. # https://www.home-assistant.io/docs/configuration/secrets/ filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) cfg.config or {}; - configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } '' + configFile = pkgs.runCommandLocal "configuration.yaml" { } '' cp ${format.generate "configuration.yaml" filteredConfig} $out sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out ''; diff --git a/nixpkgs/nixos/modules/services/matrix/synapse.nix b/nixpkgs/nixos/modules/services/matrix/synapse.nix index b38b35361cf0..12e27ef26ff3 100644 --- a/nixpkgs/nixos/modules/services/matrix/synapse.nix +++ b/nixpkgs/nixos/modules/services/matrix/synapse.nix @@ -60,7 +60,6 @@ let ++ lib.optional (cfg.settings ? oidc_providers) "oidc" ++ lib.optional (cfg.settings ? jwt_config) "jwt" ++ lib.optional (cfg.settings ? saml2_config) "saml2" - ++ lib.optional (cfg.settings ? opentracing) "opentracing" ++ lib.optional (cfg.settings ? redis) "redis" ++ lib.optional (cfg.settings ? sentry) "sentry" ++ lib.optional (cfg.settings ? user_directory) "user-search" @@ -334,7 +333,6 @@ in { [ "cache-memory" # Provide statistics about caching memory consumption "jwt" # JSON Web Token authentication - "opentracing" # End-to-end tracing support using Jaeger "oidc" # OpenID Connect authentication "postgres" # PostgreSQL database backend "redis" # Redis support for the replication stream between worker processes diff --git a/nixpkgs/nixos/modules/services/misc/ssm-agent.nix b/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix index d1f371c2bd61..0be79e759c31 100644 --- a/nixpkgs/nixos/modules/services/misc/ssm-agent.nix +++ b/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix @@ -2,7 +2,7 @@ with lib; let - cfg = config.services.ssm-agent; + cfg = config.services.amazon-ssm-agent; # The SSM agent doesn't pay attention to our /etc/os-release yet, and the lsb-release tool # in nixpkgs doesn't seem to work properly on NixOS, so let's just fake the two fields SSM @@ -16,19 +16,24 @@ let esac ''; in { - options.services.ssm-agent = { - enable = mkEnableOption (lib.mdDoc "AWS SSM agent"); + imports = [ + (mkRenamedOptionModule [ "services" "ssm-agent" "enable" ] [ "services" "amazon-ssm-agent" "enable" ]) + (mkRenamedOptionModule [ "services" "ssm-agent" "package" ] [ "services" "amazon-ssm-agent" "package" ]) + ]; + + options.services.amazon-ssm-agent = { + enable = mkEnableOption (lib.mdDoc "Amazon SSM agent"); package = mkOption { type = types.path; - description = lib.mdDoc "The SSM agent package to use"; - default = pkgs.ssm-agent.override { overrideEtc = false; }; - defaultText = literalExpression "pkgs.ssm-agent.override { overrideEtc = false; }"; + description = lib.mdDoc "The Amazon SSM agent package to use"; + default = pkgs.amazon-ssm-agent.override { overrideEtc = false; }; + defaultText = literalExpression "pkgs.amazon-ssm-agent.override { overrideEtc = false; }"; }; }; config = mkIf cfg.enable { - systemd.services.ssm-agent = { + systemd.services.amazon-ssm-agent = { inherit (cfg.package.meta) description; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; diff --git a/nixpkgs/nixos/modules/services/misc/forgejo.nix b/nixpkgs/nixos/modules/services/misc/forgejo.nix index b2920981efbd..90b5f16f4189 100644 --- a/nixpkgs/nixos/modules/services/misc/forgejo.nix +++ b/nixpkgs/nixos/modules/services/misc/forgejo.nix @@ -632,6 +632,8 @@ in }; }; + services.openssh.settings.AcceptEnv = mkIf (!cfg.settings.START_SSH_SERVER or false) "GIT_PROTOCOL"; + users.users = mkIf (cfg.user == "forgejo") { forgejo = { home = cfg.stateDir; diff --git a/nixpkgs/nixos/modules/services/monitoring/munin.nix b/nixpkgs/nixos/modules/services/monitoring/munin.nix index f37f2689927e..90a51181ac30 100644 --- a/nixpkgs/nixos/modules/services/monitoring/munin.nix +++ b/nixpkgs/nixos/modules/services/monitoring/munin.nix @@ -83,42 +83,47 @@ let # Copy one Munin plugin into the Nix store with a specific name. # This is suitable for use with plugins going directly into /etc/munin/plugins, # i.e. munin.extraPlugins. - internOnePlugin = name: path: + internOnePlugin = { name, path }: "cp -a '${path}' '${name}'"; # Copy an entire tree of Munin plugins into a single directory in the Nix - # store, with no renaming. - # This is suitable for use with munin-node-configure --suggest, i.e. - # munin.extraAutoPlugins. - internManyPlugins = name: path: + # store, with no renaming. The output is suitable for use with + # munin-node-configure --suggest, i.e. munin.extraAutoPlugins. + # Note that this flattens the input; this is intentional, as + # munin-node-configure won't recurse into subdirectories. + internManyPlugins = path: "find '${path}' -type f -perm /a+x -exec cp -a -t . '{}' '+'"; # Use the appropriate intern-fn to copy the plugins into the store and patch # them afterwards in an attempt to get them to run on NixOS. + # This is a bit hairy because we can't just fix shebangs; lots of munin plugins + # hardcode paths like /sbin/mount rather than trusting $PATH, so we have to + # look for and update those throughout the script. At the same time, if the + # plugin comes from a package that is already nixified, we don't want to + # rewrite paths like /nix/store/foo/sbin/mount. + # For now we make the simplifying assumption that no file will contain lines + # which mix store paths and FHS paths, and thus run our substitution only on + # lines which do not contain store paths. internAndFixPlugins = name: intern-fn: paths: pkgs.runCommand name {} '' mkdir -p "$out" cd "$out" - ${lib.concatStringsSep "\n" - (lib.attrsets.mapAttrsToList intern-fn paths)} + ${lib.concatStringsSep "\n" (map intern-fn paths)} chmod -R u+w . - find . -type f -exec sed -E -i ' - s,(/usr)?/s?bin/,/run/current-system/sw/bin/,g - ' '{}' '+' + ${pkgs.findutils}/bin/find . -type f -exec ${pkgs.gnused}/bin/sed -E -i " + \%''${NIX_STORE}/%! s,(/usr)?/s?bin/,/run/current-system/sw/bin/,g + " '{}' '+' ''; # TODO: write a derivation for munin-contrib, so that for contrib plugins # you can just refer to them by name rather than needing to include a copy # of munin-contrib in your nixos configuration. extraPluginDir = internAndFixPlugins "munin-extra-plugins.d" - internOnePlugin nodeCfg.extraPlugins; + internOnePlugin + (lib.attrsets.mapAttrsToList (k: v: { name = k; path = v; }) nodeCfg.extraPlugins); extraAutoPluginDir = internAndFixPlugins "munin-extra-auto-plugins.d" - internManyPlugins - (builtins.listToAttrs - (map - (path: { name = baseNameOf path; value = path; }) - nodeCfg.extraAutoPlugins)); + internManyPlugins nodeCfg.extraAutoPlugins; customStaticDir = pkgs.runCommand "munin-custom-static-data" {} '' cp -a "${pkgs.munin}/etc/opt/munin/static" "$out" diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix index ed33c72f644f..8b1cd47d0a40 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix @@ -15,8 +15,8 @@ in { type = types.listOf types.str; example = literalExpression '' [ - "/run/kea/kea-dhcp4.socket" - "/run/kea/kea-dhcp6.socket" + "/run/kea-dhcp4/kea-dhcp4.socket" + "/run/kea-dhcp6/kea-dhcp6.socket" ] ''; description = lib.mdDoc '' diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix index a73425b37da7..775848750803 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix @@ -8,9 +8,9 @@ in { port = 9433; extraOpts = { knotLibraryPath = mkOption { - type = types.str; - default = "${pkgs.knot-dns.out}/lib/libknot.so"; - defaultText = literalExpression ''"''${pkgs.knot-dns.out}/lib/libknot.so"''; + type = types.nullOr types.str; + default = null; + example = literalExpression ''"''${pkgs.knot-dns.out}/lib/libknot.so"''; description = lib.mdDoc '' Path to the library of `knot-dns`. ''; @@ -25,7 +25,7 @@ in { }; knotSocketTimeout = mkOption { - type = types.int; + type = types.ints.positive; default = 2000; description = lib.mdDoc '' Timeout in seconds. @@ -33,17 +33,22 @@ in { }; }; serviceOpts = { + path = with pkgs; [ + procps + ]; serviceConfig = { ExecStart = '' - ${pkgs.prometheus-knot-exporter}/bin/knot_exporter \ + ${pkgs.prometheus-knot-exporter}/bin/knot-exporter \ --web-listen-addr ${cfg.listenAddress} \ --web-listen-port ${toString cfg.port} \ - --knot-library-path ${cfg.knotLibraryPath} \ --knot-socket-path ${cfg.knotSocketPath} \ --knot-socket-timeout ${toString cfg.knotSocketTimeout} \ + ${lib.optionalString (cfg.knotLibraryPath != null) "--knot-library-path ${cfg.knotLibraryPath}"} \ ${concatStringsSep " \\\n " cfg.extraFlags} ''; - SupplementaryGroups = [ "knot" ]; + SupplementaryGroups = [ + "knot" + ]; RestrictAddressFamilies = [ # Need AF_UNIX to collect data "AF_UNIX" diff --git a/nixpkgs/nixos/modules/services/networking/fastnetmon-advanced.nix b/nixpkgs/nixos/modules/services/networking/fastnetmon-advanced.nix new file mode 100644 index 000000000000..26e8ad8b76d9 --- /dev/null +++ b/nixpkgs/nixos/modules/services/networking/fastnetmon-advanced.nix @@ -0,0 +1,222 @@ +{ config, lib, pkgs, ... }: + +let + # Background information: FastNetMon requires a MongoDB to start. This is because + # it uses MongoDB to store its configuration. That is, in a normal setup there is + # one collection with one document. + # To provide declarative configuration in our NixOS module, this database is + # completely emptied and replaced on each boot by the fastnetmon-setup service + # using the configuration backup functionality. + + cfg = config.services.fastnetmon-advanced; + settingsFormat = pkgs.formats.yaml { }; + + # obtain the default configs by starting up ferretdb and fcli in a derivation + default_configs = pkgs.runCommand "default-configs" { + nativeBuildInputs = [ + pkgs.ferretdb + pkgs.fastnetmon-advanced # for fcli + pkgs.proot + ]; + } '' + mkdir ferretdb fastnetmon $out + FERRETDB_TELEMETRY="disable" FERRETDB_HANDLER="sqlite" FERRETDB_STATE_DIR="$PWD/ferretdb" FERRETDB_SQLITE_URL="file:$PWD/ferretdb/" ferretdb & + + cat << EOF > fastnetmon/fastnetmon.conf + ${builtins.toJSON { + mongodb_username = ""; + }} + EOF + proot -b fastnetmon:/etc/fastnetmon -0 fcli create_configuration + proot -b fastnetmon:/etc/fastnetmon -0 fcli set bgp default + proot -b fastnetmon:/etc/fastnetmon -0 fcli export_configuration backup.tar + tar -C $out --no-same-owner -xvf backup.tar + ''; + + # merge the user configs into the default configs + config_tar = pkgs.runCommand "fastnetmon-config.tar" { + nativeBuildInputs = with pkgs; [ jq ]; + } '' + jq -s add ${default_configs}/main.json ${pkgs.writeText "main-add.json" (builtins.toJSON cfg.settings)} > main.json + mkdir hostgroup + ${lib.concatImapStringsSep "\n" (pos: hostgroup: '' + jq -s add ${default_configs}/hostgroup/0.json ${pkgs.writeText "hostgroup-${toString (pos - 1)}-add.json" (builtins.toJSON hostgroup)} > hostgroup/${toString (pos - 1)}.json + '') hostgroups} + mkdir bgp + ${lib.concatImapStringsSep "\n" (pos: bgp: '' + jq -s add ${default_configs}/bgp/0.json ${pkgs.writeText "bgp-${toString (pos - 1)}-add.json" (builtins.toJSON bgp)} > bgp/${toString (pos - 1)}.json + '') bgpPeers} + tar -cf $out main.json ${lib.concatImapStringsSep " " (pos: _: "hostgroup/${toString (pos - 1)}.json") hostgroups} ${lib.concatImapStringsSep " " (pos: _: "bgp/${toString (pos - 1)}.json") bgpPeers} + ''; + + hostgroups = lib.mapAttrsToList (name: hostgroup: { inherit name; } // hostgroup) cfg.hostgroups; + bgpPeers = lib.mapAttrsToList (name: bgpPeer: { inherit name; } // bgpPeer) cfg.bgpPeers; + +in { + options.services.fastnetmon-advanced = with lib; { + enable = mkEnableOption "the fastnetmon-advanced DDoS Protection daemon"; + + settings = mkOption { + description = '' + Extra configuration options to declaratively load into FastNetMon Advanced. + + See the [FastNetMon Advanced Configuration options reference](https://fastnetmon.com/docs-fnm-advanced/fastnetmon-advanced-configuration-options/) for more details. + ''; + type = settingsFormat.type; + default = {}; + example = literalExpression '' + { + networks_list = [ "192.0.2.0/24" ]; + gobgp = true; + gobgp_flow_spec_announces = true; + } + ''; + }; + hostgroups = mkOption { + description = "Hostgroups to declaratively load into FastNetMon Advanced"; + type = types.attrsOf settingsFormat.type; + default = {}; + }; + bgpPeers = mkOption { + description = "BGP Peers to declaratively load into FastNetMon Advanced"; + type = types.attrsOf settingsFormat.type; + default = {}; + }; + + enableAdvancedTrafficPersistence = mkOption { + description = "Store historical flow data in clickhouse"; + type = types.bool; + default = false; + }; + + traffic_db.settings = mkOption { + type = settingsFormat.type; + description = "Additional settings for /etc/fastnetmon/traffic_db.conf"; + }; + }; + + config = lib.mkMerge [ (lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + fastnetmon-advanced # for fcli + ]; + + environment.etc."fastnetmon/license.lic".source = "/var/lib/fastnetmon/license.lic"; + environment.etc."fastnetmon/gobgpd.conf".source = "/run/fastnetmon/gobgpd.conf"; + environment.etc."fastnetmon/fastnetmon.conf".source = pkgs.writeText "fastnetmon.conf" (builtins.toJSON { + mongodb_username = ""; + }); + + services.ferretdb.enable = true; + + systemd.services.fastnetmon-setup = { + wantedBy = [ "multi-user.target" ]; + after = [ "ferretdb.service" ]; + path = with pkgs; [ fastnetmon-advanced config.systemd.package ]; + script = '' + fcli create_configuration + fcli delete hostgroup global + fcli import_configuration ${config_tar} + systemctl --no-block try-restart fastnetmon + ''; + serviceConfig.Type = "oneshot"; + }; + + systemd.services.fastnetmon = { + wantedBy = [ "multi-user.target" ]; + after = [ "ferretdb.service" "fastnetmon-setup.service" "polkit.service" ]; + path = with pkgs; [ iproute2 ]; + unitConfig = { + # Disable logic which shuts service when we do too many restarts + # We do restarts from sudo fcli commit and it's expected that we may have many restarts + # Details: https://github.com/systemd/systemd/issues/2416 + StartLimitInterval = 0; + }; + serviceConfig = { + ExecStart = "${pkgs.fastnetmon-advanced}/bin/fastnetmon --log_to_console"; + + LimitNOFILE = 65535; + # Restart service when it fails due to any reasons, we need to keep processing traffic no matter what happened + Restart= "on-failure"; + RestartSec= "5s"; + + DynamicUser = true; + CacheDirectory = "fastnetmon"; + RuntimeDirectory = "fastnetmon"; # for gobgpd config + StateDirectory = "fastnetmon"; # for license file + }; + }; + + security.polkit.enable = true; + security.polkit.extraConfig = '' + polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.systemd1.manage-units" && + subject.isInGroup("fastnetmon")) { + if (action.lookup("unit") == "gobgp.service") { + var verb = action.lookup("verb"); + if (verb == "start" || verb == "stop" || verb == "restart") { + return polkit.Result.YES; + } + } + } + }); + ''; + + # We don't use the existing gobgp NixOS module and package, because the gobgp + # version might not be compatible with fastnetmon. Also, the service name + # _must_ be 'gobgp' and not 'gobgpd', so that fastnetmon can reload the config. + systemd.services.gobgp = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + description = "GoBGP Routing Daemon"; + unitConfig = { + ConditionPathExists = "/run/fastnetmon/gobgpd.conf"; + }; + serviceConfig = { + Type = "notify"; + ExecStartPre = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -f /run/fastnetmon/gobgpd.conf -d"; + SupplementaryGroups = [ "fastnetmon" ]; + ExecStart = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -f /run/fastnetmon/gobgpd.conf --sdnotify"; + ExecReload = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -r"; + DynamicUser = true; + AmbientCapabilities = "cap_net_bind_service"; + }; + }; + }) + + (lib.mkIf (cfg.enable && cfg.enableAdvancedTrafficPersistence) { + ## Advanced Traffic persistence + ## https://fastnetmon.com/docs-fnm-advanced/fastnetmon-advanced-traffic-persistency/ + + services.clickhouse.enable = true; + + services.fastnetmon-advanced.settings.traffic_db = true; + + services.fastnetmon-advanced.traffic_db.settings = { + clickhouse_batch_size = lib.mkDefault 1000; + clickhouse_batch_delay = lib.mkDefault 1; + traffic_db_host = lib.mkDefault "127.0.0.1"; + traffic_db_port = lib.mkDefault 8100; + clickhouse_host = lib.mkDefault "127.0.0.1"; + clickhouse_port = lib.mkDefault 9000; + clickhouse_user = lib.mkDefault "default"; + clickhouse_password = lib.mkDefault ""; + }; + environment.etc."fastnetmon/traffic_db.conf".text = builtins.toJSON cfg.traffic_db.settings; + + systemd.services.traffic_db = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + ExecStart = "${pkgs.fastnetmon-advanced}/bin/traffic_db"; + # Restart service when it fails due to any reasons, we need to keep processing traffic no matter what happened + Restart= "on-failure"; + RestartSec= "5s"; + + DynamicUser = true; + }; + }; + + }) ]; + + meta.maintainers = lib.teams.wdz.members; +} diff --git a/nixpkgs/nixos/modules/services/networking/kea.nix b/nixpkgs/nixos/modules/services/networking/kea.nix index 945f4113bd47..2f922a026a3a 100644 --- a/nixpkgs/nixos/modules/services/networking/kea.nix +++ b/nixpkgs/nixos/modules/services/networking/kea.nix @@ -254,7 +254,6 @@ in DynamicUser = true; User = "kea"; ConfigurationDirectory = "kea"; - RuntimeDirectory = "kea"; StateDirectory = "kea"; UMask = "0077"; }; @@ -289,8 +288,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea"; - KEA_LOCKFILE_DIR = "/run/kea"; + KEA_PIDFILE_DIR = "/run/kea-ctrl-agent"; + KEA_LOCKFILE_DIR = "/run/kea-ctrl-agent"; }; restartTriggers = [ @@ -301,6 +300,7 @@ in ExecStart = "${package}/bin/kea-ctrl-agent -c /etc/kea/ctrl-agent.conf ${lib.escapeShellArgs cfg.ctrl-agent.extraArgs}"; KillMode = "process"; Restart = "on-failure"; + RuntimeDirectory = "kea-ctrl-agent"; } // commonServiceConfig; }; }) @@ -329,8 +329,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea"; - KEA_LOCKFILE_DIR = "/run/kea"; + KEA_PIDFILE_DIR = "/run/kea-dhcp4"; + KEA_LOCKFILE_DIR = "/run/kea-dhcp4"; }; restartTriggers = [ @@ -348,6 +348,7 @@ in "CAP_NET_BIND_SERVICE" "CAP_NET_RAW" ]; + RuntimeDirectory = "kea-dhcp4"; } // commonServiceConfig; }; }) @@ -376,8 +377,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea"; - KEA_LOCKFILE_DIR = "/run/kea"; + KEA_PIDFILE_DIR = "/run/kea-dhcp6"; + KEA_LOCKFILE_DIR = "/run/kea-dhcp6"; }; restartTriggers = [ @@ -393,6 +394,7 @@ in CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + RuntimeDirectory = "kea-dhcp6"; } // commonServiceConfig; }; }) @@ -421,8 +423,8 @@ in ]; environment = { - KEA_PIDFILE_DIR = "/run/kea"; - KEA_LOCKFILE_DIR = "/run/kea"; + KEA_PIDFILE_DIR = "/run/kea-dhcp-ddns"; + KEA_LOCKFILE_DIR = "/run/kea-dhcp-ddns"; }; restartTriggers = [ @@ -437,6 +439,7 @@ in CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + RuntimeDirectory = "kea-dhcp-ddns"; } // commonServiceConfig; }; }) diff --git a/nixpkgs/nixos/modules/services/networking/rosenpass.nix b/nixpkgs/nixos/modules/services/networking/rosenpass.nix new file mode 100644 index 000000000000..d2a264b83d67 --- /dev/null +++ b/nixpkgs/nixos/modules/services/networking/rosenpass.nix @@ -0,0 +1,233 @@ +{ config +, lib +, options +, pkgs +, ... +}: +let + inherit (lib) + attrValues + concatLines + concatMap + filter + filterAttrsRecursive + flatten + getExe + mdDoc + mkIf + optional + ; + + cfg = config.services.rosenpass; + opt = options.services.rosenpass; + settingsFormat = pkgs.formats.toml { }; +in +{ + options.services.rosenpass = + let + inherit (lib) + literalExpression + mdDoc + mkOption + ; + inherit (lib.types) + enum + listOf + nullOr + path + str + submodule + ; + in + { + enable = lib.mkEnableOption (mdDoc "Rosenpass"); + + package = lib.mkPackageOption pkgs "rosenpass" { }; + + defaultDevice = mkOption { + type = nullOr str; + description = mdDoc "Name of the network interface to use for all peers by default."; + example = "wg0"; + }; + + settings = mkOption { + type = submodule { + freeformType = settingsFormat.type; + + options = { + public_key = mkOption { + type = path; + description = mdDoc "Path to a file containing the public key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`."; + }; + + secret_key = mkOption { + type = path; + description = mdDoc "Path to a file containing the secret key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`."; + }; + + listen = mkOption { + type = listOf str; + description = mdDoc "List of local endpoints to listen for connections."; + default = [ ]; + example = literalExpression "[ \"0.0.0.0:10000\" ]"; + }; + + verbosity = mkOption { + type = enum [ "Verbose" "Quiet" ]; + default = "Quiet"; + description = mdDoc "Verbosity of output produced by the service."; + }; + + peers = + let + peer = submodule { + freeformType = settingsFormat.type; + + options = { + public_key = mkOption { + type = path; + description = mdDoc "Path to a file containing the public key of the remote Rosenpass peer."; + }; + + endpoint = mkOption { + type = nullOr str; + default = null; + description = mdDoc "Endpoint of the remote Rosenpass peer."; + }; + + device = mkOption { + type = str; + default = cfg.defaultDevice; + defaultText = literalExpression "config.${opt.defaultDevice}"; + description = mdDoc "Name of the local WireGuard interface to use for this peer."; + }; + + peer = mkOption { + type = str; + description = mdDoc "WireGuard public key corresponding to the remote Rosenpass peer."; + }; + }; + }; + in + mkOption { + type = listOf peer; + description = mdDoc "List of peers to exchange keys with."; + default = [ ]; + }; + }; + }; + default = { }; + description = mdDoc "Configuration for Rosenpass, see <https://rosenpass.eu/> for further information."; + }; + }; + + config = mkIf cfg.enable { + warnings = + let + # NOTE: In the descriptions below, we tried to refer to e.g. + # options.systemd.network.netdevs."<name>".wireguardPeers.*.PublicKey + # directly, but don't know how to traverse "<name>" and * in this path. + extractions = [ + { + relevant = config.systemd.network.enable; + root = config.systemd.network.netdevs; + peer = (x: x.wireguardPeers); + key = (x: if x.wireguardPeerConfig ? PublicKey then x.wireguardPeerConfig.PublicKey else null); + description = mdDoc "${options.systemd.network.netdevs}.\"<name>\".wireguardPeers.*.wireguardPeerConfig.PublicKey"; + } + { + relevant = config.networking.wireguard.enable; + root = config.networking.wireguard.interfaces; + peer = (x: x.peers); + key = (x: x.publicKey); + description = mdDoc "${options.networking.wireguard.interfaces}.\"<name>\".peers.*.publicKey"; + } + rec { + relevant = root != { }; + root = config.networking.wg-quick.interfaces; + peer = (x: x.peers); + key = (x: x.publicKey); + description = mdDoc "${options.networking.wg-quick.interfaces}.\"<name>\".peers.*.publicKey"; + } + ]; + relevantExtractions = filter (x: x.relevant) extractions; + extract = { root, peer, key, ... }: + filter (x: x != null) (flatten (concatMap (x: (map key (peer x))) (attrValues root))); + configuredKeys = flatten (map extract relevantExtractions); + itemize = xs: concatLines (map (x: " - ${x}") xs); + descriptions = map (x: "`${x.description}`"); + missingKeys = filter (key: !builtins.elem key configuredKeys) (map (x: x.peer) cfg.settings.peers); + unusual = '' + While this may work as expected, e.g. you want to manually configure WireGuard, + such a scenario is unusual. Please double-check your configuration. + ''; + in + (optional (relevantExtractions != [ ] && missingKeys != [ ]) '' + You have configured Rosenpass peers with the WireGuard public keys: + ${itemize missingKeys} + But there is no corresponding active Wireguard peer configuration in any of: + ${itemize (descriptions relevantExtractions)} + ${unusual} + '') + ++ + optional (relevantExtractions == [ ]) '' + You have configured Rosenpass, but you have not configured Wireguard via any of: + ${itemize (descriptions extractions)} + ${unusual} + ''; + + environment.systemPackages = [ cfg.package pkgs.wireguard-tools ]; + + systemd.services.rosenpass = + let + filterNonNull = filterAttrsRecursive (_: v: v != null); + config = settingsFormat.generate "config.toml" ( + filterNonNull (cfg.settings + // + ( + let + credentialPath = id: "$CREDENTIALS_DIRECTORY/${id}"; + # NOTE: We would like to remove all `null` values inside `cfg.settings` + # recursively, since `settingsFormat.generate` cannot handle `null`. + # This would require to traverse both attribute sets and lists recursively. + # `filterAttrsRecursive` only recurses into attribute sets, but not + # into values that might contain other attribute sets (such as lists, + # e.g. `cfg.settings.peers`). Here, we just specialize on `cfg.settings.peers`, + # and this may break unexpectedly whenever a `null` value is contained + # in a list in `cfg.settings`, other than `cfg.settings.peers`. + peersWithoutNulls = map filterNonNull cfg.settings.peers; + in + { + secret_key = credentialPath "pqsk"; + public_key = credentialPath "pqpk"; + peers = peersWithoutNulls; + } + ) + ) + ); + in + rec { + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + path = [ cfg.package pkgs.wireguard-tools ]; + + serviceConfig = { + User = "rosenpass"; + Group = "rosenpass"; + RuntimeDirectory = "rosenpass"; + DynamicUser = true; + AmbientCapabilities = [ "CAP_NET_ADMIN" ]; + LoadCredential = [ + "pqsk:${cfg.settings.secret_key}" + "pqpk:${cfg.settings.public_key}" + ]; + }; + + # See <https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers> + environment.CONFIG = "%t/${serviceConfig.RuntimeDirectory}/config.toml"; + + preStart = "${getExe pkgs.envsubst} -i ${config} -o \"$CONFIG\""; + script = "rosenpass exchange-config \"$CONFIG\""; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/networking/syncthing.nix b/nixpkgs/nixos/modules/services/networking/syncthing.nix index c4b2d0e80f9b..bdcdaf056d03 100644 --- a/nixpkgs/nixos/modules/services/networking/syncthing.nix +++ b/nixpkgs/nixos/modules/services/networking/syncthing.nix @@ -10,6 +10,21 @@ let settingsFormat = pkgs.formats.json { }; cleanedConfig = converge (filterAttrsRecursive (_: v: v != null && v != {})) cfg.settings; + isUnixGui = (builtins.substring 0 1 cfg.guiAddress) == "/"; + + # Syncthing supports serving the GUI over Unix sockets. If that happens, the + # API is served over the Unix socket as well. This function returns the correct + # curl arguments for the address portion of the curl command for both network + # and Unix socket addresses. + curlAddressArgs = path: if isUnixGui + # if cfg.guiAddress is a unix socket, tell curl explicitly about it + # note that the dot in front of `${path}` is the hostname, which is + # required. + then "--unix-socket ${cfg.guiAddress} http://.${path}" + # no adjustements are needed if cfg.guiAddress is a network address + else "${cfg.guiAddress}${path}" + ; + devices = mapAttrsToList (_: device: device // { deviceID = device.id; }) cfg.settings.devices; @@ -62,14 +77,14 @@ let GET_IdAttrName = "deviceID"; override = cfg.overrideDevices; conf = devices; - baseAddress = "${cfg.guiAddress}/rest/config/devices"; + baseAddress = curlAddressArgs "/rest/config/devices"; }; dirs = { new_conf_IDs = map (v: v.id) folders; GET_IdAttrName = "id"; override = cfg.overrideFolders; conf = folders; - baseAddress = "${cfg.guiAddress}/rest/config/folders"; + baseAddress = curlAddressArgs "/rest/config/folders"; }; } [ # Now for each of these attributes, write the curl commands that are @@ -117,15 +132,14 @@ let builtins.attrNames (lib.subtractLists ["folders" "devices"]) (map (subOption: '' - curl -X PUT -d ${lib.escapeShellArg (builtins.toJSON cleanedConfig.${subOption})} \ - ${cfg.guiAddress}/rest/config/${subOption} + curl -X PUT -d ${lib.escapeShellArg (builtins.toJSON cleanedConfig.${subOption})} ${curlAddressArgs "/rest/config/${subOption}"} '')) (lib.concatStringsSep "\n") ]) + '' # restart Syncthing if required - if curl ${cfg.guiAddress}/rest/config/restart-required | + if curl ${curlAddressArgs "/rest/config/restart-required"} | ${jq} -e .requiresRestart > /dev/null; then - curl -X POST ${cfg.guiAddress}/rest/system/restart + curl -X POST ${curlAddressArgs "/rest/system/restart"} fi ''); in { @@ -651,7 +665,7 @@ in { ExecStart = '' ${cfg.package}/bin/syncthing \ -no-browser \ - -gui-address=${cfg.guiAddress} \ + -gui-address=${if isUnixGui then "unix://" else ""}${cfg.guiAddress} \ -home=${cfg.configDir} ${escapeShellArgs cfg.extraFlags} ''; MemoryDenyWriteExecute = true; diff --git a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix index 0595e9e6df23..90d9c68433cf 100644 --- a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix @@ -530,5 +530,5 @@ in { ''; }; - meta.maintainers = with lib.maintainers; [ globin rnhmjoj ]; + meta.maintainers = with lib.maintainers; [ rnhmjoj ]; } diff --git a/nixpkgs/nixos/modules/services/web-apps/akkoma.nix b/nixpkgs/nixos/modules/services/web-apps/akkoma.nix index 8d1775258612..eaee70c712bb 100644 --- a/nixpkgs/nixos/modules/services/web-apps/akkoma.nix +++ b/nixpkgs/nixos/modules/services/web-apps/akkoma.nix @@ -282,11 +282,11 @@ let AKKOMA_CONFIG_PATH="$RUNTIME_DIRECTORY/config.exs" \ ERL_EPMD_ADDRESS="${cfg.dist.address}" \ ERL_EPMD_PORT="${toString cfg.dist.epmdPort}" \ - ERL_FLAGS="${concatStringsSep " " [ - "-kernel inet_dist_use_interface '${erlAddr cfg.dist.address}'" - "-kernel inet_dist_listen_min ${toString cfg.dist.portMin}" - "-kernel inet_dist_listen_max ${toString cfg.dist.portMax}" - ]}" \ + ERL_FLAGS=${lib.escapeShellArg (lib.escapeShellArgs ([ + "-kernel" "inet_dist_use_interface" (erlAddr cfg.dist.address) + "-kernel" "inet_dist_listen_min" (toString cfg.dist.portMin) + "-kernel" "inet_dist_listen_max" (toString cfg.dist.portMax) + ] ++ cfg.dist.extraFlags))} \ RELEASE_COOKIE="$(<"$RUNTIME_DIRECTORY/cookie")" \ RELEASE_NAME="akkoma" \ exec "${cfg.package}/bin/$(basename "$0")" "$@" @@ -553,6 +553,13 @@ in { description = mdDoc "TCP port to bind Erlang Port Mapper Daemon to."; }; + extraFlags = mkOption { + type = with types; listOf str; + default = [ ]; + description = mdDoc "Extra flags to pass to Erlang"; + example = [ "+sbwt" "none" "+sbwtdcpu" "none" "+sbwtdio" "none" ]; + }; + portMin = mkOption { type = types.port; default = 49152; diff --git a/nixpkgs/nixos/modules/services/web-apps/lanraragi.nix b/nixpkgs/nixos/modules/services/web-apps/lanraragi.nix new file mode 100644 index 000000000000..f1ab8b8b4eb4 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-apps/lanraragi.nix @@ -0,0 +1,100 @@ +{ pkgs, lib, config, ... }: + +let + cfg = config.services.lanraragi; +in +{ + meta.maintainers = with lib.maintainers; [ tomasajt ]; + + options.services = { + lanraragi = { + enable = lib.mkEnableOption (lib.mdDoc "LANraragi"); + package = lib.mkPackageOptionMD pkgs "lanraragi" { }; + + port = lib.mkOption { + type = lib.types.port; + default = 3000; + description = lib.mdDoc "Port for LANraragi's web interface."; + }; + + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/lanraragi-password"; + description = lib.mdDoc '' + A file containing the password for LANraragi's admin interface. + ''; + }; + + redis = { + port = lib.mkOption { + type = lib.types.port; + default = 6379; + description = lib.mdDoc "Port for LANraragi's Redis server."; + }; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/redis-lanraragi-password"; + description = lib.mdDoc '' + A file containing the password for LANraragi's Redis server. + ''; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + services.redis.servers.lanraragi = { + enable = true; + port = cfg.redis.port; + requirePassFile = cfg.redis.passwordFile; + }; + + systemd.services.lanraragi = { + description = "LANraragi main service"; + after = [ "network.target" "redis-lanraragi.service" ]; + requires = [ "redis-lanraragi.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = lib.getExe cfg.package; + DynamicUser = true; + StateDirectory = "lanraragi"; + RuntimeDirectory = "lanraragi"; + LogsDirectory = "lanraragi"; + Restart = "on-failure"; + WorkingDirectory = "/var/lib/lanraragi"; + }; + environment = { + "LRR_TEMP_DIRECTORY" = "/run/lanraragi"; + "LRR_LOG_DIRECTORY" = "/var/log/lanraragi"; + "LRR_NETWORK" = "http://*:${toString cfg.port}"; + "HOME" = "/var/lib/lanraragi"; + }; + preStart = '' + REDIS_PASS=${lib.optionalString (cfg.redis.passwordFile != null) "$(head -n1 ${cfg.redis.passwordFile})"} + cat > lrr.conf <<EOF + { + redis_address => "127.0.0.1:${toString cfg.redis.port}", + redis_password => "$REDIS_PASS", + redis_database => "0", + redis_database_minion => "1", + redis_database_config => "2", + redis_database_search => "3", + } + EOF + '' + lib.optionalString (cfg.passwordFile != null) '' + PASS_HASH=$( + PASS=$(head -n1 ${cfg.passwordFile}) ${cfg.package.perlEnv}/bin/perl -I${cfg.package}/share/lanraragi/lib -e \ + 'use LANraragi::Controller::Config; print LANraragi::Controller::Config::make_password_hash($ENV{PASS})' \ + 2>/dev/null + ) + + ${lib.getExe pkgs.redis} -h 127.0.0.1 -p ${toString cfg.redis.port} -a "$REDIS_PASS" <<EOF + SELECT 2 + HSET LRR_CONFIG password $PASS_HASH + EOF + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix index c82f02ecefec..9db4c8e23025 100644 --- a/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -35,7 +35,10 @@ with lib; }; port = mkOption { type = types.nullOr port; - description = lib.mdDoc "Port number."; + description = lib.mdDoc '' + Port number to listen on. + If unset and the listen address is not a socket then nginx defaults to 80. + ''; default = null; }; ssl = mkOption { diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix index 285d0a181931..fc3287045710 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -379,7 +379,7 @@ in # Update the start menu for each user that is currently logged in system.userActivationScripts.plasmaSetup = activationScript; - programs.firefox.wrapperConfig.enablePlasmaBrowserIntegration = true; + programs.firefox.nativeMessagingHosts.packages = [ pkgs.plasma5Packages.plasma-browser-integration ]; }) (mkIf (cfg.kwinrc != {}) { |