logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·02.11.26
← Back to news

How to Build a Minimal ZFS NAS Without Synology, QNAP, TrueNAS (2024)

Original article
neil.computer|301 points|207 comments|by 4diii|Jul 8, 2026

Guide: Constructing a Minimalist ZFS NAS (2024 Edition)

Avoiding the Bloat of Synology, QNAP, and TrueNAS

If your goal is a straightforward Network Attached Storage (NAS) and you have no need for a complex Graphical User Interface (GUI), setting up a ZFS dataset and sharing it via Samba is remarkably simple.


🎯 Scope & System Requirements

The following specifications define the environment used for this build.

ComponentSpecification
RAID LevelRAIDZ1 (Single Drive Redundancy)
Operating SystemDebian 12 Bookworm
EncryptionEnabled None
ZFS VersionOpenZFS, zfs-2.1.1
CPU4 Cores (Cheap Xeon Server CPUs recommended)
RAM16 GB ECC RDIMM
Storage4 x 4TB NVMe SSDs
BackupsNot covered (Suggested: ZFS Backup Scheduler)
Skill LevelBeginner / Easy

Note: This guide serves as personal documentation for future reference, but it is open for anyone to adapt for their own hardware.


🧠 The Philosophy: Why Minimalist?

Many users gravitate toward TrueNAS because it is marketed as an enterprise-grade software suite. While powerful, it often introduces a mismatch between the user's actual needs and the provided features.

The core motivations for this approach are:

  1. Simplicity: Avoiding "bells and whistles" that add complexity without value.
  2. Knowledge: Building a system where you understand every single configuration point.
  3. Independence: Reducing reliance on third-party management layers.

🌟 The "Hidden" Superpower of ZFS

There is a critical feature of ZFS that is rarely highlighted: The filesystem is entirely self-contained.

All configuration data and pool metadata are stored directly on the disks. This means:

  • If your OS drive is nuked, your data remains safe.
  • You can move your disks to a completely different machine.
  • Simply install ZFS on the new host and run zfs import to recover everything.

Whether you have a RAIDZ2 (RAID 6) with 6 disks or a simple mirror, the disks carry their own identity. As long as the physical hardware is intact, your data is portable.


🛠️ Step 1: Disk Identification and Organization

First, identify the available drives on your Linux system using the following command:

lsblk -d -o TRAN,NAME,TYPE,MODEL,SERIAL,SIZE

Example Output:

[root@sys ~]# lsblk -d -o TRAN,NAME,TYPE,MODEL,SERIAL,SIZE 
TRAN NAME TYPE MODEL SERIAL SIZE 
sda disk Virtual disk 40G 
nvme nvme5n1 disk Samsung SSD 990 PRO 4TB XXXXXXXXXXXXXXX 3.6T 
nvme nvme2n1 disk Samsung SSD 990 PRO 4TB XXXXXXXXXXXXXXX 3.6T 
nvme nvme6n1 disk Samsung SSD 990 PRO 4TB XXXXXXXXXXXXXXX 3.6T 
nvme nvme3n1 disk Samsung SSD 990 PRO 4TB XXXXXXXXXXXXXXX 3.6T 

Mapping via Disk IDs

To avoid issues where drive letters (like sda or nvme0n1) change after a reboot or hardware swap, we use the unique IDs found in /dev/disk/by-id.

[root@sys ~]# ls -lh /dev/disk/by-id 
total 0 
lrwxrwxrwx. 1 root root 10 May 10 09:34 dm-name-rhel-root -> ../../dm-0 
lrwxrwxrwx. 1 root root 10 May 10 09:34 dm-name-rhel-swap -> ../../dm-1 
lrwxrwxrwx. 1 root root 13 May 10 09:34 nvme-Samsung_SSD_990_PRO_4TB_XXXXX -> ../../nvme2n1 
lrwxrwxrwx. 1 root root 13 May 10 09:34 nvme-Samsung_SSD_990_PRO_4TB_XXXXX -> ../../nvme5n1 
lrwxrwxrwx. 1 root root 13 May 10 09:34 nvme-Samsung_SSD_990_PRO_4TB_XXXXX -> ../../nvme3n1 
lrwxrwxrwx. 1 root root 13 May 10 09:34 nvme-Samsung_SSD_990_PRO_4TB_XXXXX -> ../../nvme6n1 

Creating Friendly Aliases (Optional)

You can create a mapping file at /etc/zfs/vdev_id.conf to give these long IDs shorter aliases:

# Edit the config file
[root@sys ~]# vim /etc/zfs/vdev_id.conf 

# Add the following mappings:
alias nvme0 /dev/disk/by-id/nvme-Samsung_SSD_990_PRO_4TB_XXXXXXXXXXXXXXX 
alias nvme1 /dev/disk/by-id/nvme-Samsung_SSD_990_PRO_4TB_XXXXXXXXXXXXXXX 
alias nvme2 /dev/disk/by-id/nvme-Samsung_SSD_990_PRO_4TB_XXXXXXXXXXXXXXX 
alias nvme3 /dev/disk/by-id/nvme-Samsung_SSD_990_PRO_4TB_XXXXXXXXXXXXXXX 

After saving, apply the changes: udevadm trigger

Verification: ls -lh /dev/disk/by-vdev should now show your aliases (nvme0, nvme1, etc.) pointing to the correct physical disks.

Pro Tip: While aliases are convenient for setup, they are not required for the pool to function. If you lose your vdev_id.conf file, ZFS still knows which disks belong to the pool because it uses the hardware serial numbers.


🏗️ Step 2: Creating the ZPOOL

For this build, we are implementing RAIDZ1, which allows for the failure of one drive without data loss.

Installation

Install the ZFS tools. On RHEL 9, for example: dnf install zfs

The Importance of ashift

When creating the pool, you must set the ashift value. This defines the sector size. Many modern SSDs (like the Samsung 990 Pro) use 4KB sectors, but report 512B for compatibility.

Using LaTeX to represent the calculation: ashift=12  ⟹  212=4096 bytes (4KB)\text{ashift} = 12 \implies 2^{12} = 4096 \text{ bytes (4KB)}ashift=12⟹212=4096 bytes (4KB)

Setting ashift=12 is critical for performance; if you miss this step during creation, you cannot change it later without destroying the pool.

Execution

# Verify aliases
[root@sys ~]# ls /dev/disk/by-vdev 
nvme0 nvme1 nvme2 nvme3 

# Create the pool (s16z1 = 16TB total raw, RAIDZ1)
[root@sys ~]# zpool create -o ashift=12 s16z1 raidz1 nvme0 nvme1 nvme2 nvme3 

# Check the status
[root@sys ~]# zpool status s16z1 

Expected Status Output:

pool: s16z1 
state: ONLINE 
config: 
NAME        STATE     READ WRITE CKSUM 
s16z1       ONLINE       0     0     0 
  raidz1-0  ONLINE       0     0     0 
    nvme0   ONLINE       0     0     0 
    nvme1   ONLINE       0     0     0 
    nvme2   ONLINE       0     0     0 
    nvme3   ONLINE       0     0     0 
errors: No known data errors 

📊 Summary Visualization

Data Architecture

Final Checklist

  • Install OpenZFS
  • Identify disks via /dev/disk/by-id
  • (Optional) Setup vdev_id.conf
  • Create pool with ashift=12
  • Verify zpool status