mirror of
				https://github.com/ItsDrike/nixdots
				synced 2025-11-04 13:26:35 +00:00 
			
		
		
		
	Update installation guide
This commit is contained in:
		
							parent
							
								
									a6cf555b00
								
							
						
					
					
						commit
						718a55f595
					
				
					 1 changed files with 92 additions and 74 deletions
				
			
		
							
								
								
									
										166
									
								
								INSTALLATION.md
									
										
									
									
									
								
							
							
						
						
									
										166
									
								
								INSTALLATION.md
									
										
									
									
									
								
							| 
						 | 
					@ -62,18 +62,6 @@ btrfs subvolume create /mnt/nix
 | 
				
			||||||
btrfs subvolume create /mnt/log
 | 
					btrfs subvolume create /mnt/log
 | 
				
			||||||
btrfs subvolume create /mnt/persist
 | 
					btrfs subvolume create /mnt/persist
 | 
				
			||||||
btrfs subvolume create /mnt/data
 | 
					btrfs subvolume create /mnt/data
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
We will now take a read-only snapshot of the root subvolume.
 | 
					 | 
				
			||||||
This snapshot will be eventually used for rolling back to on every boot (impermanence).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```shell
 | 
					 | 
				
			||||||
btrfs subvolume snapshot -r /mnt/root /mnt/root-blank
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
And finally, we can unmount the btrfs root.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```shell
 | 
					 | 
				
			||||||
umount /mnt
 | 
					umount /mnt
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -226,7 +214,11 @@ fileSystems."/" =
 | 
				
			||||||
### Subvolumes needed for boot
 | 
					### Subvolumes needed for boot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In order to correctly persist `/var/log`, the respective subvolume need to be mounted early enough in
 | 
					In order to correctly persist `/var/log`, the respective subvolume need to be mounted early enough in
 | 
				
			||||||
the boot process. To do this, we will want to add `neededForBoot = true;`, so the entry will look like this:
 | 
					the boot process. To do this, we will want to add `neededForBoot = true;`. Additionally, we will also
 | 
				
			||||||
 | 
					need to add this parameter for our `/persisr` subvolume. This is because we will be storing the user
 | 
				
			||||||
 | 
					password (including root password) in a password file there (mentioned later on).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					So the entries will look like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```nix
 | 
					```nix
 | 
				
			||||||
fileSystems."/var/log" =
 | 
					fileSystems."/var/log" =
 | 
				
			||||||
| 
						 | 
					@ -235,10 +227,14 @@ fileSystems."/var/log" =
 | 
				
			||||||
      options = [ "subvol=log" "noatime" "compress=zstd:3" ];
 | 
					      options = [ "subvol=log" "noatime" "compress=zstd:3" ];
 | 
				
			||||||
      neededForBoot = true;
 | 
					      neededForBoot = true;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Additionally, we will also need to add `neededForBoot = true;` to our `/persist` subvolume. This is because
 | 
					fileSystems."/persist" =
 | 
				
			||||||
