a more proper nixos module for the tangled knotserver

feat: yolo

Cassie Cheung 590da4ff

+2
.gitignore
··· 1 + result 2 + .direnv
+12
flake.nix
··· 1 + { 2 + description = "read if cute"; 3 + 4 + inputs = { 5 + # nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; # probably not needed until we add checks 6 + tangledCore.url = "git+https://tangled.sh/@tangled.sh/core"; 7 + }; 8 + 9 + outputs = { self, tangledCore }: { 10 + nixosModules.default = import ./module.nix tangledCore; 11 + }; 12 + }
+174
module.nix
··· 1 + # modified from https://tangled.sh/@tangled.sh/core/blob/master/flake.nix 2 + tangledFlake: 3 + { 4 + config, 5 + pkgs, 6 + lib, 7 + ... 8 + }: 9 + let 10 + inherit (lib) 11 + mkOption 12 + types 13 + mkIf 14 + optional 15 + ; 16 + cfg = config.services.tangled-knotserver; 17 + tangledPkgs = tangledFlake.packages.${pkgs.system}; 18 + 19 + keyfetchWrapper = pkgs.writeShellScriptBin { 20 + name = "keyfetch-wrapper"; 21 + runtimeInputs = [ tangledPkgs.keyfetch ]; 22 + text = '' 23 + keyfetch -repoguard-path ${lib.getExe tangledPkgs.repoguard} -log-path /tmp/repoguard.log 24 + ''; 25 + }; 26 + in 27 + { 28 + options = { 29 + services.tangled-knotserver = { 30 + enable = mkOption { 31 + type = types.bool; 32 + default = false; 33 + description = "Enable a tangled knotserver"; 34 + }; 35 + 36 + appviewEndpoint = mkOption { 37 + type = types.str; 38 + default = "https://tangled.sh"; 39 + description = "Appview endpoint"; 40 + }; 41 + 42 + gitUser = mkOption { 43 + type = types.str; 44 + default = "git"; 45 + description = "User that hosts git repos and performs git operations"; 46 + }; 47 + 48 + repo = { 49 + scanPath = mkOption { 50 + type = types.path; 51 + default = "/var/lib/tangled-knot"; 52 + description = "Path where repositories are scanned from"; 53 + }; 54 + 55 + mainBranch = mkOption { 56 + type = types.str; 57 + default = "main"; 58 + description = "Default branch name for repositories"; 59 + }; 60 + }; 61 + 62 + server = { 63 + listenAddr = mkOption { 64 + type = types.str; 65 + default = "0.0.0.0:5555"; 66 + description = "Address to listen on"; 67 + }; 68 + 69 + internalListenAddr = mkOption { 70 + type = types.str; 71 + default = "127.0.0.1:5444"; 72 + description = "Internal address for inter-service communication"; 73 + }; 74 + 75 + dbPath = mkOption { 76 + type = types.path; 77 + default = "knotserver.db"; 78 + description = "Path to the database file"; 79 + }; 80 + 81 + hostname = mkOption { 82 + type = types.str; 83 + example = "knot.tangled.sh"; 84 + description = "Hostname for the server (required)"; 85 + }; 86 + 87 + dev = mkOption { 88 + type = types.bool; 89 + default = false; 90 + description = "Enable development mode (disables signature verification)"; 91 + internal = true; 92 + }; 93 + }; 94 + 95 + extraConfig = mkOption { 96 + type = types.attrsOf types.str; 97 + default = { }; 98 + example = lib.literalExpression '' 99 + { 100 + # this is only an example, do NOT do this! your secret will end up readable by *everyone*! 101 + KNOT_SERVER_SECRET = "verysecuresecret"; 102 + } 103 + ''; 104 + description = "Additional environment variables. Use `environmentFile` for secrets."; 105 + }; 106 + 107 + environmentFile = mkOption { 108 + type = types.nullOr types.path; 109 + default = null; 110 + example = "/etc/tangled/knotserver.env"; 111 + description = '' 112 + Environment file to set additional configuration and secrets for the knotserver. 113 + 114 + `KNOT_SERVER_SECRET` must be set for the knotserver to work, and can be obtained from 115 + [this page](https://tangled.sh/knots). 116 + ''; 117 + }; 118 + }; 119 + }; 120 + 121 + config = mkIf config.enable { 122 + warnings = optional cfg.server.dev '' 123 + tangled-knotserver: development mode is enabled. This is not recommended in production as signature checks are disabled. 124 + ''; 125 + 126 + environment.systemPackages = with pkgs; [ git ]; 127 + 128 + users.users.${cfg.gitUser} = { 129 + home = cfg.repo.scanPath; 130 + group = cfg.gitUser; 131 + isSystemUser = true; 132 + useDefaultShell = true; 133 + }; 134 + 135 + users.groups.${cfg.gitUser} = { }; 136 + 137 + services.openssh = { 138 + enable = true; 139 + extraConfig = '' 140 + Match User ${cfg.gitUser} 141 + AuthorizedKeysCommand ${keyfetchWrapper} 142 + AuthorizedKeysCommandUser nobody 143 + ''; 144 + }; 145 + 146 + systemd.services.knotserver = { 147 + description = "knotserver service"; 148 + after = [ 149 + "network-online.target" 150 + "sshd.service" 151 + ]; 152 + wants = [ 153 + "network-online.target" 154 + "sshd.service" 155 + ]; 156 + wantedBy = [ "multi-user.target" ]; 157 + serviceConfig = { 158 + User = cfg.gitUser; 159 + WorkingDirectory = cfg.repo.scanPath; 160 + ExecStart = lib.getExe tangledPkgs.knotserver; 161 + Restart = "always"; 162 + EnvironmentFile = cfg.environmentFile; 163 + }; 164 + 165 + environment = { 166 + KNOT_REPO_SCANPATH = cfg.repo.scanPath; 167 + APPVIEW_ENDPOINT = cfg.appviewEndpoint; 168 + KNOT_SERVER_INTERNAL_LISTEN_ADDR = cfg.server.internalListenAddr; 169 + KNOT_SERVER_LISTEN_ADDR = cfg.server.listenAddr; 170 + KNOT_SERVER_HOSTNAME = cfg.server.hostname; 171 + } // cfg.extraConfig; 172 + }; 173 + }; 174 + }