From dd6496f477f59636a516e702675288eaebef2ea2 Mon Sep 17 00:00:00 2001 From: flop Date: Sun, 5 Jul 2026 20:14:30 +0200 Subject: [PATCH] feat: add gitea --- flake.nix | 12 +- machines/status.domain.com/configuration.nix | 18 +-- modules/gitea.nix | 138 +++++++++++++++++++ 3 files changed, 153 insertions(+), 15 deletions(-) create mode 100644 modules/gitea.nix diff --git a/flake.nix b/flake.nix index 01da1df..6098082 100644 --- a/flake.nix +++ b/flake.nix @@ -61,14 +61,13 @@ "pad.${domain}" = { # TODO: not implemented (hidden from gatus until gatus_health is set) description = "HedgeDoc"; - ports = {"http" = 3000; "httpws" = 3001; }; + ports = {"http" = 3001; "httpws" = 3001; }; websockets = true; }; "git.${domain}" = { - # TODO: not implemented (hidden from gatus until gatus_health is set) - description = "HedgeDoc"; - ports = {"http" = 3001; "ssh" = 22; }; - websockets = true; + description = "Gitea"; + ports = { "http" = 3000; "ssh" = 22; }; + gatus_health = "/"; }; }; @@ -93,11 +92,12 @@ status.domain.com = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; specialArgs = baseArgs // { - domains = [ "pad.${domain}" "gitea.${domain}" ]; + domains = [ "pad.${domain}" "git.${domain}" ]; }; modules = [ ./machines/status.domain.com/configuration.nix ./machines/status.domain.com/hardware-configuration.nix + ./modules/gitea.nix ] ++ sharedModules; }; }; diff --git a/machines/status.domain.com/configuration.nix b/machines/status.domain.com/configuration.nix index ed1805d..e3ac073 100644 --- a/machines/status.domain.com/configuration.nix +++ b/machines/status.domain.com/configuration.nix @@ -28,15 +28,15 @@ bash ]; - # Central nginx subdomain mapping example (enable when ready): - # infra.nginx = { - # enable = true; - # vhosts."pad.${config.networking.domain}" = { - # description = "HedgeDoc"; - # internal_proxy = "http://localhost:3000"; - # websockets = true; - # }; - # }; + infra.gitea = { + enable = true; + hostname = "git.${config.networking.domain}"; + oidc = { + enable = true; + clientId = "gitea"; + clientSecretFile = "/etc/gitea-oidc-secret"; + }; + }; infra.autoUpdate = { enable = true; diff --git a/modules/gitea.nix b/modules/gitea.nix new file mode 100644 index 0000000..abf818e --- /dev/null +++ b/modules/gitea.nix @@ -0,0 +1,138 @@ +{ config, lib, pkgs, domain, vhosts ? { }, ... }: + +with lib; + +let + cfg = config.infra.gitea; + vhost = vhosts.${cfg.hostname} or { }; + httpPort = vhost.ports.http or 3000; + sshPort = vhost.ports.ssh or 2222; + + giteaBin = "${config.services.gitea.package}/bin/gitea"; + discoveryUrl = "${cfg.oidc.issuerUrl}/.well-known/openid-configuration"; +in { + options.infra.gitea = { + enable = mkEnableOption "Gitea with Keycloak OIDC"; + + hostname = mkOption { + type = types.str; + default = "git.${domain}"; + description = "Public hostname for Gitea"; + }; + + oidc = { + enable = mkOption { + type = types.bool; + default = true; + description = "Register Keycloak as an OIDC authentication source"; + }; + + name = mkOption { + type = types.str; + default = "Keycloak"; + description = "Display name for the OIDC auth source"; + }; + + clientId = mkOption { + type = types.str; + description = "Keycloak OIDC client id"; + }; + + clientSecretFile = mkOption { + type = types.path; + description = '' + Path to a file (readable by the gitea user) containing the + Keycloak OIDC client secret. + ''; + }; + + issuerUrl = mkOption { + type = types.str; + default = "https://auth.${domain}/realms/master"; + description = "Keycloak realm issuer URL"; + }; + }; + }; + + config = mkIf cfg.enable { + services.gitea = { + enable = true; + settings = { + server = { + DOMAIN = cfg.hostname; + ROOT_URL = "https://${cfg.hostname}/"; + PROTOCOL = "http"; + HTTP_ADDR = "127.0.0.1"; + HTTP_PORT = httpPort; + SSH_DOMAIN = cfg.hostname; + SSH_PORT = sshPort; + START_SSH_SERVER = true; + SSH_LISTEN_PORT = sshPort; + LANDING_PAGE = "explore"; + }; + service = { + DISABLE_REGISTRATION = false; + SHOW_REGISTRATION_BUTTON = false; + }; + openid = { + ENABLE_OPENID_SIGNIN = true; + ENABLE_OPENID_SIGNUP = true; + }; + oauth2_client = { + ENABLE_AUTO_REGISTRATION = true; + ACCOUNT_LINKING = "login"; + UPDATE_AVATAR = true; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ sshPort ]; + + systemd.services.gitea-oidc = mkIf cfg.oidc.enable { + description = "Register Keycloak OIDC authentication source in Gitea"; + after = [ "gitea.service" ]; + bindsTo = [ "gitea.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + User = "gitea"; + Group = "gitea"; + RemainAfterExit = true; + }; + environment = { + GITEA_CUSTOM = "/var/lib/gitea/custom"; + GITEA_WORK_DIR = "/var/lib/gitea"; + }; + script = '' + secret="$(cat ${cfg.oidc.clientSecretFile})" + + # Wait until Gitea has finished initialising its database + for i in $(seq 1 60); do + if ${giteaBin} admin auth list > /tmp/gitea-auth-list 2>/dev/null; then + break + fi + sleep 2 + done + + ${giteaBin} admin auth list > /tmp/gitea-auth-list || true + existing=$(grep -w '${cfg.oidc.name}' /tmp/gitea-auth-list | awk '{print $1}' | head -n1) + + if [ -n "$existing" ]; then + ${giteaBin} admin auth update-oauth --id "$existing" \ + --name '${cfg.oidc.name}' \ + --provider openidConnect \ + --key '${cfg.oidc.clientId}' \ + --secret "$secret" \ + --auto-discover-url '${discoveryUrl}' + else + ${giteaBin} admin auth add-oauth \ + --name '${cfg.oidc.name}' \ + --provider openidConnect \ + --key '${cfg.oidc.clientId}' \ + --secret "$secret" \ + --auto-discover-url '${discoveryUrl}' + fi + ''; + }; + }; +} \ No newline at end of file