{ config, lib, vhackPackages, ... }: let cfg = config.vhack.back; mkUnit = repoPath: port: { description = "Back service for ${repoPath}"; wants = ["network-online.target"]; after = ["network-online.target"]; wantedBy = ["default.target"]; environment = { ROCKET_PORT = builtins.toString port; BACK_SOURCE_CODE_REPOSITORY_URL = "https://git.vhack.eu/vhack.eu/nixos-server/tree/pkgs/by-name/ba/back"; }; serviceConfig = { ExecStart = "${lib.getExe vhackPackages.back} ${lib.strings.escapeShellArg repoPath}"; # Ensure that the service can read the repository # FIXME(@bpeetz): This has the implied assumption, that all the exposed git # repositories are readable for the git group. This should not be necessary. <2024-12-23> User = "git"; Group = "git"; DynamicUser = true; Restart = "always"; # Sandboxing ProtectSystem = "strict"; ProtectHome = true; PrivateTmp = true; PrivateDevices = true; ProtectHostname = true; ProtectClock = true; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; RestrictNamespaces = true; LockPersonality = true; MemoryDenyWriteExecute = true; RestrictRealtime = true; RestrictSUIDSGID = true; RemoveIPC = true; PrivateMounts = true; # System Call Filtering SystemCallArchitectures = "native"; SystemCallFilter = ["~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid"]; }; }; mkVirtalHost = port: { locations."/".proxyPass = "http://127.0.0.1:${builtins.toString port}"; enableACME = true; forceSSL = true; }; services = lib.mapAttrs' (gitPath: config: { name = builtins.replaceStrings ["/"] ["_"] "back-${gitPath}-${config.domain}"; value = mkUnit gitPath config.port; }) cfg.repositories; virtualHosts = lib.mapAttrs' (gitPath: config: { name = config.domain; value = mkVirtalHost config.port; }) cfg.repositories; in { options.vhack.back = { enable = lib.mkEnableOption "Back issue tracker (inspired by tvix's panettone)"; repositories = lib.mkOption { description = "An attibute set of repos to launch `back` services for."; type = lib.types.attrsOf (lib.types.submodule { options = { enable = (lib.mkEnableOption "`back` for this repository.") // {default = true;}; domain = lib.mkOption { type = lib.types.str; description = "The domain to host this `back` instance on."; }; port = lib.mkOption { type = lib.types.port; # TODO: This _should_ be an implementation detail, but I've no real approach to # automatically generate them without encountering weird bugs. <2024-12-23> description = "The port to use for this back instance. This must be unique."; }; }; }); default = {}; }; }; config = lib.mkIf cfg.enable { systemd = {inherit services;}; services.nginx = {inherit virtualHosts;}; }; }