summary refs log tree commit diff
diff options
context:
space:
mode:
authorrnhmjoj <rnhmjoj@inventati.org>2020-11-06 10:12:20 +0100
committerrnhmjoj <rnhmjoj@inventati.org>2021-01-11 08:41:15 +0100
commit623664e84f3d3db8c32d65df4cab1a174edff71e (patch)
treef88a70be4fef9b7eb35377aec6d48a0d63d610ed
parent92d55d57ebb3a186ea23b66f3587a36bee662785 (diff)
downloadnixpkgs-623664e84f3d3db8c32d65df4cab1a174edff71e.tar
nixpkgs-623664e84f3d3db8c32d65df4cab1a174edff71e.tar.gz
nixpkgs-623664e84f3d3db8c32d65df4cab1a174edff71e.tar.bz2
nixpkgs-623664e84f3d3db8c32d65df4cab1a174edff71e.tar.lz
nixpkgs-623664e84f3d3db8c32d65df4cab1a174edff71e.tar.xz
nixpkgs-623664e84f3d3db8c32d65df4cab1a174edff71e.tar.zst
nixpkgs-623664e84f3d3db8c32d65df4cab1a174edff71e.zip
nixos/searx: add support for running in uWSGI
-rw-r--r--nixos/modules/services/networking/searx.nix102
-rw-r--r--nixos/tests/searx.nix75
2 files changed, 151 insertions, 26 deletions
diff --git a/nixos/modules/services/networking/searx.nix b/nixos/modules/services/networking/searx.nix
index 5b0836e6751..85696beeba4 100644
--- a/nixos/modules/services/networking/searx.nix
+++ b/nixos/modules/services/networking/searx.nix
@@ -3,7 +3,7 @@
 with lib;
 
 let
-  dataDir = "/var/lib/searx";
+  runDir = "/run/searx";
   cfg = config.services.searx;
 
   hasEngines =
@@ -13,7 +13,7 @@ let
   # Script to merge NixOS settings with
   # the default settings.yml bundled in searx.
   mergeConfig = ''
-    cd ${dataDir}
+    cd ${runDir}
     # find the default settings.yml
     default=$(find '${cfg.package}/' -name settings.yml)
 
@@ -46,6 +46,9 @@ let
     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
   '';
 
 in
@@ -114,7 +117,7 @@ in
 
       settingsFile = mkOption {
         type = types.path;
-        default = "${dataDir}/settings.yml";
+        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
@@ -136,6 +139,38 @@ in
         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.
+          <warning>
+            <para>
+              The built-in HTTP server logs all queries by default.
+            </para>
+          </warning>
+        '';
+      };
+
+      uwsgiConfig = mkOption {
+        type = types.attrs;
+        default = { http = ":8080"; };
+        example = lib.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.
+        '';
+      };
+
     };
 
   };
@@ -143,23 +178,66 @@ in
 
   ###### implementation
 
-  config = mkIf config.services.searx.enable {
-    systemd.services.searx = {
-      description = "Searx server, the meta search engine.";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
+  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";
-        DynamicUser = true;
+        RuntimeDirectory = "searx";
+        RuntimeDirectoryMode = "750";
+      } // optionalAttrs (cfg.environmentFile != null)
+        { EnvironmentFile = builtins.toPath cfg.environmentFile; };
+      script = mergeConfig;
+    };
+
+    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";
-        StateDirectory = "searx";
       } // optionalAttrs (cfg.environmentFile != null)
         { EnvironmentFile = builtins.toPath cfg.environmentFile; };
       environment.SEARX_SETTINGS_PATH = cfg.settingsFile;
-      preStart = mergeConfig;
     };
 
-    environment.systemPackages = [ cfg.package ];
+    systemd.services.uwsgi = mkIf (cfg.runInUwsgi)
+      { requires = [ "searx-init.service" ];
+        after = [ "searx-init.service" ];
+      };
+
+    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;
+    };
 
   };
 
