diff --git a/services/searxng/default.nix b/services/searxng/default.nix new file mode 100644 index 0000000..9a28810 --- /dev/null +++ b/services/searxng/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./firewall.nix + ./nginx.nix + ./options.nix + ./service.nix + ]; +} diff --git a/services/searxng/firewall.nix b/services/searxng/firewall.nix new file mode 100644 index 0000000..df51a26 --- /dev/null +++ b/services/searxng/firewall.nix @@ -0,0 +1,39 @@ +{ + config, + lib, + ... +}: +let + inherit (config.machine.prosody) + enable + ; +in +with lib; +mkIf enable { + networking.firewall = { + allowedTCPPorts = [ + # HTTP filer + 80 + 443 + + # C2S + 5222 + 5223 + + # S2S + 5269 + 5270 + + # WebSockets / BOSH + 5280 + 5281 + ] + ++ concatLists ( + with config.services.prosody; + [ + httpPorts + httpsPorts + ] + ); + }; +} diff --git a/services/searxng/nginx.nix b/services/searxng/nginx.nix new file mode 100644 index 0000000..254b1e1 --- /dev/null +++ b/services/searxng/nginx.nix @@ -0,0 +1,57 @@ +{ + config, + lib, + ... +}: +let + inherit (config.machine.prosody) + enable + domain + ; + + localhost = "http://localhost:5280"; +in +with lib; +mkIf enable { + security.acme.certs."${domain}".extraDomainNames = [ + "conference.${domain}" + "upload.${domain}" + ]; + users.groups.acme.members = [ + "prosody" + ]; + services.nginx.virtualHosts = + with lib; + mkIf (domain != null) { + "${domain}".locations = { + "= /xmpp-websocket" = { + proxyPass = localhost; + proxyWebsockets = true; + }; + "= /http-bind".proxyPass = localhost; + "/push".proxyPass = localhost; + "= /.well-known/host-meta".proxyPass = localhost; + "= /.well-known/host-meta.json".proxyPass = localhost; + }; + "conference.${domain}" = { + http3 = true; + quic = true; + forceSSL = true; + kTLS = true; + useACMEHost = domain; + sslCertificate = "${config.security.acme.certs.${domain}.directory}/fullchain.pem"; + sslCertificateKey = "${config.security.acme.certs.${domain}.directory}/key.pem"; + locations."/".proxyPass = localhost; + }; + "upload.${domain}" = { + http3 = true; + quic = true; + forceSSL = true; + kTLS = true; + useACMEHost = domain; + sslCertificate = "${config.security.acme.certs.${domain}.directory}/fullchain.pem"; + sslCertificateKey = "${config.security.acme.certs.${domain}.directory}/key.pem"; + locations."/".proxyPass = localhost; + }; + }; +} diff --git a/services/searxng/options.nix b/services/searxng/options.nix new file mode 100644 index 0000000..264de26 --- /dev/null +++ b/services/searxng/options.nix @@ -0,0 +1,17 @@ +{ lib, ... }: +with lib; +{ + options.machine.searxng = { + enable = mkEnableOption "SearXNG"; + domain = mkOption { + type = types.nullOr types.str; + default = null; + description = "Domain name. If not set, will be disabled, and use the localhost."; + }; + port = mkOption { + type = types.port; + default = 4000; + description = "Listen port."; + }; + }; +} diff --git a/services/searxng/service.nix b/services/searxng/service.nix new file mode 100644 index 0000000..c5d6e4b --- /dev/null +++ b/services/searxng/service.nix @@ -0,0 +1,163 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.machine.searxng; +in +with lib; +mkIf enable { + services.searx = { + enable = true; + redisCreateLocally = true; + + # Rate limiting + limiterSettings = { + real_ip = { + x_for = 1; + ipv4_prefix = 32; + ipv6_prefix = 56; + }; + + botdetection = { + ip_limit = { + filter_link_local = true; + link_token = true; + }; + }; + }; + + settings = { + # Instance settings + general = { + debug = false; + instance_name = "SearXNG Instance"; + donation_url = false; + contact_url = false; + privacypolicy_url = false; + enable_metrics = false; + }; + + # User interface + ui = { + static_use_hash = true; + default_locale = "en"; + query_in_title = true; + infinite_scroll = false; + center_alignment = true; + default_theme = "simple"; + theme_args.simple_style = "auto"; + search_on_category_select = false; + hotkeys = "vim"; + }; + + # Search engine settings + search = { + safe_search = 2; + autocomplete_min = 2; + autocomplete = "duckduckgo"; + ban_time_on_fail = 5; + max_ban_time_on_fail = 120; + }; + + # Server configuration + server = { + base_url = cfg.domain != null ? "https://${cfg.domain}" : null; + port = cfg.port; + bind_address = "127.0.0.1"; + limiter = true; + public_instance = true; + image_proxy = true; + method = "GET"; + }; + + # Search engines + engines = lib.mapAttrsToList (name: value: { inherit name; } // value) { + "duckduckgo".disabled = true; + "brave".disabled = true; + "bing".disabled = false; + "mojeek".disabled = true; + "mwmbl".disabled = false; + "mwmbl".weight = 0.4; + "qwant".disabled = true; + "crowdview".disabled = false; + "crowdview".weight = 0.5; + "curlie".disabled = true; + "ddg definitions".disabled = false; + "ddg definitions".weight = 2; + "wikibooks".disabled = false; + "wikidata".disabled = false; + "wikiquote".disabled = true; + "wikisource".disabled = true; + "wikispecies".disabled = false; + "wikispecies".weight = 0.5; + "wikiversity".disabled = false; + "wikiversity".weight = 0.5; + "wikivoyage".disabled = false; + "wikivoyage".weight = 0.5; + "currency".disabled = true; + "dictzone".disabled = true; + "lingva".disabled = true; + "bing images".disabled = false; + "brave.images".disabled = true; + "duckduckgo images".disabled = true; + "google images".disabled = false; + "qwant images".disabled = true; + "1x".disabled = true; + "artic".disabled = false; + "deviantart".disabled = false; + "flickr".disabled = true; + "imgur".disabled = false; + "library of congress".disabled = false; + "material icons".disabled = true; + "material icons".weight = 0.2; + "openverse".disabled = false; + "pinterest".disabled = true; + "svgrepo".disabled = false; + "unsplash".disabled = false; + "wallhaven".disabled = false; + "wikicommons.images".disabled = false; + "yacy images".disabled = true; + "bing videos".disabled = false; + "brave.videos".disabled = true; + "duckduckgo videos".disabled = true; + "google videos".disabled = false; + "qwant videos".disabled = false; + "dailymotion".disabled = true; + "google play movies".disabled = true; + "invidious".disabled = true; + "odysee".disabled = true; + "peertube".disabled = false; + "piped".disabled = true; + "rumble".disabled = false; + "sepiasearch".disabled = false; + "vimeo".disabled = true; + "youtube".disabled = false; + "brave.news".disabled = true; + "google news".disabled = true; + }; + + # Outgoing requests + outgoing = { + request_timeout = 5.0; + max_request_timeout = 15.0; + pool_connections = 100; + pool_maxsize = 15; + enable_http2 = true; + }; + + # Enabled plugins + enabled_plugins = [ + "Basic Calculator" + "Hash plugin" + "Tor check plugin" + "Open Access DOI rewrite" + "Hostnames plugin" + "Unit converter plugin" + "Tracker URL remover" + ]; + }; + }; +}