we will be storing the root users password file in there.
 | 
					    { device = "/dev/disk/by-label/NIXFS";
 | 
				
			||||||
 | 
					      fsType = "btrfs";
 | 
				
			||||||
 | 
					      options = [ "subvol=persist" "noatime" "compress=zstd:3" ];
 | 
				
			||||||
 | 
					      neededForBoot = true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Minimal config
 | 
					## Minimal config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -310,12 +306,11 @@ screen. Log in as root, set your password (`passwd itsdrike`), log out and re-lo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This is an optional step, if you don't want your root partition to get auto-reset on each boot, you can simply skip this.
 | 
					This is an optional step, if you don't want your root partition to get auto-reset on each boot, you can simply skip this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Auto-restore root-blank snapshot
 | 
					### Auto-wipe root partition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Remember how we create the empty snapshot of our root subvolume? Well now comes the time when we put it to use. We will
 | 
					To reset the root subvolume on every boot, we can simply delete it and create a new one in its place. We will be doing
 | 
				
			||||||
restore this snapshot from initrd, which runs in a temporary file-system, before our actual file-system is even mounted.
 | 
					this from initrd, which runs in a temporary file-system, before the actual file-system is properly mounted (following
 | 
				
			||||||
This makes it a perfect place to run a script which will restore our root subvolume to the blank snapshot before each
 | 
					fstab). This makes it a perfect place to run a script, which will wipe the root subvolume before each boot.
 | 
				
			||||||
boot.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
I will set this up using a systemd-based initrd, because I will need systemd for TPM unlocking later on. If you don't
 | 
					I will set this up using a systemd-based initrd, because I will need systemd for TPM unlocking later on. If you don't
 | 
				
			||||||
care about that, it is also possible to do this without systemd. You can a guide for such setup
 | 
					care about that, it is also possible to do this without systemd. You can a guide for such setup
 | 
				
			||||||
| 
						 | 
					@ -338,41 +333,37 @@ boot.initrd.systemd = {
 | 
				
			||||||
    unitConfig.DefaultDependencies = "no";
 | 
					    unitConfig.DefaultDependencies = "no";
 | 
				
			||||||
    serviceConfig.Type = "oneshot";
 | 
					    serviceConfig.Type = "oneshot";
 | 
				
			||||||
    script = ''
 | 
					    script = ''
 | 
				
			||||||
      mkdir -p /mnt
 | 
					      # Mount the BTRFS root to /mnt so we can manipulate btrfs subvolumes
 | 
				
			||||||
 | 
					      mount --mkdir /dev/mapper/cryptfs /mnt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # We first mount the btrfs root to /mnt
 | 
					      # Simply deleting a subvolume with btrfs subvolume delete will not work,
 | 
				
			||||||
      # so we can manipulate btrfs subvolumes.
 | 
					      # if that subvolume contains other btrfs subvolumes. Because of that, we
 | 
				
			||||||
      mount /dev/mapper/cryptfs /mnt
 | 
					      # instead use this function to delete subvolumes, whihc will first perform
 | 
				
			||||||
 | 
					      # a recursive deletion of any nested subvolumes.
 | 
				
			||||||
      # While we're tempted to just delete /root and create
 | 
					 | 
				
			||||||
      # a new snapshot from /root-blank, /root is already
 | 
					 | 
				
			||||||
      # populated at this point with a number of subvolumes,
 | 
					 | 
				
			||||||
      # which makes `btrfs subvolume delete` fail.
 | 
					 | 
				
			||||||
      # So, we remove them first.
 | 
					 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      # /root contains subvolumes:
 | 
					      # This is necessary, because the root subvolume will actually usually contain
 | 
				
			||||||
      # - /root/var/lib/portables
 | 
					      # other subvolumes, even if the user haven't created those explicitly. It seems
 | 
				
			||||||
      # - /root/var/lib/machines
 | 
					      # that NixOS creates these automatically. Namely, I observed these in root subvol:
 | 
				
			||||||
      #
 | 
					      # - root/srv
 | 
				
			||||||
      # These are probably related to systemd-nspawn, but
 | 
					      # - root/var/lib/portables
 | 
				
			||||||
      # since I don't use it, I'm not 100% sure.
 | 
					      # - root/var/lib/machines
 | 
				
			||||||
      # Anyhow, deleting these subvolumes hasn't resulted in
 | 
					      # - root/var/tmp
 | 
				
			||||||
      # any issues so far, except for fairly benign-looking
 | 
					      delete_subvolume_recursively() {
 | 
				
			||||||
      # errors from systemd-tmpfiles.
 | 
					        IFS=$'\n'
 | 
				
			||||||
      btrfs subvolume list -o /mnt/root |
 | 
					        for x in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
 | 
				
			||||||
        cut -f9 -d' ' |
 | 
					          delete_subvolume_recursively "/mnt/$x"
 | 
				
			||||||
        while read subvolume; do
 | 
					        done
 | 
				
			||||||
          echo "deleting /$subvolume subvolume..."
 | 
					 | 
				
			||||||
          btrfs subvolume delete "/mnt/$subvolume"
 | 
					 | 
				
			||||||
        done &&
 | 
					 | 
				
			||||||
        echo "deleting /root subvolume..." &&
 | 
					 | 
				
			||||||
        btrfs subvolume delete /mnt/root
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      echo "restoring blank /root subvolume..."
 | 
					        echo "Deleting subvolume $1"
 | 
				
			||||||
      btrfs subvolume snapshot /mnt/root-blank /mnt/root
 | 
					        btrfs subvolume delete "$1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Once we're done rolling back to a blank snapshot,
 | 
					      # Recreate the root subvolume
 | 
				
			||||||
      # we can unmount /mnt and continue on the boot process.
 | 
					      delete_subvolume_recursively "/mnt/root"
 | 
				
			||||||
 | 
					      echo "Re-creating root subvolume"
 | 
				
			||||||
 | 
					      btrfs subvolume create "/mnt/root"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # we can now unmount /mnt and continue on the boot process.
 | 
				
			||||||
      umount /mnt
 | 
					      umount /mnt
 | 
				
			||||||
    '';
 | 
					    '';
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
| 
						 | 
					@ -407,12 +398,6 @@ in
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
    files = [
 | 
					    files = [
 | 
				
			||||||
      "/etc/machine-id"
 | 
					      "/etc/machine-id"
 | 
				
			||||||
 | 
					 | 
				
			||||||
      # ssh stuff
 | 
					 | 
				
			||||||
      "/etc/ssh/ssh_host_ed25519_key"
 | 
					 | 
				
			||||||
      "/etc/ssh/ssh_host_ed25519_key.pub"
 | 
					 | 
				
			||||||
      "/etc/ssh/ssh_host_rsa_key"
 | 
					 | 
				
			||||||
      "/etc/ssh/ssh_host_rsa_key.pub"
 | 
					 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -422,6 +407,21 @@ in
 | 
				
			||||||
    "L /var/lib/NetworkManager/seen-bssids - - - - /persist/system/var/lib/NetworkManager/seen-bssids"
 | 
					    "L /var/lib/NetworkManager/seen-bssids - - - - /persist/system/var/lib/NetworkManager/seen-bssids"
 | 
				
			||||||
    "L /var/lib/NetworkManager/timestamps - - - - /persist/system/var/lib/NetworkManager/timestamps"
 | 
					    "L /var/lib/NetworkManager/timestamps - - - - /persist/system/var/lib/NetworkManager/timestamps"
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Define host key paths in the persistent mount point instead of using impermanence for these.
 | 
				
			||||||
 | 
					  # This works better, because these keys also get auto-created if they don't already exist.
 | 
				
			||||||
 | 
					  services.openssh.hostKeys = mkForce [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      bits = 4096;
 | 
				
			||||||
 | 
					      path = "/persist/system/etc/ssh/ssh_host_rsa_key";
 | 
				
			||||||
 | 
					      type = "rsa";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      bits = 4096;
 | 
				
			||||||
 | 
					      path = "/persist/system/etc/ssh/ssh_host_ed25519_key";
 | 
				
			||||||
 | 
					      type = "ed25519";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -436,23 +436,25 @@ Note that with impermanence, your user passwords will get erased too (with the `
 | 
				
			||||||
you can create password files, which will contain the password hashes for each user:
 | 
					you can create password files, which will contain the password hashes for each user:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					```shell
 | 
				
			||||||
mkpasswd -m sha-512 > /persist/system/passwords/root
 | 
					mkdir -p /persist/passwords
 | 
				
			||||||
mkpasswd -m sha-512 > /persist/system/passwords/itsdrike
 | 
					chmod 700 /persist/passwords
 | 
				
			||||||
 | 
					mkpasswd -m sha-512 > /persist/passwords/root
 | 
				
			||||||
 | 
					mkpasswd -m sha-512 > /persist/passwords/itsdrike
 | 
				
			||||||
 | 
					chmod 600 /persist/passwords/*
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
And declare these in our `configuration.nix` or `impermanence.nix`
 | 
					And declare these in our `configuration.nix` or `impermanence.nix`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```nix
 | 
					```nix
 | 
				
			||||||
users = {
 | 
					users = {
 | 
				
			||||||
  # This option makes it that users are not mutable outside our configuration
 | 
					  # This option makes it that users are not mutable outside of our configuration.
 | 
				
			||||||
  # If you are using impermanence, this will actually be the case regardless of this setting,
 | 
					  # If you're using root impermanence, this will actually be the case regardless
 | 
				
			||||||
  # however, setting this explicitly is a good idea, because nix will warn us if
 | 
					  # of this setting, however, setting this explicitly is a good idea, because nix
 | 
				
			||||||
  # our users don't have passwords set
 | 
					  # will warn us if our users don't have passwords set, preventing lock outs.
 | 
				
			||||||
  mutableUsers = false;
 | 
					  mutableUsers = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Each existing user needs to have a password file defined here
 | 
					  # Each existing user needs to have a password file defined here, otherwise
 | 
				
			||||||
  # otherwise, they will not be available to login.
 | 
					  # they will not be available to login. These password files can be generated with:
 | 
				
			||||||
  # These password files can be generated using the following command:
 | 
					 | 
				
			||||||
  # mkpasswd -m sha-512 > /persist/passwords/myuser
 | 
					  # mkpasswd -m sha-512 > /persist/passwords/myuser
 | 
				
			||||||
  users = {
 | 
					  users = {
 | 
				
			||||||
    root = {
 | 
					    root = {
 | 
				
			||||||
| 
						 | 
					@ -601,7 +603,6 @@ The resulting file should then look something like this:
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  imports = [
 | 
					  imports = [
 | 
				
			||||||
    ./hardware-configuration.nix
 | 
					    ./hardware-configuration.nix
 | 
				
			||||||
    ./impermanence.nix
 | 
					 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  boot.supportedFilesystems = [ "btrfs" ];
 | 
					  boot.supportedFilesystems = [ "btrfs" ];
 | 
				
			||||||
| 
						 | 
					@ -625,6 +626,21 @@ The resulting file should then look something like this:
 | 
				
			||||||
    system = {
 | 
					    system = {
 | 
				
			||||||
      hostname = "anduril";
 | 
					      hostname = "anduril";
 | 
				
			||||||
      username = "itsdrike";
 | 
					      username = "itsdrike";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      impermanence = {
 | 
				
			||||||
 | 
					        root = {
 | 
				
			||||||
 | 
					          enable = true;
 | 
				
			||||||
 | 
					          # Some people use /nix/persist/system for this, leaving persistent files in /nix subvolume
 | 
				
			||||||
 | 
					          # I much prefer using a standalone subvolume for this though.
 | 
				
			||||||
 | 
					          persistentMountPoint = "/persist";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Configure automatic root subvolume wiping on boot from initrd
 | 
				
			||||||
 | 
					        autoWipeBtrfs = {
 | 
				
			||||||
 | 
					          enable = true;
 | 
				
			||||||
 | 
					          devices."/dev/disk/by-label/NIXROOT".subvolumes = [ "root" ];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    device = {
 | 
					    device = {
 | 
				
			||||||
      virtual-machine = false;
 | 
					      virtual-machine = false;
 | 
				
			||||||
| 
						 | 
					@ -646,12 +662,14 @@ The resulting file should then look something like this:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!WARNING]
 | 
					> [!NOTE]
 | 
				
			||||||
> I'm currently working on making impermanence config in my flake directly. This will mean you will eventually be
 | 
					> You may notice that this configuration also includes custom options for impermanence,
 | 
				
			||||||
> expected to just enable impermanence through myOptions. Right now, the config above includes `impermanence.nix`
 | 
					> and that the impermanence.nix is no longer declared in imports. This is because my
 | 
				
			||||||
> that we have enabled earlier. This will work, however note that flakes are a bit stricter with fetchTarball, and
 | 
					> flake already contains a fully custom support (mostly similar to what I've shown here)
 | 
				
			||||||
> require a sha256 hash to be specified. You can specify it, or use the `--impure` flag for now. Once impermanence
 | 
					> to handle impermanence. This allows me to re-use this impermanence across multiple
 | 
				
			||||||
> will be integrated into my flake, it will be handled as an input, and you won't have to worry about anything.
 | 
					> machines very easily.
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					> You can now therefore delete the `impermanence.nix` file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Commit and switch
 | 
					### Commit and switch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue