Disko Layouts
This repository uses disko to declare host disk layouts.
Host Wiring
Disk layout selection happens in each host file through mkHost:
mkHost {
name = "example";
diskoDevice = "/dev/nvme0n1";
# Optional override; default is ../modules/disko/_boot-and-ext4.nix
diskoModule = ../disko/_learn-zfs.nix;
modules = [ ... ];
}
If diskoModule is not set, mkHost keeps using the default layout at modules/disko/_boot-and-ext4.nix.
Vinea learn-zfs Layout
Vinea now uses modules/disko/_learn-zfs.nix.
That layout is intentionally opinionated and more advanced:
- Pure UEFI boot: no BIOS boot partition.
- boot.initrd.systemd.enable = true.
- boot.loader.systemd-boot.enable = true.
- LVM volume group vg0 on the main disk.
- Logical volumes:
- / as ext4 (50G)
- /nix as ext4 (100G)
- /var/lib as XFS (50G)
- /home as LUKS-encrypted btrfs (remaining ~270G on the 500G disk)
- Three GPT partitions typed for ZFS (zfs1, zfs2, zfs3; 10G each), intentionally left empty.
Initializing Reserved ZFS Partitions Manually
The reserved ZFS partitions are created but not used by NixOS configuration. Initialize them manually when ready.
- Inspect partition names and paths:
ls -l /dev/disk/by-partlabel
- Confirm the three reserved partitions exist:
ls -l /dev/disk/by-partlabel/zfs1 /dev/disk/by-partlabel/zfs2 /dev/disk/by-partlabel/zfs3
- Example: initialize one partition as a simple pool:
sudo zpool create data /dev/disk/by-partlabel/zfs1
- Example: create datasets for large stateful workloads:
sudo zfs create -o mountpoint=/var/lib/containers data/containers
sudo zfs create -o mountpoint=/var/lib/libvirt/images data/vm-images
sudo zfs create -o mountpoint=/var/lib/postgresql data/postgresql
LUKS Encryption & Passphrase Flows
The /home partition layout on vinea (configured in _learn-zfs.nix) uses LUKS encryption (type = "luks") with Btrfs.
To enable automated formatting and installations, the layout declares:
passwordFile = "/tmp/luks.secret";
The passwordFile property tells disko where to read the decryption passphrase from during formatting and installation time. It is not used or baked into the system after it boots; at boot time, NixOS relies on the interactive console or keyfiles to unlock the drive.
Here is exactly how the /tmp/luks.secret file is populated and used depending on the target environment:
💻 Local VM Testing (with vmb)
When building and booting a local VM using the vmb tool:
- Passphrase Creation: The
vmbcommand automatically generates a temporary passphrase file on the host machine containing the dummy passwordx. - Injecting into Build Environment:
vmbcalls thediskoimage generation script using the--pre-format-filesflag. This copies the temporary host passphrase file into the build environment as/tmp/luks.secretbefore partitioning begins. - LUKS Formatting: The
diskolayout reads the dummy passphrasexfrom/tmp/luks.secretand formats the encrypted LUKS container on the virtual disk image. - Boot Decryption: At boot time, the initrd phase halts and prompts for the decryption passphrase (
crypt-home) on the QEMU graphical console. Because it was formatted withx, you click in the QEMU window, typex, and hitEnterto decrypt.
For step-by-step instructions on running this VM test, see the Testing in Virtual Machines tutorial.
🖥️ Bare-Metal Installation
When installing on physical hardware (e.g., using nixos-anywhere or the manual console installer):
- Passphrase Choice: Before running the installation, you (the administrator) choose your own secure target passphrase.
- Writing the Secret: On the target machine's installer environment (or inside the nixos-anywhere extra-files), you must manually create
/tmp/luks.secretcontaining your real passphrase:echo -n "my-real-secure-passphrase" > /tmp/luks.secret[!IMPORTANT] Make sure to use
echo -nto avoid writing a trailing newline into the password file, which would become part of your passphrase! - LUKS Formatting: When you run
diskoornixos-anywhere, the installation script reads/tmp/luks.secretand formats the LUKS container with your real passphrase. - Boot Decryption: Once the installation is complete and the system reboots, NixOS will prompt you on the physical console to input your secure passphrase at every boot to unlock
/home.
Updating or Changing Disko Layouts on Existing Hosts
[!WARNING] Running
nixos-rebuild switch --flake .#<host> --target-host <host> --sudo --ask-sudo-password(or similar) after modifying a host's Disko partition layout will completely break the target system.NixOS's
nixos-rebuildtries to mount new systems according to/etc/fstaband reload system services. However, it cannot dynamically re-partition or format mounted, active drives on a running system. Disko does not detect active layout mismatches to fail gracefully, which causes the rebuild process to crash, leaving filesystems unmounted and rendering the host unbootable.
Why is there no "force format" flag or option?
You might wonder if you can pass a flag to nixos-rebuild or add an option in Nix to force formatting. This is not supported due to two core constraints:
- Safety: Automatically formatting/partitioning during a rebuild would risk wiping your running system's data on a simple typo or configuration update.
- Kernel Limitations: The active operating system has
/and/nixmounted and in use. The Linux kernel will refuse to delete or re-partition active, mounted disk blocks.
Let Disko Wipe and Recreate
Because the disk layout cannot be changed on a running OS, the layout must be rewritten from outside the active system:
💻 For Virtual Machines (tested via vmb or QEMU)
If the host is a virtual machine, you do not need a live installer:
- Stop the VM.
- Delete the virtual disk image file (e.g.,
vinea.qcow2or similar) on the host machine. - Re-run your VM boot/build command (
vmbornix run .#vm). This will automatically trigger Disko to partition, format, and build a fresh disk image from scratch.
🖥️ For Physical Hosts / Bare-Metal
-
Boot into an Installer: Boot the target host from a NixOS installer environment (e.g. NixOS installation USB/ISO, or a netboot image).
-
Retrieve the Flake: Clone or pull your
nixfilesrepository onto the installer environment. -
Run the Disko Script: Each host configuration in this repository builds a custom
diskoScriptthat contains the layout, filesystem options, and disk overrides (e.g.,diskoDevice) configured for that specific host in the flake.
Build and execute the script directly from the flake:
# Build the diskoScript derivation for the target host (e.g., vinea)
script=$(nix build --print-out-paths --no-link .#nixosConfigurations.vinea.config.system.build.diskoScript)
# Execute the script to wipe partition tables, format disks, and mount everything
# WARNING: This will destroy all existing data on the configured disks!
sudo "$script"
- Proceed with Clean Install:
Once the script finishes, the new layout filesystems are mounted under
/mnt. You can then proceed withnixos-installor your standard provisioning flow.
Notes
- This layout assumes a reasonably large disk; adjust LV and partition sizes if needed.
/homeencryption uses LUKS managed through the systemd-based initrd flow./var/libwas chosen as the default location for containers, VM images, and database state.