diff --git a/nixos/tests/searx.nix b/nixos/tests/searx.nix
index 128c2a9381b..e5fee3466bf 100644
--- a/nixos/tests/searx.nix
+++ b/nixos/tests/searx.nix
@@ -6,7 +6,8 @@ import ./make-test-python.nix ({ pkgs, ...} :
     maintainers = [ rnhmjoj ];
   };
 
-  machine = { ... }: {
+  # basic setup: searx running the built-in webserver
+  nodes.base = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
 
     services.searx = {
@@ -17,11 +18,10 @@ import ./make-test-python.nix ({ pkgs, ...} :
       '';
 
       settings.server =
-        { port = 8080;
+        { port = "8080";
           bind_address = "0.0.0.0";
           secret_key = "@SEARX_SECRET_KEY@";
         };
-
       settings.engines = {
         wolframalpha =
           { api_key = "@WOLFRAM_API_KEY@";
@@ -29,34 +29,81 @@ import ./make-test-python.nix ({ pkgs, ...} :
           };
         startpage.shortcut = "start";
       };
+    };
+
+  };
+
+  # fancy setup: run in uWSGI and use nginx as proxy
+  nodes.fancy = { ... }: {
+    imports = [ ../modules/profiles/minimal.nix ];
+
+    services.searx = {
+      enable = true;
+      runInUwsgi = true;
+      uwsgiConfig = {
+        # serve using the uwsgi protocol
+        socket = "/run/searx/uwsgi.sock";
+        chmod-socket = "660";
+
+        # use /searx as url "mountpoint"
+        mount = "/searx=searx.webapp:application";
+        module = "";
+        manage-script-name = true;
+      };
+    };
 
+    # use nginx as reverse proxy
+    services.nginx.enable = true;
+    services.nginx.virtualHosts.localhost = {
+      locations."/searx".extraConfig =
+        ''
+          include ${pkgs.nginx}/conf/uwsgi_params;
+          uwsgi_pass unix:/run/searx/uwsgi.sock;
+        '';
+      locations."/searx/static/".alias = "${pkgs.searx}/share/static/";
     };
+
+    # allow nginx access to the searx socket
+    users.users.nginx.extraGroups = [ "searx" ];
+
   };
 
   testScript =
     ''
-      start_all()
+      base.start()
 
       with subtest("Settings have been merged"):
-          machine.wait_for_unit("searx")
-          output = machine.succeed(
-              "${pkgs.yq-go}/bin/yq r /var/lib/searx/settings.yml"
+          base.wait_for_unit("searx-init")
+          base.wait_for_file("/run/searx/settings.yml")
+          output = base.succeed(
+              "${pkgs.yq-go}/bin/yq r /run/searx/settings.yml"
               " 'engines.(name==startpage).shortcut'"
           ).strip()
           assert output == "start", "Settings not merged"
 
       with subtest("Environment variables have been substituted"):
-          machine.succeed("grep -q somesecret /var/lib/searx/settings.yml")
-          machine.succeed("grep -q sometoken /var/lib/searx/settings.yml")
+          base.succeed("grep -q somesecret /run/searx/settings.yml")
+          base.succeed("grep -q sometoken /run/searx/settings.yml")
+          base.copy_from_vm("/run/searx/settings.yml")
 
-      with subtest("Searx service is running"):
-          machine.wait_for_open_port(8080)
-          machine.succeed(
+      with subtest("Basic setup is working"):
+          base.wait_for_open_port(8080)
+          base.wait_for_unit("searx")
+          base.succeed(
               "${pkgs.curl}/bin/curl --fail http://localhost:8080"
           )
+          base.shutdown()
 
-      machine.copy_from_vm("/var/lib/searx/settings.yml")
-      machine.shutdown()
+      with subtest("Nginx+uWSGI setup is working"):
+          fancy.start()
+          fancy.wait_for_open_port(80)
+          fancy.wait_for_unit("uwsgi")
+          fancy.succeed(
+              "${pkgs.curl}/bin/curl --fail http://localhost/searx >&2"
+          )
+          fancy.succeed(
+              "${pkgs.curl}/bin/curl --fail http://localhost/searx/static/js/bootstrap.min.js >&2"
+          )
     '';
 })