about summary refs log tree commit diff
path: root/modules/server/cgit/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'modules/server/cgit/default.nix')
-rw-r--r--modules/server/cgit/default.nix133
1 files changed, 133 insertions, 0 deletions
diff --git a/modules/server/cgit/default.nix b/modules/server/cgit/default.nix
new file mode 100644
index 000000000000..aba0d1b54c5d
--- /dev/null
+++ b/modules/server/cgit/default.nix
@@ -0,0 +1,133 @@
+{ lib, pkgs, config, ... }:
+
+let
+  inherit (builtins) split;
+  inherit (lib) flip foldr groupBy head literalExpression mapAttrs
+    mapAttrs' mapAttrsToList mdDoc mkOption nameValuePair optionalAttrs types;
+
+  cfg = config.services.cgit-qyliss;
+
+  instancesByVhost = groupBy ({ value, ... }: value.vhost)
+    (mapAttrsToList nameValuePair cfg.instances);
+
+  vhostConfigs = mapAttrs (vhost: instances:
+    foldr (l: r: l // r) {} (map ({ name, value }: let
+      unslashedPath = head (split "/+$" value.path);
+      # We'll be dealing almost exclusively with paths ending in /,
+      # since otherwise Nginx likes to do simple prefix matching.
+      path = "${unslashedPath}/";
+    in {
+      locations = {
+        ${path} = {
+          alias = "${value.package}/cgit/";
+          tryFiles = "$uri @${name}-cgit";
+        };
+        "@${name}-cgit" = {
+          proxyPass = "http://unix:/run/cgit/${name}.sock";
+        };
+      } // optionalAttrs (unslashedPath != "") {
+        ${unslashedPath} = {
+          return = "301 ${path}";
+        };
+      };
+
+      extraConfig = ''
+        if ($http_user_agent = "my-tiny-bot") {
+          return 429;
+        }
+        if ($http_user_agent = "thesis-research-bot") {
+          return 429;
+        }
+      '';
+    }) instances)
+  ) instancesByVhost;
+in
+
+{
+  options.services.cgit-qyliss = {
+    instances = mkOption {
+      type = types.attrsOf (types.submodule {
+        options = {
+          vhost = mkOption {
+            type = types.str;
+            example = "spectrum-os.org";
+            description = mdDoc "Nginx vhost for the cgit";
+          };
+
+          path = mkOption {
+            type = types.strMatching "/(.*[^/])?";
+            default = "/";
+            example = "/git";
+            description = mdDoc ''
+              Path to be appended to all cgit URLs.
+
+              Leading slashes are mandatory; trailing slashes are forbidden.
+            '';
+          };
+
+          package = mkOption {
+            type = types.package;
+            default = pkgs.cgit;
+            defaultText = literalExpression "pkgs.cgit";
+            description = mdDoc "cgit package to use";
+          };
+
+          config = mkOption {
+            type = types.package;
+            description = mdDoc ''
+              Configuration file for cgit.  See
+              <citerefentry><refentrytitle>cgitrc</refentrytitle>
+              <manvolnum>5</manvolnum></citerefentry>.
+            '';
+          };
+        };
+      });
+      default = {};
+      description = mdDoc "List of cgit instances to run";
+    };
+  };
+
+  config = {
+    services.nginx.virtualHosts = vhostConfigs;
+
+    systemd.services = flip mapAttrs' cfg.instances (name: instance: {
+      name = "lighttpd-${name}@";
+      value = {
+        unitConfig.CollectMode = "inactive-or-failed";
+        serviceConfig.StandardInput = "socket";
+        serviceConfig.StandardOutput = "socket";
+        serviceConfig.StandardError = "journal";
+        serviceConfig.DynamicUser = true;
+        serviceConfig.Type = "oneshot";
+        serviceConfig.TimeoutSec = "30";
+        serviceConfig.ExecStart = "${lib.getExe pkgs.lighttpd} -1 -f ${pkgs.writeText "lighttpd-${name}.conf" ''
+          server.modules = ( "mod_alias", "mod_setenv", "mod_cgi" )
+
+          server.document-root = "/var/empty"
+
+          alias.url = (
+            "${if instance.path == "/" then "" else instance.path}" =>
+              "${instance.package}/cgit/cgit.cgi"
+          )
+
+          cgi.assign = (
+            "cgit.cgi" => "${instance.package}/cgit/cgit.cgi"
+          )
+
+          setenv.add-environment = (
+            "CGIT_CONFIG" => "${instance.config}"
+          )
+        ''}";
+      };
+    });
+
+    systemd.sockets = flip mapAttrs' cfg.instances (name: instance: {
+      name = "lighttpd-${name}";
+      value = {
+        wantedBy = [ "sockets.target" ];
+        socketConfig.ListenStream = "/run/cgit/${name}.sock";
+        socketConfig.Accept = "yes";
+      };
+    });
+  };
+}