Files
Anish Lakhwara d0cde973e7 box zfs
2026-01-19 22:37:30 -08:00

239 lines
7.1 KiB
Nix

# Disko configuration for box NAS
# NVMe boot drive with LUKS + 3x 4TB ZFS RAIDZ1 pool (~8TB usable)
# Unified encryption: LUKS passphrase unlocks root, ZFS uses keyfile inside encrypted root
#
# NOTE: Using RAIDZ1 (3 drives) temporarily due to DOA drive. Can migrate to RAIDZ2
# with 4 drives later by creating a new pool and copying data.
#
# Installation steps:
#
# 1. Generate the ZFS keyfile and LUKS password:
# dd if=/dev/urandom of=/tmp/tank.key bs=32 count=1
# echo -n "your-luks-password" > /tmp/luks-password
#
# 2. Run disko-install:
# sudo nix run 'github:nix-community/disko/latest#disko-install' -- \
# --flake ~/helm#box \
# --disk nvme /dev/disk/by-id/nvme-CT500P310SSD8_2544543B87C2 \
# --disk zfs1 /dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX32D954A2J7 \
# --disk zfs2 /dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX32D95FVZVL \
# --disk zfs3 /dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX42D95M807R
#
# 3. Copy the keyfile and update keylocation:
# sudo mkdir -p /mnt/etc/zfs
# sudo cp /tmp/tank.key /mnt/etc/zfs/tank.key
# sudo chmod 000 /mnt/etc/zfs/tank.key
# sudo zfs set keylocation=file:///etc/zfs/tank.key tank
{
disko.devices = {
disk = {
# Boot drive - 500GB NVMe with LUKS encryption
nvme = {
type = "disk";
device = "/dev/disk/by-id/nvme-placeholder"; # Override with --disk nvme /dev/disk/by-id/...
content = {
type = "gpt";
partitions = {
ESP = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
luks = {
size = "100%";
content = {
type = "luks";
name = "cryptroot";
settings = {
allowDiscards = true;
};
# Passphrase will be prompted during boot
passwordFile = "/tmp/luks-password"; # Only used during install, set this before running disko
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
mountOptions = [ "noatime" ];
};
};
};
};
};
};
# ZFS pool drives - 3x 4TB in RAIDZ1
zfs1 = {
type = "disk";
device = "/dev/disk/by-id/placeholder-zfs1"; # Override with --disk zfs1 /dev/disk/by-id/...
content = {
type = "gpt";
partitions = {
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "tank";
};
};
};
};
};
zfs2 = {
type = "disk";
device = "/dev/disk/by-id/placeholder-zfs2";
content = {
type = "gpt";
partitions = {
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "tank";
};
};
};
};
};
zfs3 = {
type = "disk";
device = "/dev/disk/by-id/placeholder-zfs3";
content = {
type = "gpt";
partitions = {
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "tank";
};
};
};
};
};
};
zpool = {
tank = {
type = "zpool";
mode = "raidz1";
options = {
ashift = "12";
cachefile = "none"; # Needed for disko
};
rootFsOptions = {
compression = "lz4";
atime = "off";
xattr = "sa";
acltype = "posixacl";
# ZFS native encryption
# During install: keyfile at /tmp/tank.key
# After install: install-box.sh copies to /etc/zfs/tank.key and updates keylocation
encryption = "aes-256-gcm";
keyformat = "raw";
keylocation = "file:///tmp/tank.key";
"com.sun:auto-snapshot" = "false";
};
# Don't mount the pool root directly
mountpoint = null;
datasets = {
# /nix is on the NVMe ext4 root, not on ZFS
# This simplifies boot dependencies - ZFS is purely for data storage
# Parent dataset for all data - inherits encryption
data = {
type = "zfs_fs";
options.mountpoint = "none";
};
# Media datasets
"data/media" = {
type = "zfs_fs";
options.mountpoint = "none";
};
"data/media/music" = {
type = "zfs_fs";
mountpoint = "/tank/media/music";
options.recordsize = "1M"; # Large files benefit from larger recordsize
};
"data/media/photos" = {
type = "zfs_fs";
mountpoint = "/tank/media/photos";
options.recordsize = "1M";
};
"data/media/movies" = {
type = "zfs_fs";
mountpoint = "/tank/media/movies";
options.recordsize = "1M";
};
"data/media/tv" = {
type = "zfs_fs";
mountpoint = "/tank/media/tv";
options.recordsize = "1M";
};
# Other data
"data/books" = {
type = "zfs_fs";
mountpoint = "/tank/books";
options."com.sun:auto-snapshot" = "true";
};
"data/podcasts" = {
type = "zfs_fs";
mountpoint = "/tank/podcasts";
};
"data/postgres" = {
type = "zfs_fs";
mountpoint = "/tank/postgres";
options = {
recordsize = "16K"; # Better for databases
"com.sun:auto-snapshot" = "true";
};
};
"data/syncthing" = {
type = "zfs_fs";
options.mountpoint = "none";
options."com.sun:auto-snapshot" = "true";
};
"data/syncthing/drawing" = {
type = "zfs_fs";
mountpoint = "/tank/syncthing/drawing";
};
"data/backup" = {
type = "zfs_fs";
mountpoint = "/tank/backup";
options."com.sun:auto-snapshot" = "true";
};
"data/ftp" = {
type = "zfs_fs";
mountpoint = "/tank/ftp";
};
"data/cache" = {
type = "zfs_fs";
mountpoint = "/tank/cache";
options."com.sun:auto-snapshot" = "false";
};
"data/playlists" = {
type = "zfs_fs";
mountpoint = "/tank/playlists";
};
"data/new-music" = {
type = "zfs_fs";
mountpoint = "/tank/new-music";
};
"data/archive" = {
type = "zfs_fs";
mountpoint = "/tank/archive";
options."com.sun:auto-snapshot" = "true";
};
};
};
};
};
}