This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / configs / services / git / knot.nix
6.1 kB 201 lines
1{ 2 self, 3 config, 4 lib, 5 pkgs, 6 ... 7}: 8let 9 domain = "knot.lassul.us"; 10 # DID of the owner's account on pds.lassul.us; the knot stays off while null 11 ownerDid = null; 12 user = "tangled-knot"; 13 stateDir = "/var/lib/tangled-knot"; 14 listenAddr = "127.0.0.1:5555"; 15 sshPort = 2222; 16 package = self.packages.${pkgs.stdenv.hostPlatform.system}.tangled.knot-rs; 17 18 # `knot-server config-template` lists the keys; upstream's defaults, except 19 # where commented 20 rendered = (pkgs.formats.toml { }).generate "knot.toml" { 21 server = { 22 hostname = domain; 23 admins = [ ownerDid ]; 24 appview_endpoint = "https://git.lassul.us"; 25 listen_addr = listenAddr; 26 internal_listen_addr = "[::1]:5444"; 27 ssh_listen_addr = "[::]:${toString sshPort}"; 28 ssh_host_key_file = "${stateDir}/ssh_host_key"; 29 }; 30 atproto.plc_directory = "https://plc.directory"; 31 acl.admission = "closed"; 32 repo.scan_path = "${stateDir}/repos"; 33 # sha256 repos can't exchange objects with sha1 ones (github, cgit) 34 git.object_format = "sha1"; 35 secrets = { 36 sealed_key_file = "${stateDir}/sealed-keys"; 37 master_key_env = "KNOT_MASTER_KEY"; 38 }; 39 tls = { 40 http3 = true; 41 acme_enabled = false; 42 acme_cache_dir = "${stateDir}/acme"; 43 acme_staging = false; 44 mtls_enabled = false; 45 }; 46 xrpc = { 47 trusted_proxy_header = "x-forwarded-for"; 48 trusted_proxies = [ 49 "127.0.0.1" 50 "::1" 51 ]; 52 }; 53 }; 54 configFile = pkgs.runCommandLocal "knot-config.toml" { nativeBuildInputs = [ package ]; } '' 55 knot-server validate --config-only ${rendered} 56 ln -s ${rendered} $out 57 ''; 58in 59{ 60 # Tangled knot 2 (knot-rs): git hosting for git.lassul.us, following 61 # tangled's nix/modules/knot-rs.nix without its flake (the module files are 62 # in a fetched source, importing them would be IFD): plain HTTP behind 63 # nginx, unprivileged ports, keys in stateDir. The Go knot's unit and user 64 # are both named knot, which the DNS server already uses. 65 # Knot 2 serves ssh itself, on port 2222 since sshd keeps 22, so clone URLs 66 # need ssh://git@knot.lassul.us:2222/... or a Port line in ~/.ssh/config. 67 68 config = lib.mkIf (ownerDid != null) { 69 clan.core.vars.generators.tangled-knot = { 70 files."knot.env" = { }; 71 runtimeInputs = [ pkgs.openssl ]; 72 script = '' 73 echo "KNOT_MASTER_KEY=$(openssl rand -base64 32)" > "$out/knot.env" 74 ''; 75 }; 76 77 environment.systemPackages = [ package ]; 78 environment.etc."knot/config.toml".source = configFile; 79 80 users.users.${user} = { 81 isSystemUser = true; 82 home = stateDir; 83 group = user; 84 }; 85 users.groups.${user} = { }; 86 87 systemd.tmpfiles.settings."10-knot-rs" = { 88 ${stateDir}.d = { 89 mode = "0750"; 90 inherit user; 91 group = user; 92 }; 93 "${stateDir}/repos".d = { 94 mode = "0750"; 95 inherit user; 96 group = user; 97 }; 98 }; 99 100 systemd.services.knot-rs = { 101 description = "knot git server"; 102 after = [ "network-online.target" ]; 103 wants = [ "network-online.target" ]; 104 wantedBy = [ "multi-user.target" ]; 105 restartTriggers = [ configFile ]; 106 startLimitIntervalSec = 60; 107 startLimitBurst = 5; 108 serviceConfig = { 109 User = user; 110 Group = user; 111 UMask = "0077"; 112 WorkingDirectory = stateDir; 113 EnvironmentFile = config.clan.core.vars.generators.tangled-knot.files."knot.env".path; 114 ExecStart = "${lib.getExe package} /etc/knot/config.toml"; 115 Restart = "on-failure"; 116 RestartSec = 5; 117 TimeoutStopSec = 120; 118 LimitNOFILE = 65536; 119 CapabilityBoundingSet = [ ]; 120 ReadWritePaths = [ 121 stateDir 122 "${stateDir}/repos" 123 ]; 124 NoNewPrivileges = true; 125 ProtectProc = "invisible"; 126 ProtectSystem = "strict"; 127 ProtectHome = true; 128 PrivateTmp = true; 129 PrivateDevices = true; 130 PrivateUsers = true; 131 ProtectHostname = true; 132 ProtectClock = true; 133 ProtectKernelTunables = true; 134 ProtectKernelModules = true; 135 ProtectKernelLogs = true; 136 ProtectControlGroups = true; 137 RestrictAddressFamilies = [ 138 "AF_INET" 139 "AF_INET6" 140 "AF_NETLINK" 141 "AF_UNIX" 142 ]; 143 RestrictNamespaces = true; 144 LockPersonality = true; 145 MemoryDenyWriteExecute = true; 146 RestrictRealtime = true; 147 RestrictSUIDSGID = true; 148 RemoveIPC = true; 149 PrivateMounts = true; 150 SystemCallFilter = [ 151 "@system-service" 152 "~@privileged @resources" 153 ]; 154 SystemCallArchitectures = "native"; 155 }; 156 }; 157 158 networking.firewall.allowedTCPPorts = [ sshPort ]; 159 160 # knot 2 doesn't request crawls (no KNOT_MIRRORS), so subscribe our 161 # mirror (knotmirror.nix) to the knot's event stream whenever either 162 # starts; the mirror marks a knot offline after it was unreachable for a 163 # while 164 systemd.services.knotmirror-request-crawl = { 165 wantedBy = [ 166 "knot-rs.service" 167 "knotmirror.service" 168 ]; 169 after = [ 170 "knot-rs.service" 171 "knotmirror.service" 172 ]; 173 serviceConfig.Type = "oneshot"; 174 script = '' 175 ${pkgs.curl}/bin/curl -fsS --retry 10 --retry-connrefused \ 176 -H 'Content-Type: application/json' -d '{"hostname":"${domain}"}' \ 177 http://127.0.0.1:7000/xrpc/sh.tangled.sync.requestCrawl 178 ''; 179 }; 180 181 # repos (with the ACL data), sealed keys and ssh host key; the master key 182 # is in vars 183 lass.backup.state.tangled-knot.folders = [ stateDir ]; 184 185 services.nginx.virtualHosts.${domain} = { 186 enableACME = true; 187 forceSSL = true; 188 locations."/" = { 189 proxyPass = "http://${listenAddr}"; 190 recommendedProxySettings = true; 191 # /events 192 proxyWebsockets = true; 193 extraConfig = '' 194 proxy_read_timeout 1d; 195 client_max_body_size 0; 196 proxy_request_buffering off; 197 ''; 198 }; 199 }; 200 }; 201}