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 }; 131 132 environment.sessionVariables = { 133 XDG_CACHE_HOME = "$HOME/.cache"; 134 XDG_CONFIG_HOME = "$HOME/.config"; 135 XDG_DATA_HOME = "$HOME/.local/share"; 136 XDG_STATE_HOME = "$HOME/.local/state"; 137 EDITOR = "nvim"; 138 SYSTEMD_EDITOR = "nvim"; 139 VISUAL = "nvim"; 140 }; 141 142 atelier = { 143 authentication.enable = true; 144 }; 145 146 networking = { 147 hostName = "terebithia"; 148 networkmanager.enable = true; 149 }; 150 151 programs.zsh.enable = true; 152 programs.direnv.enable = true; 153 154 users.users = { 155 kierank = { 156 initialPassword = "changeme"; 157 isNormalUser = true; 158 shell = pkgs.zsh; 159 openssh.authorizedKeys.keys = [ 160 "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" 161 ]; 162 extraGroups = [ 163 "wheel" 164 "networkmanager" 165 "services" 166 ]; 167 }; 168 root.openssh.authorizedKeys.keys = [ 169 "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" 170 ]; 171 }; 172 173 # Allow passwordless sudo for wheel group (needed for deploy-rs) 174 security.sudo.wheelNeedsPassword = false; 175 176 services.openssh = { 177 enable = true; 178 openFirewall = true; 179 settings = { 180 PermitRootLogin = "no"; 181 PasswordAuthentication = false; 182 }; 183 }; 184 185 networking.firewall = { 186 enable = true; 187 allowedTCPPorts = [ 188 22 189 80 190 443 191 ]; 192 logRefusedConnections = false; 193 rejectPackets = true; 194 }; 195 196 services.tailscale = { 197 enable = true; 198 useRoutingFeatures = "client"; 199 }; 200 201 services.caddy = { 202 enable = true; 203 package = pkgs.caddy.withPlugins { 204 plugins = [ "github.com/caddy-dns/cloudflare@v0.2.2" ]; 205 hash = "sha256-ea8PC/+SlPRdEVVF/I3c1CBprlVp1nrumKM5cMwJJ3U="; 206 }; 207 email = "me@dunkirk.sh"; 208 globalConfig = '' 209 acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN} 210 ''; 211 virtualHosts."knot.dunkirk.sh" = { 212 extraConfig = '' 213 tls { 214 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 215 } 216 header { 217 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 218 } 219 reverse_proxy localhost:5555 { 220 header_up X-Forwarded-Proto {scheme} 221 header_up X-Forwarded-For {remote} 222 } 223 ''; 224 }; 225 virtualHosts."spindle.dunkirk.sh" = { 226 extraConfig = '' 227 tls { 228 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 229 } 230 header { 231 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 232 } 233 reverse_proxy localhost:6555 { 234 header_up X-Forwarded-Proto {scheme} 235 header_up X-Forwarded-For {remote} 236 } 237 ''; 238 }; 239 virtualHosts."emojibot.dunkirk.sh" = { 240 extraConfig = '' 241 tls { 242 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 243 } 244 header { 245 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 246 } 247 reverse_proxy localhost:3002 { 248 header_up X-Forwarded-Proto {scheme} 249 header_up X-Forwarded-For {remote} 250 } 251 ''; 252 }; 253 virtualHosts."battleship.dunkirk.sh" = { 254 extraConfig = '' 255 tls { 256 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 257 } 258 header { 259 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 260 } 261 reverse_proxy localhost:8081 { 262 header_up X-Forwarded-Proto {scheme} 263 header_up X-Forwarded-For {remote} 264 } 265 ''; 266 }; 267 extraConfig = '' 268 # Default response for unhandled domains 269 :80 { 270 respond "404 - Looks like this bridge doesn't have an end" 404 271 } 272 :443 { 273 respond "404 - Looks like this bridge doesn't have an end" 404 274 } 275 ''; 276 }; 277 278 systemd.services.caddy.serviceConfig = { 279 EnvironmentFile = config.age.secrets.cloudflare.path; 280 }; 281 282 atelier.services.cachet = { 283 enable = true; 284 domain = "cachet.dunkirk.sh"; 285 secretsFile = config.age.secrets.cachet.path; 286 }; 287 288 atelier.services.hn-alerts = { 289 enable = true; 290 domain = "hn.dunkirk.sh"; 291 secretsFile = config.age.secrets.hn-alerts.path; 292 }; 293 294 atelier.services.emojibot = { 295 enable = true; 296 domain = "emojibot.dunkirk.sh"; 297 secretsFile = config.age.secrets.emojibot.path; 298 }; 299 300 atelier.services.battleship-arena = { 301 enable = true; 302 domain = "battleship.dunkirk.sh"; 303 sshPort = 2222; 304 package = inputs.battleship-arena.packages.aarch64-linux.default; 305 secretsFile = config.age.secrets.battleship-arena.path; 306 }; 307 308 services.tangled.knot = { 309 enable = true; 310 package = inputs.tangled.packages.aarch64-linux.knot; 311 appviewEndpoint = "https://tangled.org"; 312 server = { 313 owner = "did:plc:krxbvxvis5skq7jj6eot23ul"; 314 hostname = "knot.dunkirk.sh"; 315 listenAddr = "127.0.0.1:5555"; 316 }; 317 }; 318 319 services.tangled.spindle = { 320 enable = true; 321 package = inputs.tangled.packages.aarch64-linux.spindle; 322 server = { 323 owner = "did:plc:krxbvxvis5skq7jj6eot23ul"; 324 hostname = "spindle.dunkirk.sh"; 325 listenAddr = "127.0.0.1:6555"; 326 }; 327 }; 328 329 atelier.services.knot-sync = { 330 enable = true; 331 secretsFile = config.age.secrets.github-knot-sync.path; 332 }; 333 334 services.n8n = { 335 enable = true; 336 environment = { 337 N8N_HOST = "n8n.dunkirk.sh"; 338 N8N_PROTOCOL = "https"; 339 WEBHOOK_URL = "https://n8n.dunkirk.sh"; 340 }; 341 }; 342 343 services.caddy.virtualHosts."n8n.dunkirk.sh" = { 344 extraConfig = '' 345 tls { 346 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 347 } 348 header { 349 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 350 } 351 reverse_proxy localhost:5678 { 352 header_up X-Forwarded-Proto {scheme} 353 header_up X-Forwarded-For {remote} 354 } 355 ''; 356 }; 357 358 boot.loader.systemd-boot.enable = true; 359 boot.loader.efi.canTouchEfiVariables = true; 360 boot.kernelParams = [ "console=ttyS0" ]; 361 362 system.stateVersion = "23.05"; 363}