diff options
| author | Grisha Shipunov | 2026-07-26 16:15:35 +0000 |
|---|---|---|
| committer | Grisha Shipunov | 2026-07-26 20:19:26 +0000 |
| commit | fa816e580c3bcc70f0b58d2991ed65d919fbc05e (patch) | |
| tree | e6ef36148c8488d81df4742fd24a5e93d2291a53 | |
| parent | 08d7de681a1cdd9d4e3eb1dff4a3bbf5af880a9d (diff) | |
cgit: init
| -rw-r--r-- | flake.nix | 1 | ||||
| -rw-r--r-- | hosts/cloud/proxy/git.nix | 13 | ||||
| -rw-r--r-- | microvms/cgit/cgit.nix | 203 | ||||
| -rw-r--r-- | microvms/cgit/default.nix | 24 | ||||
| -rw-r--r-- | modules/wg/proxy.nix | 8 |
5 files changed, 245 insertions, 4 deletions
@@ -57,6 +57,7 @@ "forgejo" "miniflux" "stream" + "cgit" ]; microvm-unstable-list = [ "auth" diff --git a/hosts/cloud/proxy/git.nix b/hosts/cloud/proxy/git.nix index 6b4a895..0a6a753 100644 --- a/hosts/cloud/proxy/git.nix +++ b/hosts/cloud/proxy/git.nix @@ -1,4 +1,9 @@ -{ ... }: +{ lib, ... }: +let + cgit = "10.89.88.19"; + cgit6 = "fd31:185d:722f::19"; + gitport = 8080; +in { # ssh config for forgejo # need ip forward for nat @@ -12,11 +17,11 @@ # git.oxapentane.com: port forward 22 to forgejo # TODO do a proper thing with ipv6 extraCommands = '' - iptables -t nat -I PREROUTING -p tcp --dport 22 -d 116.202.5.66 -j DNAT --to-destination 10.89.88.15:2222 + iptables -t nat -I PREROUTING -p tcp --dport 22 -d 116.202.5.66 -j DNAT --to-destination ${cgit}:22 iptables ! -o lo -t nat -A POSTROUTING -j MASQUERADE ''; extraStopCommands = '' - iptables -t nat -D PREROUTING -p tcp --dport 22 -d 116.202.5.66 -j DNAT --to-destination 10.89.88.15:2222 || true + iptables -t nat -D PREROUTING -p tcp --dport 22 -d 116.202.5.66 -j DNAT --to-destination ${cgit}:22 || true ''; }; # host sshd: only listen on oxapentane.com and mgmt vpn @@ -36,6 +41,6 @@ ]; services.caddy.virtualHosts."git.oxapentane.com".extraConfig = '' - respond "Temporary unavailable due to maintenance" 503 + reverse_proxy ${cgit}:${lib.toString gitport} ''; } diff --git a/microvms/cgit/cgit.nix b/microvms/cgit/cgit.nix new file mode 100644 index 0000000..09b1048 --- /dev/null +++ b/microvms/cgit/cgit.nix @@ -0,0 +1,203 @@ +{ pkgs, lib, ... }: +let + host = "git.oxapentane.com"; + gitHome = "/var/lib/git"; + cgitPort = 8080; + + defaultBranch = "main"; + + mkCreateRepoCommand = + { + command, + visibility, + }: + pkgs.writeShellApplication { + name = command; + + runtimeInputs = [ + pkgs.coreutils + pkgs.git + pkgs.gnugrep + ]; + + text = '' + set -eu + + if [ "$#" -ne 1 ]; then + printf 'usage: ${command} NAME\n' >&2 + exit 2 + fi + + name=$1 + + # Accept either "foo" or "foo.git". + case "$name" in + *.git) + name="''${name%.git}" + ;; + esac + + # Deliberately only allow a single path component. + # This excludes traversal, slashes, spaces and shell metacharacters. + if ! printf '%s\n' "$name" \ + | grep -Eq '^[A-Za-z0-9][A-Za-z0-9._-]*$' + then + printf '%s\n' \ + 'invalid repository name: use letters, digits, ".", "_" and "-"' \ + >&2 + exit 2 + fi + + base=${lib.escapeShellArg "${gitHome}/${visibility}"} + repo="$base/$name.git" + + umask 0027 + + # mkdir is the existence check: never silently reinitialize a repo. + if ! mkdir -- "$repo" 2>/dev/null; then + printf 'repository already exists or cannot be created: %s\n' \ + "$name.git" >&2 + exit 1 + fi + + if ! git init \ + --bare \ + --initial-branch=${lib.escapeShellArg defaultBranch} \ + "$repo" \ + >/dev/null + then + printf 'failed to initialize repository: %s\n' "$name.git" >&2 + exit 1 + fi + + # Avoid Git's default "Unnamed repository..." text appearing in cgit. + : > "$repo/description" + + # This is the only successful stdout output, making $() safe. + printf '%s\n' "git@${host}:${visibility}/$name.git" + ''; + }; + + createPrivate = mkCreateRepoCommand { + command = "create"; + visibility = "private"; + }; + + createPublic = mkCreateRepoCommand { + command = "create-pub"; + visibility = "public"; + }; + + noInteractiveLogin = pkgs.writeShellScript "no-interactive-login" '' + printf '%s\n' "Interactive shell access is disabled." >&2 + exit 128 + ''; + + restrictedGitShell = + (pkgs.writeShellApplication { + name = "restricted-git-shell"; + + text = '' + umask 0027 + exec ${pkgs.git}/bin/git-shell "$@" + ''; + }).overrideAttrs (old: { + passthru = (old.passthru or { }) // { + shellPath = "/bin/restricted-git-shell"; + }; + }); +in +{ + # public repos in cgit + services.cgit."${host}" = { + enable = true; + user = "cgit"; + group = "cgit"; + scanPath = "${gitHome}/public"; + gitHttpBackend = { + enable = true; + checkExportOkFiles = false; # /public is unconditionally public anyway... + }; + + settings = { + root-title = "0xa's compilable shitposts"; + root-desc = "Public directory of my finest spaghetti"; + + remove-suffix = true; + clone-url = + "https://${host}/$CGIT_REPO_URL.git " + + "git@${host}:public/$CGIT_REPO_URL.git"; + + enable-http-clone = false; + enable-filter-overrides = false; + enable-git-config = false; + enable-http-serving = false; + + max-blob-size = 2048; + noplainemail = true; + + snapshots = ""; + }; + + nginx = { + virtualHost = host; + location = "/"; + }; + }; + + # just bind to proxy interface, everything's handeled by caddy + services.nginx.virtualHosts.${host}.listen = [ + { + addr = "10.89.88.19"; + port = cgitPort; + } + ]; + + # private - bare repos behind separate user + users.groups.git = {}; + users.users.git = { + isSystemUser = true; + group = "git"; + home = gitHome; + createHome = false; + shell = restrictedGitShell; + hashedPassword = "!"; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAXrwZsBChUhVuF5gFEfj8GwQlnrqEttAytS5jVCfuE4 0xa@frituurpan" + ]; + }; + + # enable and cofigure ssh + services.openssh = { + enable = true; + extraConfig = '' + Match User git + AuthenticationMethods publickey + PasswordAuthentication no + KbdInteractiveAuthentication no + DisableForwarding yes + PermitTTY no + PermitUserRC no + ''; + }; + + # ensure directories and rights + systemd.tmpfiles.rules = [ + "d ${gitHome} 0711 git git -" + "d ${gitHome}/public 2750 git cgit -" + "d ${gitHome}/private 0711 git git -" + "d ${gitHome}/git-shell-commands 0700 git git -" + + + "L+ ${gitHome}/git-shell-commands/create - - - - ${createPrivate}/bin/create" + "L+ ${gitHome}/git-shell-commands/create-pub - - - - ${createPublic}/bin/create-pub" + "L+ ${gitHome}/git-shell-commands/no-interactive-login - - - - ${noInteractiveLogin}" + ]; + + # dubious ownership error + systemd.services."fcgiwrap-cgit-${host}".environment = { + GIT_CONFIG_COUNT = "1"; + GIT_CONFIG_KEY_0 = "safe.directory"; + GIT_CONFIG_VALUE_0 = "${gitHome}/public/*"; + }; +} diff --git a/microvms/cgit/default.nix b/microvms/cgit/default.nix new file mode 100644 index 0000000..f58b7c0 --- /dev/null +++ b/microvms/cgit/default.nix @@ -0,0 +1,24 @@ +{ config, ... }: +{ + imports = [ + ../lib + ./cgit.nix + ]; + + oxalab.vm.number = 9; + + networking.hostName = "cgit"; + system.stateVersion = "26.05"; + + sops.secrets = { + "wg/0xa-proxy" = { + owner = config.users.users.systemd-network.name; + }; + }; + + + microvm = { + mem = 1 * 1024; + vcpu = 2; + }; +} diff --git a/modules/wg/proxy.nix b/modules/wg/proxy.nix index 091f057..ada0a8e 100644 --- a/modules/wg/proxy.nix +++ b/modules/wg/proxy.nix @@ -71,6 +71,14 @@ publicKey = "RDxbOvd/1FSWqIp5v1++wPBcG1hScAT4mhIlMZdvxU4="; privateKeyFile = config.sops.secrets."wg/0xa-proxy".path; }; + "cgit" = { + address = [ + "10.89.88.19/24" + "fd31:185d:722f::19/48" + ]; + publicKey = "E9cs2Lq5hsBkz5UoUviJEf22pF0EpX6IYGm9L8D7QDc="; + privateKeyFile = config.sops.secrets."wg/0xa-proxy".path; + }; }; } ]; |
