diff --git a/README.md b/README.md index 8879e7f..1f6aef3 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ My NixOS configuration. -## Usage +## Installation -Clone the repository to some directory. And build with `sudo nixos-rebuild switch --flake /directory/containing/flake.nix/`. \ No newline at end of file +For disk configuration we use disko, this means that installing the system from the configuration is just a single command: + +``` +sudo nix --experimental-features "nix-command flakes" run "github:nix-community/disko/latest#disko-install" -- --flake git+https://git.bulthuis.dev/Jan/dotfiles# --disk main /dev/sda +``` \ No newline at end of file diff --git a/flake.lock b/flake.lock index cd645d1..cab0620 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,25 @@ { "nodes": { + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748225455, + "narHash": "sha256-AzlJCKaM4wbEyEpV3I/PUq5mHnib2ryEy32c+qfj6xk=", + "owner": "nix-community", + "repo": "disko", + "rev": "a894f2811e1ee8d10c50560551e50d6ab3c392ba", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { @@ -54,6 +74,21 @@ "type": "github" } }, + "impermanence": { + "locked": { + "lastModified": 1737831083, + "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, "nix-minecraft": { "inputs": { "flake-compat": "flake-compat", @@ -114,7 +149,9 @@ }, "root": { "inputs": { + "disko": "disko", "home-manager": "home-manager", + "impermanence": "impermanence", "nix-minecraft": "nix-minecraft", "nix-modpack": "nix-modpack", "nixpkgs": "nixpkgs" diff --git a/flake.nix b/flake.nix index 131919f..bcd520d 100644 --- a/flake.nix +++ b/flake.nix @@ -2,9 +2,15 @@ description = "System configuration for NixOS"; inputs = { + # General inputs nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; home-manager.url = "github:nix-community/home-manager"; home-manager.inputs.nixpkgs.follows = "nixpkgs"; + disko.url = "github:nix-community/disko"; + disko.inputs.nixpkgs.follows = "nixpkgs"; + impermanence.url = "github:nix-community/impermanence"; + + # For Minecraft VM nix-minecraft.url = "github:Jan-Bulthuis/nix-minecraft"; nix-minecraft.inputs.nixpkgs.follows = "nixpkgs"; nix-modpack.url = "github:Jan-Bulthuis/nix-modpack"; diff --git a/modules/home/utilities/impermanence.nix b/modules/home/utilities/impermanence.nix new file mode 100644 index 0000000..336549a --- /dev/null +++ b/modules/home/utilities/impermanence.nix @@ -0,0 +1,35 @@ +{ lib, config, ... }: + +with lib; +let + cfg = config.modules.impermanence; +in +{ + options.modules.impermanence = { + enable = mkEnableOption "Impermanence"; + directories = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + Directories that should be stored in persistent storage. + ''; + }; + files = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + Files that should be stored in persistent storage. + ''; + }; + }; + + config = mkIf cfg.enable { + home.persistence."/persist/home/${config.home.username}" = { + enable = true; + hideMounts = true; + allowOther = true; + directories = cfg.directories; + files = cfg.files; + }; + }; +} diff --git a/modules/nixos/disko.nix b/modules/nixos/disko.nix new file mode 100644 index 0000000..dbdbc36 --- /dev/null +++ b/modules/nixos/disko.nix @@ -0,0 +1,24 @@ +{ + lib, + config, + inputs, + ... +}: + +with lib; +let + cfg = config.modules.disko; + profile = import "${inputs.self}/profiles/disko/${cfg.profile}.nix"; +in +{ + options.modules.disko = { + enable = mkEnableOption "Disko module"; + profile = mkOption { + type = types.str; + default = null; + description = "The profile to use for the disko module."; + }; + }; + + config = mkIf cfg.enable { disko.devices = profile.disko.devices; }; +} diff --git a/modules/nixos/impermanence.nix b/modules/nixos/impermanence.nix new file mode 100644 index 0000000..9983ae5 --- /dev/null +++ b/modules/nixos/impermanence.nix @@ -0,0 +1,46 @@ +{ lib, config, ... }: + +with lib; +let + cfg = config.modules.impermanence; +in +{ + options.modules.impermanence = { + enable = mkEnableOption "Impermanence"; + directories = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + Directories that should be stored in persistent storage. + ''; + }; + files = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + Files that should be stored in persistent storage. + ''; + }; + resetScript = mkOption { + type = types.lines; + description = '' + Script to run on boot that resets the root partition. + ''; + }; + }; + + config = mkIf cfg.enable { + fileSystems."/persist".neededForBoot = true; + boot.initrd.postResumeCommands = mkAfter cfg.resetScript; + + # For home-manager persistence + programs.fuse.userAllowOther = true; + + environment.persistence."/persist/system" = { + enable = true; + hideMounts = true; + directories = cfg.directories; + files = cfg.files; + }; + }; +} diff --git a/profiles/disko/vm.nix b/profiles/disko/vm.nix new file mode 100644 index 0000000..2035785 --- /dev/null +++ b/profiles/disko/vm.nix @@ -0,0 +1,56 @@ +{ + disko.devices = { + disk = { + main = { + type = "disk"; + content = { + type = "gpt"; + partitions = { + boot = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + zfs = { + size = "100%"; + content = { + type = "zfs"; + pool = "tank"; + }; + }; + }; + }; + }; + }; + zpool = { + tank = { + type = "zpool"; + rootFsOptions = { + compression = "zstd"; + }; + mountpoint = null; + postCreateHook = "zfs snapshot -r tank@blank && zfs hold -r blank tank@blank"; + + datasets = { + root = { + type = "zfs_fs"; + mountpoint = "/"; + }; + nix = { + type = "zfs_fs"; + mountpoint = "/nix"; + }; + persist = { + type = "zfs_fs"; + mountpoint = "/persist"; + }; + }; + }; + }; + }; +} diff --git a/profiles/nixos/base.nix b/profiles/nixos/base.nix index 36955f6..dfc9b73 100644 --- a/profiles/nixos/base.nix +++ b/profiles/nixos/base.nix @@ -19,6 +19,14 @@ in modules = { bootloader.enable = mkDefault true; ssh.enable = mkDefault true; + + # Setup sensible default persistent data + impermanence.directories = [ + "/var/lib/nixos" + ]; + impermanence.files = [ + "/etc/shadow" + ]; }; # Localization diff --git a/profiles/nixos/vm.nix b/profiles/nixos/vm.nix index 8a52ff6..b4fdd8e 100644 --- a/profiles/nixos/vm.nix +++ b/profiles/nixos/vm.nix @@ -19,14 +19,26 @@ in # Enabled modules modules = { profiles.base.enable = true; + disko = { + enable = true; + profile = "vm"; + }; + impermanence = { + enable = true; + resetScript = '' + # Revert to the blank state for the root directory + zfs rollback -r tank/root@blank + ''; + }; ssh.enable = true; }; # Admin users users.users.local = { + initialPassword = "local"; extraGroups = [ "wheel" ]; openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKKxoQSxfYqf9ITN8Fhckk8WbY4dwtBAXOhC9jxihJvq jan@bulthuis.dev" + "ssh-ed25519 jan@bulthuis.dev" ]; }; @@ -36,6 +48,9 @@ in # Machine platform nixpkgs.hostPlatform = "x86_64-linux"; + # Set hostid for ZFS + networking.hostId = "deadbeef"; + # Hardware configuration hardware.enableRedistributableFirmware = true; boot.initrd.availableKernelModules = [ @@ -51,21 +66,6 @@ in boot.extraModulePackages = [ ]; hardware.cpu.intel.updateMicrocode = true; - # Filesystems - fileSystems."/" = { - device = "/dev/disk/by-partlabel/root"; - fsType = "ext4"; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-partlabel/EFI"; - fsType = "vfat"; - options = [ - "fmask=0077" - "dmask=0077" - ]; - }; - # Swapfile swapDevices = [ {