diff options
Diffstat (limited to 'modules/server/cgit/default.nix')
-rw-r--r-- | modules/server/cgit/default.nix | 133 |
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"; + }; + }); + }; +} |