at 24.11-pre 8.0 kB view raw
1{ options, config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 runDir = "/run/searx"; 7 8 cfg = config.services.searx; 9 10 settingsFile = pkgs.writeText "settings.yml" 11 (builtins.toJSON cfg.settings); 12 13 limiterSettingsFile = (pkgs.formats.toml { }).generate "limiter.toml" cfg.limiterSettings; 14 15 generateConfig = '' 16 cd ${runDir} 17 18 # write NixOS settings as JSON 19 ( 20 umask 077 21 cp --no-preserve=mode ${settingsFile} settings.yml 22 ) 23 24 # substitute environment variables 25 env -0 | while IFS='=' read -r -d ''' n v; do 26 sed "s#@$n@#$v#g" -i settings.yml 27 done 28 ''; 29 30 settingType = with types; (oneOf 31 [ bool int float str 32 (listOf settingType) 33 (attrsOf settingType) 34 ]) // { description = "JSON value"; }; 35 36in 37 38{ 39 40 imports = [ 41 (mkRenamedOptionModule 42 [ "services" "searx" "configFile" ] 43 [ "services" "searx" "settingsFile" ]) 44 ]; 45 46 options = { 47 services.searx = { 48 enable = mkOption { 49 type = types.bool; 50 default = false; 51 relatedPackages = [ "searx" ]; 52 description = "Whether to enable Searx, the meta search engine."; 53 }; 54 55 environmentFile = mkOption { 56 type = types.nullOr types.path; 57 default = null; 58 description = '' 59 Environment file (see `systemd.exec(5)` 60 "EnvironmentFile=" section for the syntax) to define variables for 61 Searx. This option can be used to safely include secret keys into the 62 Searx configuration. 63 ''; 64 }; 65 66 redisCreateLocally = mkOption { 67 type = types.bool; 68 default = false; 69 description = '' 70 Configure a local Redis server for SearXNG. This is required if you 71 want to enable the rate limiter and bot protection of SearXNG. 72 ''; 73 }; 74 75 settings = mkOption { 76 type = types.attrsOf settingType; 77 default = { }; 78 example = literalExpression '' 79 { server.port = 8080; 80 server.bind_address = "0.0.0.0"; 81 server.secret_key = "@SEARX_SECRET_KEY@"; 82 83 engines = lib.singleton 84 { name = "wolframalpha"; 85 shortcut = "wa"; 86 api_key = "@WOLFRAM_API_KEY@"; 87 engine = "wolframalpha_api"; 88 }; 89 } 90 ''; 91 description = '' 92 Searx settings. These will be merged with (taking precedence over) 93 the default configuration. It's also possible to refer to 94 environment variables 95 (defined in [](#opt-services.searx.environmentFile)) 96 using the syntax `@VARIABLE_NAME@`. 97 98 ::: {.note} 99 For available settings, see the Searx 100 [docs](https://searx.github.io/searx/admin/settings.html). 101 ::: 102 ''; 103 }; 104 105 settingsFile = mkOption { 106 type = types.path; 107 default = "${runDir}/settings.yml"; 108 description = '' 109 The path of the Searx server settings.yml file. If no file is 110 specified, a default file is used (default config file has debug mode 111 enabled). Note: setting this options overrides 112 [](#opt-services.searx.settings). 113 114 ::: {.warning} 115 This file, along with any secret key it contains, will be copied 116 into the world-readable Nix store. 117 ::: 118 ''; 119 }; 120 121 limiterSettings = mkOption { 122 type = types.attrsOf settingType; 123 default = { }; 124 example = literalExpression '' 125 { 126 real_ip = { 127 x_for = 1; 128 ipv4_prefix = 32; 129 ipv6_prefix = 56; 130 } 131 botdetection.ip_lists.block_ip = [ 132 # "93.184.216.34" # example.org 133 ]; 134 } 135 ''; 136 description = '' 137 Limiter settings for SearXNG. 138 139 ::: {.note} 140 For available settings, see the SearXNG 141 [schema file](https://github.com/searxng/searxng/blob/master/searx/botdetection/limiter.toml). 142 ::: 143 ''; 144 }; 145 146 package = mkPackageOption pkgs "searxng" { }; 147 148 runInUwsgi = mkOption { 149 type = types.bool; 150 default = false; 151 description = '' 152 Whether to run searx in uWSGI as a "vassal", instead of using its 153 built-in HTTP server. This is the recommended mode for public or 154 large instances, but is unnecessary for LAN or local-only use. 155 156 ::: {.warning} 157 The built-in HTTP server logs all queries by default. 158 ::: 159 ''; 160 }; 161 162 uwsgiConfig = mkOption { 163 type = options.services.uwsgi.instance.type; 164 default = { http = ":8080"; }; 165 example = literalExpression '' 166 { 167 disable-logging = true; 168 http = ":8080"; # serve via HTTP... 169 socket = "/run/searx/searx.sock"; # ...or UNIX socket 170 chmod-socket = "660"; # allow the searx group to read/write to the socket 171 } 172 ''; 173 description = '' 174 Additional configuration of the uWSGI vassal running searx. It 175 should notably specify on which interfaces and ports the vassal 176 should listen. 177 ''; 178 }; 179 180 }; 181 182 }; 183 184 config = mkIf cfg.enable { 185 environment.systemPackages = [ cfg.package ]; 186 187 users.users.searx = 188 { description = "Searx daemon user"; 189 group = "searx"; 190 isSystemUser = true; 191 }; 192 193 users.groups.searx = { }; 194 195 systemd.services.searx-init = { 196 description = "Initialise Searx settings"; 197 serviceConfig = { 198 Type = "oneshot"; 199 RemainAfterExit = true; 200 User = "searx"; 201 RuntimeDirectory = "searx"; 202 RuntimeDirectoryMode = "750"; 203 } // optionalAttrs (cfg.environmentFile != null) 204 { EnvironmentFile = builtins.toPath cfg.environmentFile; }; 205 script = generateConfig; 206 }; 207 208 systemd.services.searx = mkIf (!cfg.runInUwsgi) { 209 description = "Searx server, the meta search engine."; 210 wantedBy = [ "network.target" "multi-user.target" ]; 211 requires = [ "searx-init.service" ]; 212 after = [ "searx-init.service" ]; 213 serviceConfig = { 214 User = "searx"; 215 Group = "searx"; 216 ExecStart = lib.getExe cfg.package; 217 } // optionalAttrs (cfg.environmentFile != null) 218 { EnvironmentFile = builtins.toPath cfg.environmentFile; }; 219 environment = { 220 SEARX_SETTINGS_PATH = cfg.settingsFile; 221 SEARXNG_SETTINGS_PATH = cfg.settingsFile; 222 }; 223 }; 224 225 systemd.services.uwsgi = mkIf cfg.runInUwsgi { 226 requires = [ "searx-init.service" ]; 227 after = [ "searx-init.service" ]; 228 }; 229 230 services.searx.settings = { 231 # merge NixOS settings with defaults settings.yml 232 use_default_settings = mkDefault true; 233 redis.url = lib.mkIf cfg.redisCreateLocally "unix://${config.services.redis.servers.searx.unixSocket}"; 234 }; 235 236 services.uwsgi = mkIf cfg.runInUwsgi { 237 enable = true; 238 plugins = [ "python3" ]; 239 240 instance.type = "emperor"; 241 instance.vassals.searx = { 242 type = "normal"; 243 strict = true; 244 immediate-uid = "searx"; 245 immediate-gid = "searx"; 246 lazy-apps = true; 247 enable-threads = true; 248 module = "searx.webapp"; 249 env = [ 250 # TODO: drop this as it is only required for searx 251 "SEARX_SETTINGS_PATH=${cfg.settingsFile}" 252 # searxng compatibility https://github.com/searxng/searxng/issues/1519 253 "SEARXNG_SETTINGS_PATH=${cfg.settingsFile}" 254 ]; 255 buffer-size = 32768; 256 pythonPackages = self: [ cfg.package ]; 257 } // cfg.uwsgiConfig; 258 }; 259 260 services.redis.servers.searx = lib.mkIf cfg.redisCreateLocally { 261 enable = true; 262 user = "searx"; 263 port = 0; 264 }; 265 266 environment.etc."searxng/limiter.toml" = lib.mkIf (cfg.limiterSettings != { }) { 267 source = limiterSettingsFile; 268 }; 269 }; 270 271 meta.maintainers = with maintainers; [ rnhmjoj _999eagle ]; 272}