{ options, config, lib, pkgs, ... }: with lib; let runDir = "/run/searx"; cfg = config.services.searx; generateConfig = '' cd ${runDir} # write NixOS settings as JSON cat <<'EOF' > settings.yml ${builtins.toJSON cfg.settings} EOF # substitute environment variables env -0 | while IFS='=' read -r -d ''' n v; do sed "s#@$n@#$v#g" -i settings.yml done # set strict permissions chmod 400 settings.yml ''; settingType = with types; (oneOf [ bool int float str (listOf settingType) (attrsOf settingType) ]) // { description = "JSON value"; }; in { imports = [ (mkRenamedOptionModule [ "services" "searx" "configFile" ] [ "services" "searx" "settingsFile" ]) ]; ###### interface options = { services.searx = { enable = mkOption { type = types.bool; default = false; relatedPackages = [ "searx" ]; description = "Whether to enable Searx, the meta search engine."; }; environmentFile = mkOption { type = types.nullOr types.path; default = null; description = '' Environment file (see systemd.exec(5) "EnvironmentFile=" section for the syntax) to define variables for Searx. This option can be used to safely include secret keys into the Searx configuration. ''; }; settings = mkOption { type = types.attrsOf settingType; default = { }; example = literalExample '' { server.port = 8080; server.bind_address = "0.0.0.0"; server.secret_key = "@SEARX_SECRET_KEY@"; engines = lib.singleton { name = "wolframalpha"; shortcut = "wa"; api_key = "@WOLFRAM_API_KEY@"; engine = "wolframalpha_api"; }; } ''; description = '' Searx settings. These will be merged with (taking precedence over) the default configuration. It's also possible to refer to environment variables (defined in ) using the syntax @VARIABLE_NAME@. For available settings, see the Searx docs. ''; }; settingsFile = mkOption { type = types.path; default = "${runDir}/settings.yml"; description = '' The path of the Searx server settings.yml file. If no file is specified, a default file is used (default config file has debug mode enabled). Note: setting this options overrides . This file, along with any secret key it contains, will be copied into the world-readable Nix store. ''; }; package = mkOption { type = types.package; default = pkgs.searx; defaultText = "pkgs.searx"; description = "searx package to use."; }; runInUwsgi = mkOption { type = types.bool; default = false; description = '' Whether to run searx in uWSGI as a "vassal", instead of using its built-in HTTP server. This is the recommended mode for public or large instances, but is unecessary for LAN or local-only use. The built-in HTTP server logs all queries by default. ''; }; uwsgiConfig = mkOption { type = options.services.uwsgi.instance.type; default = { http = ":8080"; }; example = literalExample '' { disable-logging = true; http = ":8080"; # serve via HTTP... socket = "/run/searx/searx.sock"; # ...or UNIX socket } ''; description = '' Additional configuration of the uWSGI vassal running searx. It should notably specify on which interfaces and ports the vassal should listen. ''; }; }; }; ###### implementation config = mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; users.users.searx = { description = "Searx daemon user"; group = "searx"; isSystemUser = true; }; users.groups.searx = { }; systemd.services.searx-init = { description = "Initialise Searx settings"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; User = "searx"; RuntimeDirectory = "searx"; RuntimeDirectoryMode = "750"; } // optionalAttrs (cfg.environmentFile != null) { EnvironmentFile = builtins.toPath cfg.environmentFile; }; script = generateConfig; }; systemd.services.searx = mkIf (!cfg.runInUwsgi) { description = "Searx server, the meta search engine."; wantedBy = [ "network.target" "multi-user.target" ]; requires = [ "searx-init.service" ]; after = [ "searx-init.service" ]; serviceConfig = { User = "searx"; Group = "searx"; ExecStart = "${cfg.package}/bin/searx-run"; } // optionalAttrs (cfg.environmentFile != null) { EnvironmentFile = builtins.toPath cfg.environmentFile; }; environment.SEARX_SETTINGS_PATH = cfg.settingsFile; }; systemd.services.uwsgi = mkIf (cfg.runInUwsgi) { requires = [ "searx-init.service" ]; after = [ "searx-init.service" ]; }; services.searx.settings = { # merge NixOS settings with defaults settings.yml use_default_settings = mkDefault true; }; services.uwsgi = mkIf (cfg.runInUwsgi) { enable = true; plugins = [ "python3" ]; instance.type = "emperor"; instance.vassals.searx = { type = "normal"; strict = true; immediate-uid = "searx"; immediate-gid = "searx"; lazy-apps = true; enable-threads = true; module = "searx.webapp"; env = [ "SEARX_SETTINGS_PATH=${cfg.settingsFile}" ]; pythonPackages = self: [ cfg.package ]; } // cfg.uwsgiConfig; }; }; meta.maintainers = with maintainers; [ rnhmjoj ]; }