Disko Integration
Disko provides a declarative way to partition and format disks with nix.
This module provides some pre-tested disko examples, which can be imported and re-used across hosts.
Most of the disko profiles only define root disk setups.
Module Options Reference for provision.fs.disko
Usage
You can use preconfigured disko profiles in your NixOS configurations:
bcachefs
is supported, but should definitely treated as experimental, I have had a few issues / errors with it, and have been able to recover so far, but I do not recommend storing any important data with it. Stick to ZFS for important data.
Simple unencrypted btrfs
Unencrypted btrfs with GPT with ESP (UEFI support), vfat /boot
partition.
provision.fs = {
btrfs.enable = true; # enable extra tools etc.
disko.devices.root = {
device = "/dev/nvme0n1"; # set device to install root on
profile = "btrfs-simple-uefi";
# `btrfs-simple-uefi` supports `extraDatasets` to extend profile's datasets
args.extraDatasets = {
"@lib" = {
mountpoint = "/var/lib";
mountOptions = ["compress=zstd"];
};
};
};
};
Native encrypted bcachefs root
Native encrypted bcachefs with GPT with ESP (UEFI support), unencrypted vfat /boot
.
provision.fs = {
btrfs.enable = true; # enable extra tools etc.
disko.devices.nvme = {
profile = "bcachefs-encrypted-uefi";
device = "/dev/disk/by-id/nvme-Samsung_SSD_970_PRO_1TB_SERIAL_NUMBER";
args.rootName = "bcachefs";
};
};
LUKS encrypted Ext4 root
Luks encrypted /
Ext4 with GPT with ESP (UEFI support), unencrypted vfat /boot
.
provision.fs.disko.devices.root = {
device = "/dev/sda";
profile = "ext4-luks-bios-uefi";
args.bootEnd = "1G"; # args can be used to override arguments from the profile
args.iter-time = 10000;
};
Profiles
Below is a reference of the current disko profiles.
Ext4 + UEFI: ext4-simple-uefi
- GPT partition table
/boot
: vfat (ESP)/
: Ext4
# included from ./ext4-simple-uefi.nix
{
device ? "/dev/vda",
diskName ? "root",
bootSize ? "1G",
...
}:
{
disko.devices.disk.${diskName} = {
inherit device;
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
type = "EF00";
size = bootSize;
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
}
Ext4 + UEFI + BIOS: ext4-simple-bios-uefi
- GPT partition table
- Grub MBR partition
/boot
: vfat (ESP)/
: Ext4
# included from ./ext4-simple-bios-uefi.nix
{
device ? "/dev/mmcblk0",
diskName ? "main",
bootStart ? "1M",
bootEnd ? "1G",
luksSize ? "100%",
...
}:
{
disko.devices.disk.${diskName} = {
type = "disk";
inherit device;
content = {
type = "gpt";
partitions = {
boot = {
priority = 1;
start = "0";
end = bootStart;
type = "EF02"; # for grub MBR
};
ESP = {
priority = 2;
start = bootStart;
end = bootEnd;
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
start = bootEnd;
end = luksSize;
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
}
Ext4 + LUKS + UEFI + BIOS: ext4-luks-bios-uefi
- GPT partition table
- Grub MBR partition
/boot
: vfat (ESP)/
: LUKS encrypted Ext4
# included from ./ext4-luks-bios-uefi.nix
{
device ? "/dev/vda",
diskName ? "root",
bootEnd ? "350M",
luksEnd ? "100%",
iter-time ? 3000, # in ms
key-size ? 512,
cipher ? "aes-xts-plain64",
...
}:
let
root = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
# luks container in partition 2
crypted-root = {
type = "luks";
name = "crypted-root";
extraOpenArgs = [ "--allow-discards" ];
# this is expected to be present at boot
# settings.keyFile = "/tmp/root-luks.key";
settings.allowDiscards = true;
extraFormatArgs = [
"--iter-time ${toString iter-time}"
"--hash sha256"
"--cipher ${cipher}"
"--key-size ${toString key-size}"
];
# required using na-install script during nixos-anywhere installation
# when using luks
passwordFile = "/tmp/root-luks.key";
content = root;
};
in
{
## GPT Bios Compatible
disko.devices.disk.${diskName} = {
type = "disk";
inherit device;
content = {
type = "gpt";
partitions = {
boot = {
name = "boot";
size = "1M";
type = "EF02";
};
esp = {
name = "ESP";
size = bootEnd;
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
luks = {
name = "luks";
size = luksEnd;
content = crypted-root;
};
};
};
};
}
Bcachefs + native encryption + UEFI: bcachefs-encrypted-uefi
- GPT partition table
/boot
: vfat (ESP)/
: Bcachefs (native encryption)
# included from ./bcachefs-encrypted-uefi.nix
{
device ? "/dev/vda",
diskName ? "nvme",
rootName ? "root",
# is somewhat for compat
bootEnd ? "1G",
luksSize ? "100%",
encrypted ? true,
compression ? "zstd",
# set to empty to skip
acl ? true,
discard ? true,
lib,
...
}:
let
bootStart = "1MiB";
in
{
disko.devices.disk.${diskName} = {
type = "disk";
inherit device;
content = {
type = "gpt";
partitions = {
ESP = {
priority = 2;
start = bootStart;
end = bootEnd;
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
name = rootName;
size = luksSize;
content = {
type = "filesystem";
format = "bcachefs";
extraArgs = lib.flatten [
(lib.optionalString encrypted "--encrypted")
(lib.optionalString (compression != "") "--compression=${compression}")
(lib.optionalString acl "--acl")
(lib.optionalString discard "--discard")
];
mountpoint = "/";
};
};
};
};
};
}
Bcachefs + LUKS + UEFI: bcachefs-luks-uefi
- GPT partition table
/boot
: vfat (ESP)/
: LUKS encrypted bcachefs
# included from ./bcachefs-luks-uefi.nix
{
device ? "/dev/vda",
diskName ? "nvme",
rootName ? "crypted-root",
# is somewhat for compat
bootEnd ? "1G",
luksSize ? "100%",
luksName ? "luks",
# name of luks container
# luks opts
keyFile ? "",
# if set, this key file is expected at boot i.g. "/tmp/root-luks.key"
passwordFile ? "",
# during nixos-anywhere install, this file on the installing host to use as a LUKS passphrase
iterTime ? 10000,
# 10s iter time
hash ? "sha256",
cipher ? "aes-xts-plain64",
keySize ? 512,
useRandom ? true,
# bcachefs opts
compression ? "zstd",
# set to empty to skip
acl ? true,
discard ? true,
lib,
...
}:
let
inherit (lib) mkIf optional;
bootStart = "1M";
root = {
type = "filesystem";
format = "bcachefs";
mountpoint = "/";
extraArgs = lib.flatten [
(lib.optionalString (compression != "") "--compression=${compression}")
(lib.optionalString acl "--acl")
(lib.optionalString discard "--discard")
];
};
in
{
## GPT Bios Compatible UEFI
disko.devices.disk.${diskName} = {
type = "disk";
inherit device;
content = {
type = "gpt";
partitions = {
boot = {
priority = 1;
size = bootStart;
type = "EF02";
};
ESP = {
priority = 2;
size = bootEnd;
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
${luksName} = {
size = luksSize;
content = {
type = "luks";
name = rootName;
# extraOpenArgs = [ "--allow-discards" ];
# this is expected to be present at boot
settings.keyFile = mkIf (keyFile != "") keyFile;
settings.allowDiscards = mkIf discard true;
extraFormatArgs = [
"--iter-time ${toString iterTime}"
"--hash ${hash}"
"--cipher ${cipher}"
"--key-size ${toString keySize}"
] ++ (optional useRandom "--use-random");
# required using na-install script during nixos-anywhere installation
# when using luks
passwordFile = mkIf (passwordFile != "") passwordFile;
content = root;
};
};
};
};
};
}
ZFS mirror + LUKS: zfs-mirror-luks
- 2 disks
- not designed as root FS
- GPT partition tables
/<pool>
: LUKS with ZFS on mirrored drives
# included from ./zfs-mirror-luks.nix
{
disks ? [
"/dev/vda1"
"/dev/vda2"
],
## LUKS options
# LUKS password file
passwordFile ? "/tmp/secret.key",
# LUKS extra format arguments
extraFormatArgs ? [
"--iter-time 10000"
"--hash sha512"
"--cipher aes-xts-plain64"
"--key-size 512"
],
## ZFS Options
pool ? "mymirror",
mountpoint ? "/${pool}",
# ZFS options
options ? {
ashift = "13";
autotrim = "on";
},
# ZFS root FS options
rootFsOptions ? {
compression = "zstd";
"com.sun:auto-snapshot" = "false";
recordsize = "1M";
xattr = "sa";
relatime = "on";
acltype = "posixacl";
dnodesize = "auto";
},
datasets ? {
mydataset = {
type = "zfs_fs";
mountpoint = "/${pool}/mydataset";
};
},
...
}:
{
disko.devices = {
## ZFS Pool Setup
zpool.${pool} = {
type = "zpool";
mode = "mirror";
inherit
datasets
mountpoint
options
rootFsOptions
;
};
## Physical Disk Layout
disk = {
"${pool}-disk0" = {
type = "disk";
device = builtins.elemAt disks 0;
content = {
inherit passwordFile extraFormatArgs;
type = "luks";
name = "${pool}-crypted0";
content = {
inherit pool;
type = "zfs";
};
};
};
"${pool}-disk1" = {
type = "disk";
device = builtins.elemAt disks 1;
content = {
inherit passwordFile extraFormatArgs;
type = "luks";
name = "${pool}-crypted1";
content = {
inherit pool;
type = "zfs";
};
};
};
};
};
}
Btrfs + UEFI: btrfs-simple-uefi
- GPT partition table
/boot
: vfat (ESP)/
: btrfs
# included from ./btrfs-simple-uefi.nix
{
device ? "/dev/vda",
diskName ? "root",
bootStart ? "1M",
bootSize ? "1G",
# btrfs opts
extraDatasets ? {
# allows overriding default subvolume layout
"@snapshots" = {
mountpoint = "/snapshots";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@containers" = {
mountpoint = "/containers";
mountOptions = [ "noatime" ];
};
},
...
}:
let
# btrfs filesystem inside luks container
btrfs = {
type = "btrfs";
extraArgs = [ "--label nixos" ];
subvolumes = {
"@" = {
mountpoint = "/";
mountOptions = [ "noatime" ];
};
"@nix" = {
mountpoint = "/nix";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@home" = {
mountpoint = "/home";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@log" = {
mountpoint = "/var/log";
mountOptions = [ "noatime" ];
};
} // extraDatasets;
};
in
{
disko.devices.disk.${diskName} = {
inherit device;
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
type = "EF00";
size = bootSize;
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = btrfs;
};
};
};
};
}
Btrfs + LUKS + UEFI: btrfs-luks-uefi
- GPT partition table
/boot
: vfat (ESP)/
: LUKS encrypted btrfs
# included from ./btrfs-luks-uefi.nix
{
device ? "/dev/vda",
diskName ? "root",
rootName ? "crypted-root",
bootStart ? "1M",
bootEnd ? "1G",
luksSize ? "100%",
luksName ? "luks",
# name of luks container
# luks opts
keyFile ? "",
# if set, this key file is expected at boot i.g. "/tmp/root-luks.key"
passwordFile ? "",
# during nixos-anywhere install, this file on the installing host to use as a LUKS passphrase
iterTime ? 10000,
# 10s iter time
hash ? "sha256",
cipher ? "aes-xts-plain64",
keySize ? 512,
useRandom ? true,
discard ? true,
# btrfs opts
extraDatasets ? {
"@snapshots" = {
mountpoint = "/snapshots";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@containers" = {
mountpoint = "/containers";
mountOptions = [ "noatime" ];
};
},
lib,
...
}:
let
inherit (lib) mkIf optional;
# btrfs filesystem inside luks container
root = {
type = "btrfs";
extraArgs = [ "--label nixos" ];
subvolumes = {
"@" = {
mountpoint = "/";
mountOptions = [ "noatime" ];
};
"@nix" = {
mountpoint = "/nix";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@home" = {
mountpoint = "/home";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@log" = {
mountpoint = "/var/log";
mountOptions = [ "noatime" ];
};
} // extraDatasets;
};
in
{
disko.devices.disk.${diskName} = {
type = "disk";
inherit device;
content = {
type = "gpt";
partitions = {
ESP = {
priority = 2;
start = bootStart;
end = bootEnd;
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
${luksName} = {
size = luksSize;
content = {
type = "luks";
name = rootName;
# extraOpenArgs = [ "--allow-discards" ];
# this is expected to be present at boot
settings.keyFile = mkIf (keyFile != "") keyFile;
settings.allowDiscards = mkIf discard true;
extraFormatArgs = [
"--iter-time ${toString iterTime}"
"--hash ${hash}"
"--cipher ${cipher}"
"--key-size ${toString keySize}"
] ++ (optional useRandom "--use-random");
# required using na-install script during nixos-anywhere installation
# when using luks
passwordFile = mkIf (passwordFile != "") passwordFile;
content = root;
};
};
};
};
};
}