# 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"; }; }; }; }; }; }