Commit 119b7dc

HPCesia <me@hpcesia.com>
2026-06-30 11:32:57
Add Forgejo service
1 parent 5445ec8
Changed files (2)
modules
services
modules/services/forgejo/runner.nix
@@ -0,0 +1,124 @@
+{
+  den,
+  lib,
+  inputs,
+  ...
+}: {
+  den.aspects.services.forgejo.runner = {
+    includes = [den.aspects.services.podman];
+    settings = {
+      instances = lib.mkOption {
+        type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
+          options = {
+            name = lib.mkoption {
+              type = lib.types.str;
+              default = name;
+            };
+            servers = lib.mkOption {
+              type = lib.attrsOf (lib.types.submodule {
+                options = {
+                  url = lib.mkOption {
+                    type = lib.types.str;
+                  };
+                  uuid = lib.mkOption {
+                    type = lib.types.str;
+                  };
+                  tokenFileAged = lib.mkOption {
+                    type = lib.types.path;
+                  };
+                  labels = lib.mkOption {
+                    type = lib.types.listOf lib.types.str;
+                    description = "Extra labels used for this server.";
+                    default = [];
+                  };
+                };
+              });
+              default = {};
+            };
+            labels = lib.mkOption {
+              type = lib.types.listOf lib.types.str;
+              default = [];
+            };
+            extraEnvironments = lib.mkOption {
+              type = lib.types.attrsOf lib.types.str;
+              default = {};
+            };
+            extraSettings = lib.mkOption {
+              type = lib.types.attrsOf lib.types.anything;
+              default = {};
+            };
+          };
+        }));
+        default = {};
+      };
+    };
+
+    nixos = {
+      host,
+      config,
+      ...
+    }: let
+      cfg = host.settings.services.forgejo.runner;
+      mkServerTokenSecretName = instance: server: "forgejo-runner-${instance}-${server}-token";
+    in {
+      imports = [inputs.nur-hpcesia.nixosModules.forgejo-runner];
+
+      # If you would like to use docker runners in combination with cache actions,
+      # be sure to add docker bridge interfaces “br-*” to the firewalls’ trusted interfaces.
+      # See https://forgejo.org/docs/next/admin/actions/runner-installation/#nixos
+      networking.firewall.trustedInterfaces =
+        if (config.networking.nftables.enable)
+        then ["br-*"]
+        else ["br-+"];
+
+      services.forgejo-runner.instances =
+        lib.mapAttrs (instance: instanceCfg: {
+          enable = true;
+          inherit (instanceCfg) name labels;
+
+          servers =
+            lib.mapAttrs (server: serverCfg: {
+              inherit (serverCfg) url uuid;
+              tokenFile = "$CREDENTIALS_DIRECTORY/${server}-token";
+              labels = lib.unique (instanceCfg.labels ++ (serverCfg.labels));
+            })
+            instanceCfg.servers;
+
+          settings = lib.mkMerge [
+            {
+              cache = {
+                enabled = true;
+                host = "172.17.0.1";
+              };
+              container = {
+                enable_ipv6 = true;
+                options = "--cap-add sys_admin --cap-add mknod --device /dev/fuse";
+              };
+            }
+            instanceCfg.extraSettings
+          ];
+        })
+        cfg.instances;
+
+      systemd.services = lib.mapAttrs' (instance: instanceCfg:
+        lib.nameValuePair "forgejo-runner-${instance}" {
+          serviceConfig.LoadCredential =
+            lib.map
+            (server: "${server}-token:${config.vaultix.secrets.${mkServerTokenSecretName instance server}.path}")
+            (lib.attrNames instanceCfg.servers);
+        })
+      cfg.instances;
+
+      vaultix.secrets = lib.mergeAttrsList (
+        lib.mapAttrsToList (instance: instanceCfg:
+          lib.mapAttrs' (
+            server: serverCfg:
+              lib.nameValuePair (mkServerTokenSecretName instance server) {
+                file = serverCfg.tokenFileAged;
+              }
+          ))
+        cfg.instances
+      );
+    };
+  };
+}
modules/services/forgejo.nix
@@ -0,0 +1,126 @@
+{lib, ...}: {
+  den.aspects.services.forgejo = {
+    settings = {
+      external = lib.mkEnableOption "Whether to expose Forgejo service to public internet";
+      domain = lib.mkOption {
+        type = lib.types.str;
+      };
+      address = lib.mkOption {
+        type = lib.types.str;
+        default = "127.0.0.1";
+      };
+      port = lib.mkOption {
+        type = lib.types.port;
+        default = 3155;
+      };
+    };
+
+    reverseProxy = {host, ...}: let
+      cfg = host.settings.services.forgejo;
+    in
+      lib.optionalAttrs (cfg.external) {
+        ${cfg.domain} = {
+          port = cfg.port;
+        };
+      };
+
+    reverseProxyTailscale = {host, ...}: let
+      cfg = host.settings.services.forgejo;
+    in
+      lib.optionalAttrs (!cfg.external) {
+        ${cfg.domain} = {
+          port = cfg.port;
+        };
+      };
+
+    persist = {config, ...}: {
+      directories = [
+        {
+          directory = config.services.forgejo.stateDir;
+          inherit (config.services.forgejo) user group;
+          mode = "0700";
+        }
+      ];
+    };
+
+    nixos = {
+      host,
+      config,
+      ...
+    }: let
+      hostCfg = host.settings.services.forgejo;
+    in {
+      services.forgejo = {
+        enable = true;
+        user = "git";
+        group = "forgejo";
+        database = {
+          type = "sqlite3";
+        };
+        lfs.enable = true;
+        settings = {
+          DEFAULT = {
+            APP_NAME = "Gate Of Infinity";
+            APP_SLOGAN = "Walk toward the tomorrow where the stars gleam.";
+            APP_DISPLAY_NAME_FORMAT = "{APP_NAME}";
+          };
+          server = {
+            DOMAIN = hostCfg.domain;
+            HTTP_ADDR = hostCfg.address;
+            HTTP_PORT = hostCfg.port;
+            SSH_PORT =
+              if hostCfg.external
+              then host.settings.core.openssh.access.port
+              else 22;
+            PROTOCOL = "http";
+            ROOT_URL = "http${lib.optionalString hostCfg.external "s"}://${hostCfg.domain}/";
+          };
+          service = {
+            DISABLE_REGISTRATION = true;
+            ENABLE_BASIC_AUTHENTICATION = false;
+          };
+          repository = {
+            DEFAULT_REPO_UNITS = "repo.code,repo.releases,repo.issues,repo.pulls";
+            DEFAULT_FORK_REPO_UNITS = "repo.code,repo.pulls";
+            DEFAULT_MIRROR_REPO_UNITS = "repo.code";
+          };
+          actions = {
+            ENABLED = true;
+            DEFAULT_ACTIONS_URL = "http${lib.optionalString hostCfg.external "s"}://${hostCfg.domain}";
+          };
+          webhook = {
+            ALLOWED_HOST_LIST = "external,loopback";
+          };
+          log = {
+            LEVEL = "Info";
+            LOGGER_ROUTER_MODE = "Error";
+          };
+          ui = {
+            THEMES = lib.concatStringsSep "," [
+              "forgejo-auto"
+              "forgejo-light"
+              "forgejo-dark"
+              "gitea-auto"
+              "gitea-light"
+              "gitea-dark"
+            ];
+          };
+        };
+      };
+
+      users.users."git" = {
+        isSystemUser = true;
+        useDefaultShell = true;
+        group = config.services.forgejo.group;
+        home = config.services.forgejo.stateDir;
+      };
+
+      services.openssh = {
+        extraConfig = ''
+          Match User git
+            AcceptEnv GIT_PROTOCOL
+        '';
+      };
+    };
+  };
+}