default.nix (10186B)
1 # modules/hosts/generic/default.nix — NixDaemon for any machine: a PC, a 2 # laptop, or a VM, x86_64 or aarch64. 3 # 4 # sudo nixos-install --flake .#nixdaemon (from the installer) 5 # sudo nixos-rebuild switch --flake .#nixdaemon (afterwards) 6 # nh os switch -H nixdaemon (the same, with a diff) 7 # 8 # Everything you change lives in two files beside this one: 9 # _settings.nix user, hostname, arch, boot mode, VM, desktop, toolkit 10 # _hardware-configuration.nix your disks, from nixos-generate-config 11 # 12 # This host is deliberately separate from modules/hosts/laptop (the author's 13 # machine). It shares the toolkit (modules/features/pentest), the Niri desktop 14 # and the self-contained home modules, and none of the personal parts: no 15 # sops secrets, no private dotfiles checkout, no GPG/SSH identity, no fan or 16 # NVIDIA workarounds. It builds without anyone's keys. 17 # 18 # More than one machine? `self.lib.mkHost` takes a settings set, so a second 19 # host is one line: 20 # flake.nixosConfigurations.vm = self.lib.mkHost (import ./_settings.nix // { hostName = "vm"; vm = "qemu"; }); 21 # (it also needs its own hardware configuration — see mkHost's `hardware`.) 22 { self, inputs, ... }: 23 { 24 flake.lib.mkHost = 25 settings: 26 inputs.nixpkgs.lib.nixosSystem { 27 specialArgs = { 28 inherit inputs settings; 29 inherit (settings) user; 30 }; 31 modules = [ 32 (settings.hardware or ./_hardware-configuration.nix) 33 self.nixosModules.generic 34 ]; 35 }; 36 37 flake.nixosConfigurations.nixdaemon = self.lib.mkHost (import ./_settings.nix); 38 39 flake.nixosModules.generic = 40 { 41 config, 42 pkgs, 43 lib, 44 user, 45 settings, 46 ... 47 }: 48 let 49 s = settings; 50 niri = s.desktop == "niri"; 51 xfce = s.desktop == "xfce"; 52 i3 = s.desktop == "i3"; 53 gui = s.desktop != "none"; 54 in 55 { 56 imports = [ 57 inputs.home-manager.nixosModules.home-manager 58 self.nixosModules.pentest 59 ] 60 # desktop-options asserts that Hyprland or Niri is on, so it is only 61 # pulled in when Niri is the desktop. 62 ++ lib.optionals niri [ 63 self.nixosModules.desktop-options 64 self.nixosModules.desktop-niri 65 ] 66 # The X11 desktops for VMs without 3D (modules/features/desktop/). 67 ++ lib.optional xfce self.nixosModules.desktop-xfce 68 ++ lib.optional i3 self.nixosModules.desktop-i3; 69 70 config = lib.mkMerge [ 71 { 72 assertions = [ 73 { 74 assertion = builtins.elem s.desktop [ 75 "niri" 76 "xfce" 77 "i3" 78 "none" 79 ]; 80 message = "_settings.nix: desktop must be \"niri\", \"xfce\", \"i3\" or \"none\" (got \"${s.desktop}\")"; 81 } 82 { 83 assertion = builtins.elem s.vm [ 84 "none" 85 "vmware" 86 "virtualbox" 87 "qemu" 88 "hyperv" 89 ]; 90 message = "_settings.nix: vm must be none, vmware, virtualbox, qemu or hyperv (got \"${s.vm}\")"; 91 } 92 { 93 assertion = builtins.elem s.boot [ 94 "efi" 95 "bios" 96 ]; 97 message = "_settings.nix: boot must be \"efi\" or \"bios\" (got \"${s.boot}\")"; 98 } 99 { 100 # apktool pulls in aapt, which Google only ships for x86_64. 101 assertion = !(s.system == "aarch64-linux" && (s.pentest.mobile or false)); 102 message = "_settings.nix: pentest.mobile is x86_64-only (aapt); turn it off on aarch64"; 103 } 104 ]; 105 106 nixpkgs.hostPlatform = lib.mkDefault s.system; 107 nixpkgs.config.allowUnfree = true; # burpsuite, and the NVIDIA/VMware bits some machines need 108 109 ##### Boot ############################################################### 110 boot.loader = 111 if s.boot == "efi" then 112 { 113 systemd-boot.enable = true; 114 systemd-boot.configurationLimit = 20; 115 efi.canTouchEfiVariables = true; 116 } 117 else 118 { 119 grub.enable = true; 120 grub.device = s.biosDevice; 121 grub.configurationLimit = 20; 122 }; 123 124 ##### Machine ############################################################ 125 networking.hostName = s.hostName; 126 networking.networkmanager.enable = true; 127 time.timeZone = s.timeZone; 128 i18n.defaultLocale = s.locale; 129 services.xserver.xkb.layout = s.keyboard; 130 console.useXkbConfig = true; 131 132 users.users.${user} = { 133 isNormalUser = true; 134 extraGroups = [ 135 "networkmanager" 136 "wheel" 137 ] 138 # VirtualBox shared folders appear under /media/sf_<name> for this group. 139 ++ lib.optional (s.vm == "virtualbox" && (s.sharedFolders or false)) "vboxsf"; 140 shell = pkgs.zsh; 141 initialPassword = s.initialPassword; 142 openssh.authorizedKeys.keys = s.sshKeys; 143 }; 144 145 programs.zsh.enable = true; 146 programs.nix-ld.enable = true; # prebuilt binaries (uv pythons, npm, Go releases) 147 148 services.openssh = lib.mkIf s.ssh { 149 enable = true; 150 settings.PasswordAuthentication = false; 151 settings.PermitRootLogin = "no"; 152 }; 153 154 ##### Nix ################################################################ 155 nix.settings.experimental-features = [ 156 "nix-command" 157 "flakes" 158 ]; 159 programs.nh = { 160 enable = true; 161 flake = "/home/${user}/NixDaemon"; # where docs/install.md clones it 162 clean = { 163 enable = true; 164 dates = "weekly"; 165 extraArgs = "--keep 5 --keep-since 14d"; 166 }; 167 }; 168 environment.systemPackages = with pkgs; [ 169 git 170 nvd 171 nix-output-monitor 172 pciutils 173 usbutils 174 ]; 175 176 ##### Hypervisor guest tools ############################################# 177 virtualisation.vmware.guest.enable = s.vm == "vmware"; 178 virtualisation.virtualbox.guest.enable = s.vm == "virtualbox"; 179 virtualisation.hypervGuest.enable = s.vm == "hyperv"; 180 services.qemuGuest.enable = s.vm == "qemu"; 181 services.spice-vdagentd.enable = s.vm == "qemu"; # clipboard + resize in virt-manager/UTM 182 183 # VMware: open-vm-tools above gives time sync, clean shutdown, and — 184 # under X11 (xfce, i3) — clipboard and automatic resize. The SVGA 185 # adapter's 3D needs Mesa's vmwgfx driver, hence graphics on. 186 hardware.graphics.enable = lib.mkIf (s.vm == "vmware" && gui) true; 187 # Host folders shared in VMware's settings, at /mnt/hgfs/<name>. 188 fileSystems."/mnt/hgfs" = lib.mkIf (s.vm == "vmware" && (s.sharedFolders or false)) { 189 device = ".host:/"; 190 fsType = "fuse./run/current-system/sw/bin/vmhgfs-fuse"; 191 options = [ "umask=22" "uid=1000" "gid=100" "allow_other" "auto_unmount" "defaults" "nofail" "x-systemd.automount" ]; 192 }; 193 194 ##### Desktop ############################################################ 195 196 services.greetd = lib.mkIf niri { 197 enable = true; 198 useTextGreeter = true; 199 settings.default_session.command = lib.concatStringsSep " " [ 200 "${pkgs.tuigreet}/bin/tuigreet" 201 "--time" 202 "--remember" 203 "--remember-session" 204 "--asterisks" 205 "--sessions ${config.services.displayManager.sessionData.desktops}/share/wayland-sessions" 206 ]; 207 }; 208 209 210 security.polkit.enable = lib.mkIf gui true; 211 services.udisks2.enable = lib.mkIf gui true; 212 services.gnome.gnome-keyring.enable = lib.mkIf gui true; 213 programs.dconf.enable = lib.mkIf gui true; 214 services.pulseaudio.enable = false; 215 security.rtkit.enable = lib.mkIf gui true; 216 services.pipewire = lib.mkIf gui { 217 enable = true; 218 alsa.enable = true; 219 pulse.enable = true; 220 }; 221 222 environment.sessionVariables = lib.mkIf niri { 223 ELECTRON_OZONE_PLATFORM_HINT = "auto"; 224 NIXOS_OZONE_WL = "1"; 225 }; 226 227 fonts.packages = with pkgs; [ 228 nerd-fonts.jetbrains-mono # the terminal font (kitty, below) 229 noto-fonts 230 noto-fonts-color-emoji 231 ]; 232 233 ##### Toolkit ############################################################ 234 daemon.pentest = { 235 enable = true; 236 # BloodHound CE's pinned neo4j is published for x86_64 only. 237 bloodhound.enable = lib.mkDefault (s.system == "x86_64-linux"); 238 } 239 // lib.mapAttrs (_: on: { enable = on; }) s.pentest; 240 241 ##### Home ############################################################### 242 home-manager = { 243 useGlobalPkgs = true; 244 useUserPackages = true; 245 backupFileExtension = "hm-bak"; 246 extraSpecialArgs = { inherit inputs user; }; 247 users.${user} = self.homeModules.generic; 248 }; 249 250 system.stateVersion = "26.05"; 251 } 252 253 # optionalAttrs, not mkIf: daemon.desktop is only declared when Niri 254 # imports desktop-options above, and mkIf still needs the option to exist. 255 (lib.optionalAttrs niri { 256 daemon.desktop = { 257 hyprland.enable = false; # Hyprland's home side needs the author's dotfiles 258 niri.enable = true; 259 # The neutral desktop (no author location/wallpaper/font), with 260 # this machine's keyboard layout. 261 niri.package = self.legacyPackages.${s.system}.mkNiri { 262 noctaliaPkg = self.packages.${s.system}.noctalia; 263 xkb.layout = s.keyboard; 264 }; 265 }; 266 }) 267 ]; 268 }; 269 }