Create ZFS pool (two drives mirrored)
The following example shows how to create a root ZFS filesystem, mirrored on two identical NVME drives.
Find the model name and serial numbers of your drives:
lsblk -o NAME,SIZE,MODEL,SERIALNAME SIZE MODEL SERIAL
loop0 1.3G
nvme0n1 3.6T CT4000P3PSSD8 1234567890AA
nvme1n1 3.6T CT4000P3PSSD8 1234567890ABIdentify the stable device path of the drives. (Don’t use /dev/nvme*
use /dev/disk/by-id/*) :
ls -ld /dev/disk/by-id/*lrwxrwxrwx 1 root root 13 Jan 11 16:22 /dev/disk/by-id/nvme-CT4000P3PSSD8_1234567890AA -> ../../nvme1n1
lrwxrwxrwx 1 root root 13 Jan 11 16:22 /dev/disk/by-id/nvme-CT4000P3PSSD8_1234567890AA_1 -> ../../nvme1n1
lrwxrwxrwx 1 root root 13 Jan 11 16:22 /dev/disk/by-id/nvme-CT4000P3PSSD8_1234567890BB -> ../../nvme0n1
lrwxrwxrwx 1 root root 13 Jan 11 16:22 /dev/disk/by-id/nvme-CT4000P3PSSD8_1234567890BB_1 -> ../../nvme0n1
...- The symbolic device id you want is of the format
/dev/disk/by-id/nvme-{MODEL}-{SERIAL}(without the_1part.) - Make sure the symbolic link points to the correct device reported
by
lsblk.
Set two temporary variables DISK1 and DISK2 to reference them:
export DISK1=/dev/disk/by-id/nvme-CT4000P3PSSD8_1234567890AA
export DISK2=/dev/disk/by-id/nvme-CT4000P3PSSD8_1234567890ABWipe the drives and create new UEFI and ZFS partitions:
(
set -euo pipefail
: "${DISK1:?DISK1 is not set}"
: "${DISK2:?DISK2 is not set}"
for d in "$DISK1" "$DISK2"; do
blkdiscard -f "$d" || true
sgdisk --zap-all "$d"
wipefs -a "$d" || true
sgdisk -n1:1MiB:+1GiB -t1:EF00 -c1:EFI "$d"
sgdisk -n2:0:0 -t2:BF00 -c2:ZFS "$d"
partprobe "$d"
udevadm settle
done
mkfs.fat -F 32 -n EFI1 "${DISK1}-part1"
mkfs.fat -F 32 -n EFI2 "${DISK2}-part1"
)Verify with lsblk that the new partitions have been created
correctly:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 3.6T 0 disk
├─nvme0n1p1 259:5 0 1G 0 part
└─nvme0n1p2 259:6 0 3.6T 0 part
nvme1n1 259:1 0 3.6T 0 disk
├─nvme1n1p1 259:3 0 1G 0 part
└─nvme1n1p2 259:4 0 3.6T 0 partCreate the mirrored ZFS pool:
(
set -euo pipefail
modprobe zfs
zpool create -f \
-o ashift=12 \
-o autotrim=on \
-O mountpoint=none \
-O compression=zstd \
-O atime=off \
-O xattr=sa \
-O acltype=posixacl \
-O normalization=formD \
rpool mirror "${DISK1}-part2" "${DISK2}-part2"
zpool status
)Create datasets. We’ll use mountpoint=legacy so NixOS mounts them
declaratively:
(
set -euo pipefail
zfs create -o mountpoint=none -o canmount=off rpool/root
zfs create -o mountpoint=legacy -o canmount=noauto rpool/root/nixos
zfs create -o mountpoint=legacy rpool/nix
zfs create -o mountpoint=legacy rpool/home
zfs create -o mountpoint=legacy rpool/var
zfs create -o mountpoint=legacy rpool/var/log
zpool set bootfs=rpool/root/nixos rpool
)Mount all the filesystems under /mnt, including the two UEFI boot
partitions:
(
set -euo pipefail
mount -t zfs rpool/root/nixos /mnt
mkdir -p /mnt/{nix,home,var}
mount -t zfs rpool/nix /mnt/nix
mount -t zfs rpool/home /mnt/home
mount -t zfs rpool/var /mnt/var
mkdir -p /mnt/var/log
mount -t zfs rpool/var/log /mnt/var/log
mkdir -p /mnt/{boot,boot-fallback}
mount "${DISK1}-part1" /mnt/boot
mount "${DISK2}-part1" /mnt/boot-fallback
)