Kieran's opinionated (and probably slightly dumb) nix config
1{ 2 inputs, 3 lib, 4 config, 5 pkgs, 6 ... 7}: 8{ 9 imports = [ 10 ./disk-config.nix 11 ./home-manager.nix 12 13 (inputs.import-tree ../../modules/nixos) 14 inputs.tangled.nixosModules.knot 15 inputs.tangled.nixosModules.spindle 16 ]; 17 18 nixpkgs = { 19 hostPlatform = "aarch64-linux"; 20 config = { 21 allowUnfree = true; 22 }; 23 }; 24 25 nix = 26 let 27 flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs; 28 in 29 { 30 settings = { 31 experimental-features = "nix-command flakes"; 32 flake-registry = ""; 33 nix-path = config.nix.nixPath; 34 trusted-users = [ 35 "kierank" 36 ]; 37 }; 38 channel.enable = false; 39 optimise.automatic = true; 40 registry = lib.mapAttrs (_: flake: { inherit flake; }) flakeInputs; 41 nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs; 42 }; 43 44 time.timeZone = "America/New_York"; 45 46 environment.systemPackages = with pkgs; [ 47 # core 48 coreutils 49 screen 50 bc 51 jq 52 psmisc 53 # cli_utils 54 direnv 55 zsh 56 gum 57 vim 58 # networking 59 xh 60 curl 61 wget 62 dogdns 63 inetutils 64 mosh 65 # nix_tools 66 inputs.nixvim.packages.aarch64-linux.default 67 nixd 68 nil 69 nixfmt-rfc-style 70 inputs.agenix.packages.aarch64-linux.default 71 # security 72 openssl 73 gpgme 74 gnupg 75 # dev_langs 76 nodejs_22 77 unstable.bun 78 python3 79 go 80 gopls 81 gotools 82 go-tools 83 gcc 84 # misc 85 neofetch 86 git 87 ]; 88 89 programs.nh = { 90 enable = true; 91 clean.enable = true; 92 clean.extraArgs = "--keep-since 4d --keep 3"; 93 flake = "/home/kierank/dots"; 94 }; 95 96 age.identityPaths = [ 97 "/home/kierank/.ssh/id_rsa" 98 "/etc/ssh/id_rsa" 99 ]; 100 age.secrets = { 101 wakatime = { 102 file = ../../secrets/wakatime.age; 103 path = "/home/kierank/.wakatime.cfg"; 104 owner = "kierank"; 105 }; 106 cachet = { 107 file = ../../secrets/cachet.age; 108 owner = "cachet"; 109 }; 110 hn-alerts = { 111 file = ../../secrets/hn-alerts.age; 112 owner = "hn-alerts"; 113 }; 114 emojibot = { 115 file = ../../secrets/emojibot.age; 116 owner = "emojibot"; 117 }; 118 cloudflare = { 119 file = ../../secrets/cloudflare.age; 120 owner = "caddy"; 121 }; 122 github-knot-sync = { 123 file = ../../secrets/github-knot-sync.age; 124 owner = "git"; 125 }; 126 battleship-arena = { 127 file = ../../secrets/battleship-arena.age; 128 owner = "battleship-arena"; 129 }; 130 frp-auth-token = { 131 file = ../../secrets/frp-auth-token.age; 132 }; 133 }; 134 135 environment.sessionVariables = { 136 XDG_CACHE_HOME = "$HOME/.cache"; 137 XDG_CONFIG_HOME = "$HOME/.config"; 138 XDG_DATA_HOME = "$HOME/.local/share"; 139 XDG_STATE_HOME = "$HOME/.local/state"; 140 EDITOR = "nvim"; 141 SYSTEMD_EDITOR = "nvim"; 142 VISUAL = "nvim"; 143 }; 144 145 atelier = { 146 authentication.enable = true; 147 }; 148 149 networking = { 150 hostName = "terebithia"; 151 networkmanager.enable = true; 152 }; 153 154 programs.zsh.enable = true; 155 programs.direnv.enable = true; 156 157 users.users = { 158 kierank = { 159 initialPassword = "changeme"; 160 isNormalUser = true; 161 shell = pkgs.zsh; 162 openssh.authorizedKeys.keys = [ 163 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzEEjvbL/ttqmYoDjxYQmDIq36BabROJoXgQKeh9liBxApwp+2PmgxROzTg42UrRc9pyrkq5kVfxG5hvkqCinhL1fMiowCSEs2L2/Cwi40g5ZU+QwdcwI8a4969kkI46PyB19RHkxg54OUORiIiso/WHGmqQsP+5wbV0+4riSnxwn/JXN4pmnE//stnyAyoiEZkPvBtwJjKb3Ni9n3eNLNs6gnaXrCtaygEZdebikr9kS2g9mM696HvIFgM6cdR/wZ7DcLbG3IdTXuHN7PC3xxL+Y4ek5iMreQIPmuvs4qslbthPGYoYbYLUQiRa9XO5s/ksIj5Z14f7anHE6cuTQVpvNWdGDOigyIVS5qU+4ZF7j+rifzOXVL48gmcAvw/uV68m5Wl/p0qsC/d8vI3GYwEsWG/EzpAlc07l8BU2LxWgN+d7uwBFaJV9VtmUDs5dcslsh8IbzmtC9gq3OLGjklxTfIl6qPiL8U33oc/UwqzvZUrI2BlbagvIZYy6rP+q0= kierank@mockingjay" 164 ]; 165 extraGroups = [ 166 "wheel" 167 "networkmanager" 168 "services" 169 ]; 170 }; 171 root.openssh.authorizedKeys.keys = [ 172 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzEEjvbL/ttqmYoDjxYQmDIq36BabROJoXgQKeh9liBxApwp+2PmgxROzTg42UrRc9pyrkq5kVfxG5hvkqCinhL1fMiowCSEs2L2/Cwi40g5ZU+QwdcwI8a4969kkI46PyB19RHkxg54OUORiIiso/WHGmqQsP+5wbV0+4riSnxwn/JXN4pmnE//stnyAyoiEZkPvBtwJjKb3Ni9n3eNLNs6gnaXrCtaygEZdebikr9kS2g9mM696HvIFgM6cdR/wZ7DcLbG3IdTXuHN7PC3xxL+Y4ek5iMreQIPmuvs4qslbthPGYoYbYLUQiRa9XO5s/ksIj5Z14f7anHE6cuTQVpvNWdGDOigyIVS5qU+4ZF7j+rifzOXVL48gmcAvw/uV68m5Wl/p0qsC/d8vI3GYwEsWG/EzpAlc07l8BU2LxWgN+d7uwBFaJV9VtmUDs5dcslsh8IbzmtC9gq3OLGjklxTfIl6qPiL8U33oc/UwqzvZUrI2BlbagvIZYy6rP+q0= kierank@mockingjay" 173 ]; 174 }; 175 176 # Allow passwordless sudo for wheel group (needed for deploy-rs) 177 security.sudo.wheelNeedsPassword = false; 178 179 services.openssh = { 180 enable = true; 181 openFirewall = true; 182 settings = { 183 PermitRootLogin = "no"; 184 PasswordAuthentication = false; 185 }; 186 }; 187 188 networking.firewall = { 189 enable = true; 190 allowedTCPPorts = [ 191 22 192 80 193 443 194 ]; 195 logRefusedConnections = false; 196 rejectPackets = true; 197 }; 198 199 services.tailscale = { 200 enable = true; 201 useRoutingFeatures = "client"; 202 }; 203 204 services.caddy = { 205 enable = true; 206 package = pkgs.caddy.withPlugins { 207 plugins = [ "github.com/caddy-dns/cloudflare@v0.2.2" ]; 208 hash = "sha256-ea8PC/+SlPRdEVVF/I3c1CBprlVp1nrumKM5cMwJJ3U="; 209 }; 210 email = "me@dunkirk.sh"; 211 globalConfig = '' 212 acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN} 213 ''; 214 virtualHosts."knot.dunkirk.sh" = { 215 extraConfig = '' 216 tls { 217 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 218 } 219 header { 220 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 221 } 222 reverse_proxy localhost:5555 { 223 header_up X-Forwarded-Proto {scheme} 224 header_up X-Forwarded-For {remote} 225 } 226 ''; 227 }; 228 virtualHosts."spindle.dunkirk.sh" = { 229 extraConfig = '' 230 tls { 231 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 232 } 233 header { 234 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 235 } 236 reverse_proxy localhost:6555 { 237 header_up X-Forwarded-Proto {scheme} 238 header_up X-Forwarded-For {remote} 239 } 240 ''; 241 }; 242 virtualHosts."emojibot.dunkirk.sh" = { 243 extraConfig = '' 244 tls { 245 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 246 } 247 header { 248 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 249 } 250 reverse_proxy localhost:3002 { 251 header_up X-Forwarded-Proto {scheme} 252 header_up X-Forwarded-For {remote} 253 } 254 ''; 255 }; 256 virtualHosts."battleship.dunkirk.sh" = { 257 extraConfig = '' 258 tls { 259 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 260 } 261 header { 262 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 263 } 264 reverse_proxy localhost:8081 { 265 header_up X-Forwarded-Proto {scheme} 266 header_up X-Forwarded-For {remote} 267 } 268 ''; 269 }; 270 extraConfig = '' 271 # Default response for unhandled domains 272 :80 { 273 respond "404 - Looks like this bridge doesn't have an end" 404 274 } 275 :443 { 276 respond "404 - Looks like this bridge doesn't have an end" 404 277 } 278 ''; 279 }; 280 281 systemd.services.caddy.serviceConfig = { 282 EnvironmentFile = config.age.secrets.cloudflare.path; 283 }; 284 285 atelier.services.cachet = { 286 enable = true; 287 domain = "cachet.dunkirk.sh"; 288 secretsFile = config.age.secrets.cachet.path; 289 }; 290 291 atelier.services.hn-alerts = { 292 enable = true; 293 domain = "hn.dunkirk.sh"; 294 secretsFile = config.age.secrets.hn-alerts.path; 295 }; 296 297 atelier.services.emojibot = { 298 enable = true; 299 domain = "emojibot.dunkirk.sh"; 300 secretsFile = config.age.secrets.emojibot.path; 301 }; 302 303 atelier.services.battleship-arena = { 304 enable = true; 305 domain = "battleship.dunkirk.sh"; 306 sshPort = 2222; 307 package = inputs.battleship-arena.packages.aarch64-linux.default; 308 secretsFile = config.age.secrets.battleship-arena.path; 309 }; 310 311 services.tangled.knot = { 312 enable = true; 313 package = inputs.tangled.packages.aarch64-linux.knot; 314 appviewEndpoint = "https://tangled.org"; 315 server = { 316 owner = "did:plc:krxbvxvis5skq7jj6eot23ul"; 317 hostname = "knot.dunkirk.sh"; 318 listenAddr = "127.0.0.1:5555"; 319 }; 320 }; 321 322 services.tangled.spindle = { 323 enable = true; 324 package = inputs.tangled.packages.aarch64-linux.spindle; 325 server = { 326 owner = "did:plc:krxbvxvis5skq7jj6eot23ul"; 327 hostname = "spindle.dunkirk.sh"; 328 listenAddr = "127.0.0.1:6555"; 329 }; 330 }; 331 332 atelier.services.knot-sync = { 333 enable = true; 334 secretsFile = config.age.secrets.github-knot-sync.path; 335 }; 336 337 atelier.services.frps = { 338 enable = true; 339 domain = "bore.dunkirk.sh"; 340 authTokenFile = config.age.secrets.frp-auth-token.path; 341 }; 342 343 services.n8n = { 344 enable = true; 345 environment = { 346 N8N_HOST = "n8n.dunkirk.sh"; 347 N8N_PROTOCOL = "https"; 348 WEBHOOK_URL = "https://n8n.dunkirk.sh"; 349 }; 350 }; 351 352 services.caddy.virtualHosts."n8n.dunkirk.sh" = { 353 extraConfig = '' 354 tls { 355 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 356 } 357 header { 358 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 359 } 360 reverse_proxy localhost:5678 { 361 header_up X-Forwarded-Proto {scheme} 362 header_up X-Forwarded-For {remote} 363 } 364 ''; 365 }; 366 367 boot.loader.systemd-boot.enable = true; 368 boot.loader.efi.canTouchEfiVariables = true; 369 boot.kernelParams = [ "console=ttyS0" ]; 370 371 system.stateVersion = "23.05"; 372}