From 0a5754541bb01e96021ca7ee74f1256a8ee68bc4 Mon Sep 17 00:00:00 2001 From: tdback Date: Sat, 21 Dec 2024 15:32:13 -0500 Subject: initial commit to self-hosted git --- modules/customs/cgit/default.nix | 134 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 modules/customs/cgit/default.nix (limited to 'modules/customs/cgit') diff --git a/modules/customs/cgit/default.nix b/modules/customs/cgit/default.nix new file mode 100644 index 0000000..19eac01 --- /dev/null +++ b/modules/customs/cgit/default.nix @@ -0,0 +1,134 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.cgit; + + mkCgitrc = cfg: + pkgs.writeText "cgitrc" (let + cgitConfig = { + css = "/cgit.css"; + logo = "/cgit.png"; + favicon = "/favicon.ico"; + about-filter = "${cfg.package}/lib/cgit/filters/about-formatting.sh"; + source-filter = "${cfg.package}/lib/cgit/filters/syntax-highlighting.py"; + enable-git-config = 1; + # Disable cgit's HTTP "dumb" protocol and use git itself to provide the + # HTTP "smart" protocol instead. + enable-http-clone = 0; + remove-suffix = 1; + clone-url = "https://${cfg.virtualHost}/$CGIT_REPO_URL.git"; + scan-path = cfg.scanPath; + }; + in + generators.toKeyValue { } (cfg.settings // cgitConfig) + ); + + mkCgitAssets = pkg: files: + builtins.map (f: '' + handle_path /${f} { + root * ${pkg}/cgit/${f} + file_server + } + '') files |> strings.concatStringsSep "\n"; +in +{ + disabledModules = [ "services/networking/cgit.nix" ]; + + options = { + services.cgit = { + enable = mkEnableOption "cgit"; + package = mkPackageOption pkgs "cgit" { }; + user = mkOption { + description = "User to run cgit service as"; + type = types.str; + default = "git"; + }; + group = mkOption { + description = "Group to run cgit service as"; + type = types.str; + default = "git"; + }; + scanPath = mkOption { + description = "A path which will be scanned for repositories"; + type = types.path; + default = "/var/lib/cgit"; + }; + virtualHost = mkOption { + description = "Virtual host to serve cgit on"; + type = types.str; + default = null; + }; + authorizedKeys = mkOption { + description = "SSH keys for authorized git users"; + type = types.listOf types.str; + default = [ ]; + }; + settings = mkOption { + description = "Additional cgit configuration. see cgitrc(5)"; + type = with types; let settingType = oneOf [ bool int str ]; in + attrsOf (oneOf [ + settingType + (listOf settingType) + ]); + default = { }; + }; + }; + }; + + config = mkIf cfg.enable { + programs.git = { + enable = true; + config.init.defaultBranch = "main"; + }; + + # Setup git user with git-shell for authenticated pushes. + users.users.${cfg.user} = { + isSystemUser = true; + home = cfg.scanPath; + group = cfg.group; + shell = "${pkgs.git}/bin/git-shell"; + openssh.authorizedKeys.keys = cfg.authorizedKeys; + }; + + users.groups.${cfg.group} = {}; + + # Harden git user to prevent SSH port forwarding to other servers. + services.openssh = { + enable = true; + settings.AllowUsers = [ cfg.user ]; + extraConfig = '' + Match user ${cfg.user} + AllowTCPForwarding no + AllowAgentForwarding no + PasswordAuthentication no + PermitTTY no + X11Forwarding no + ''; + }; + + # Configure fcgiwrap instance for caddy to properly serve cgi scripts. + # Reference: https://github.com/NixOS/nixpkgs/blob/nixos-24.11/nixos/modules/services/networking/cgit.nix + services.fcgiwrap.instances.cgit = { + process = { inherit (cfg) user group; }; + socket = { inherit (config.services.caddy) user group; }; + }; + + services.caddy.virtualHosts.${cfg.virtualHost}.extraConfig = + let + socket = config.services.fcgiwrap.instances.cgit.socket.address; + in '' + encode zstd gzip + + reverse_proxy unix/${socket} { + transport fastcgi { + env SCRIPT_FILENAME ${cfg.package}/cgit/cgit.cgi + env CGIT_CONFIG ${mkCgitrc cfg} + } + } + + ${mkCgitAssets cfg.package [ + "cgit.css" "cgit.png" "favicon.ico" "robots.txt" + ]} + ''; + }; +} -- cgit v1.2.3