{ self, inputs, ... }: { flake.modules.nixos.forgejo = {config, pkgs, lib, ... }: let cfg = config.forgejo; needsPrivilegedPort = cfg.port < 1024; in { options.forgejo = { enable = lib.mkEnableOption "Enable Forgejo backed with PostgreSQL"; root_url = lib.mkOption { type = lib.types.str; }; port = lib.mkOption { type = lib.types.port; default = 3000; description = "TCP port for the Forgejo web interface."; }; openFirewall = lib.mkOption { type = lib.types.bool; default = true; description = "Open the Forgejo web interface port in the firewall."; }; https = lib.mkEnableOption "Open the Forgejo web interface port in the firewall."; }; config = lib.mkIf cfg.enable { networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ cfg.port ]; systemd.services.forgejo.serviceConfig = lib.mkIf needsPrivilegedPort { AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; PrivateUsers = lib.mkForce false; }; sops.secrets = { "forgejo/secret_key".owner = config.services.forgejo.user; "forgejo/internal_token".owner = config.services.forgejo.user; "forgejo/jwt_secret".owner = config.services.forgejo.user; "forgejo/lfs_jwt_secret".owner = config.services.forgejo.user; }; services = { forgejo = { enable = true; lfs.enable = true; database.type = "postgres"; settings = { DEFAULT = { RUN_MODE = "dev"; }; server = lib.mkMerge [ { HTTP_PORT = cfg.port; DISABLE_SSH = true; ROOT_URL = cfg.root_url; } (lib.mkIf cfg.https { PROTOCOL = "https"; COOKIE_SECURE = true; KEY_FILE = config.mtls.keyFile; CERT_FILE = config.mtls.certFile; }) ]; oauth2_client = { ENABLE_AUTO_REGISTRATION = true; USERNAME = "nickname"; UPDATE_AVATAR = true; ACCOUNT_LINKING = "login"; REGISTER_EMAIL_CONFIRM = false; }; repository = { ENABLE_PUSH_CREATE_USER = true; }; ui.SHOW_USER_EMAIL = false; markup = { ENABLED = true; }; }; secrets = { security = { SECRET_KEY = lib.mkForce config.sops.secrets."forgejo/secret_key".path; INTERNAL_TOKEN = lib.mkForce config.sops.secrets."forgejo/internal_token".path; }; oauth2.JWT_SECRET = lib.mkForce config.sops.secrets."forgejo/jwt_secret".path; server.LFS_JWT_SECRET = lib.mkForce config.sops.secrets."forgejo/lfs_jwt_secret".path; }; dump = { enable = true; type = "tar"; interval = "*-*-* 00/12:00:00"; }; }; postgresql = { enable = true; enableTCPIP = false; }; }; # https://forgejo.org/docs/latest/admin/command-line/#dump systemd.services.forgejo-dump.serviceConfig.ExecStart = lib.mkForce '' ${lib.getExe config.services.forgejo.package} dump --verbose \ --type ${config.services.forgejo.dump.type} \ --database postgres \ --work-path ${config.services.forgejo.dump.backupDir} ''; environment.systemPackages = let systemctl = lib.getExe' pkgs.systemd "systemctl"; clean-forgejo = (pkgs.writeShellScriptBin "clean-forgejo" '' set -euo pipefail sudo ${systemctl} stop forgejo.service ${lib.getExe' pkgs.coreutils "echo"} "Stopped Forgejo" sudo ${lib.getExe' pkgs.coreutils "rm"} -rf ${config.services.forgejo.stateDir} ${lib.getExe' pkgs.coreutils "echo"} "Removed ${config.services.forgejo.stateDir}" ''); clean-postgres = (pkgs.writeShellScriptBin "clean-postgres" '' set -euo pipefail sudo ${systemctl} stop postgresql.service ${lib.getExe' pkgs.coreutils "echo"} "Stopped PostgreSQL" sudo ${lib.getExe' pkgs.coreutils "rm"} -rf ${config.services.postgresql.dataDir} ${lib.getExe' pkgs.coreutils "echo"} "Removed ${config.services.postgresql.dataDir}" ''); in [ clean-forgejo clean-postgres (pkgs.writeShellScriptBin "clean-all" '' set -euo pipefail GREEN_CHECK="\e[32m✔\e[0m" YELLOW_BANG="\e[33m!\e[0m" ${lib.getExe' pkgs.coreutils "echo"} -n -e "$YELLOW_BANG Remove everything related to Forgejo and the PostgreSQL database behind it?" read -p " (y/n) " -n 1 -r if [[ $REPLY =~ ^[Yy]$ ]]; then ${lib.getExe clean-forgejo} ${lib.getExe clean-postgres} ${lib.getExe' pkgs.coreutils "echo"} -e "$GREEN_CHECK Removed everything related to forgejo" fi '') ]; }; }; }