LUNAROPS · OPERATIONAL UPLINK 100% UPTIME 1,247d POSTS 893 JEFF.MOON@LUNAROPS.DEV UTC --:--:--

TrueNAS SCALE Deep Dive

truenaszfsstoragenassmbnfsiscsihomelab

TrueNAS SCALE has matured from an experimental Linux-based challenger into a serious production NAS platform. If you run a homelab with meaningful storage requirements, or if you manage a small-to-medium storage environment at work and want something that does not cost a fortune in licensing, SCALE is worth understanding deeply. This post is not a “click here, click there” UI walkthrough. It is a systems-level treatment of how TrueNAS SCALE actually works — where ZFS fits in, how to design pools you will not regret, how to configure block and file protocols properly, and how to keep the whole thing running reliably over years.

I have run TrueNAS SCALE in production across several environments, from 4-drive homelab rigs to 12-drive enterprise-adjacent setups. The rough edges are real. So is the power.


TrueNAS SCALE vs CORE: Choosing Your Base

The first question most people hit is CORE vs SCALE. Both share the same ZFS heart, but the platform underneath them is entirely different.

TrueNAS CORE runs on FreeBSD. It has been the production-grade option for years, and the SMB stack — which runs atop Samba compiled against FreeBSD’s kernel primitives — is mature and extremely well-tested for Windows environments. CORE’s jails and plugins system is simpler than SCALE’s app ecosystem, though it is also more limited. If you are primarily doing SMB file serving to Windows clients in a conservative environment and want the most battle-hardened platform, CORE is still a defensible choice.

TrueNAS SCALE runs on Debian Linux. This matters for several reasons: it gets OpenZFS releases faster than CORE does (Linux is OpenZFS’s primary development target), the Linux ecosystem means Docker-native app deployment, and hardware support for newer network cards and storage controllers is generally better. The SMB stack is also Samba, but on Linux, and historically there have been subtle SMB behavioral differences that CORE users noticed when migrating. Those gaps have mostly closed.

Current versions as of this writing: TrueNAS SCALE 25.10 “Goldeye” is the current general availability release (as of May 2026), built on OpenZFS 2.3. TrueNAS 25.04 “Fangtooth” remains the conservative recommendation for those who want a fully-matured release. The older 24.10 “ElectricEel” is archived but still sees maintenance updates. TrueNAS 26 is in early beta and introduces a simplified annual versioning scheme, dropping the fish-name convention.

The practical summary: if you are starting fresh and care about the app ecosystem, Linux tooling, or want RAIDZ expansion (more on that below), run SCALE. If you are running a legacy SMB environment and your current CORE system is working perfectly, do not fix what is not broken.


Hardware: What Actually Matters for ZFS

Before you write a single configuration line, your hardware choices determine whether ZFS will be a rock-solid foundation or a slow-motion disaster.

ECC RAM is non-negotiable in production. ZFS is designed to detect and repair data corruption through its end-to-end checksumming model, but that model assumes the data flowing through RAM is correct. A bit flip in non-ECC RAM can write silently corrupted data to disk and ZFS will checksum it faithfully — making the corruption look legitimate. For a NAS storing data you care about, ECC is not optional. The cost delta on modern AMD Ryzen Pro or Xeon platforms is modest. Do not cheap out here.

RAM sizing for ARC: The general rule of thumb is 1 GB of RAM per 1 TB of raw storage, with a practical minimum of 8 GB. This is not a hard requirement — ZFS will function below this — but it gives the Adaptive Replacement Cache (ARC) enough headroom to be meaningful. A 64 TB pool with only 8 GB of RAM means the ARC is tiny relative to your data, and cache hit rates will be low for anything but the hottest data. For a NAS used as a Proxmox datastore or active file server, more RAM is always better. 32–64 GB is a comfortable working range for most serious homelab builds.

HBA vs RAID controller: ZFS must see individual disk drives. It does its own redundancy. If you hand it a hardware RAID controller presenting a virtual disk, ZFS cannot read SMART data, cannot replace failed drives properly, and the entire resilvering model breaks. You need an HBA — a Host Bus Adapter — that passes drives through to the OS without any RAID abstraction. Common choices are the LSI SAS 9207-8i or 9300-8i. If you have a RAID controller, you will need to reflash it to “IT mode” (initiator-target mode), which disables the RAID firmware and converts it to a pure HBA. This is a documented process for most LSI-based cards and is worth doing.

CMR vs SMR drives: Conventional Magnetic Recording (CMR) drives write data directly to a location on the disk. Shingled Magnetic Recording (SMR) drives overlap tracks to increase density, which means writes must be buffered and re-written in large sequential chunks. SMR drives are poison for ZFS. The ZFS COW write pattern constantly writes to new locations across the disk, which on an SMR drive triggers massive write amplification and fills the SMR buffer, causing the drive to halt for minutes at a time while it internally reorganizes data. SMR is fine for cold archival storage with long sequential writes. It is completely unsuitable for a ZFS pool under any active workload. Check the manufacturer’s specifications carefully — some drives that look like NAS-grade CMR are SMR. WD Red (non-Plus) was a notorious example.

SLOG (ZFS Intent Log): The ZIL (ZFS Intent Log) is where synchronous writes are logged before being committed to the main pool. By default the ZIL lives on the pool itself. Adding a dedicated SLOG device — an NVMe with power loss protection (PLN) — offloads synchronous write latency from the spinning drives and can dramatically improve NFS/iSCSI performance for workloads that request sync=always. The SLOG device must have power loss protection; consumer NVMe drives that lack a supercapacitor or have no flush guarantee are not suitable. Intel Optane, or enterprise NVMe like the Samsung PM9A3, are appropriate. Note that SLOG does not speed up asynchronous writes. If your workload is async (most home file transfers are), a SLOG provides no benefit.

L2ARC: A secondary ARC tier on SSD. L2ARC extends your read cache beyond what fits in RAM. The honest assessment is that L2ARC is rarely worth it in a homelab context: it consumes ARC RAM to maintain its own index (roughly 70 bytes of RAM per 512 bytes of L2ARC content), adds overhead on pool import (the L2ARC index must be rebuilt), and only helps if your working set is genuinely larger than RAM and you have a read-heavy workload with good locality. If you are streaming video from a single NAS, your working set at any moment is one file. L2ARC does nothing for you. If you are running a build server with hundreds of developers hitting the same source trees, maybe. For most readers of this post: skip L2ARC, buy more RAM instead.


ZFS Pool Design: Getting It Right the First Time

Pool design decisions are permanent in ways that matter. Ashift is set at creation and cannot be changed without destroying the pool. vdev types are fixed once written. You can add vdevs to a pool (growing capacity) but you cannot change a RAIDZ2 to a RAIDZ3 without rebuilding. Spend time here.

vdev Types

Pool vdev types at a glance:

  mirror       2+ drives, N-way mirror, lose N-1 drives safely
  RAIDZ1       3+ drives, 1 parity disk equivalent, 1 drive loss
  RAIDZ2       4+ drives, 2 parity disks equivalent, 2 drive loss
  RAIDZ3       5+ drives, 3 parity disks equivalent, 3 drive loss
  dRAID        New in OpenZFS 2.1: distributed spare integrated
               into the vdev, faster resilvering than RAIDZ
  special       Metadata-only vdev (fast SSD), reduces fragmentation
  dedup         Dedicated dedup table vdev, rarely needed in practice
  log (SLOG)    Synchronous write log device
  cache (L2ARC) Read cache extension
vdev Type Min Drives Drive Fault Tolerance Usable Capacity Random IOPS Resilver Risk
Mirror (2-way) 2 1 drive 50% Excellent (reads scale) Low
Mirror (3-way) 3 2 drives 33% Excellent Very Low
RAIDZ1 3 1 drive (N-1)/N Moderate High (large drives)
RAIDZ2 4 2 drives (N-2)/N Moderate Moderate
RAIDZ3 5 3 drives (N-3)/N Moderate Low
dRAID2 6+ 2 drives + hot spare Variable Moderate Very Low

The IOPS characteristics deserve emphasis. A 2-way mirror pool with four drives (two mirrors striped) delivers four drives worth of read IOPS and two drives worth of write IOPS. A RAIDZ2 pool with six drives delivers approximately six drives worth of sequential throughput but random write IOPS are constrained because every write must update parity across all drives in the vdev. For a NAS doing large sequential transfers (video, backups, file copies), RAIDZ2 is excellent. For a database or VM datastore with heavy random I/O, mirrors win by a wide margin.

The “never RAIDZ1 with large drives” rule is about Unrecoverable Read Error (URE) probability. Modern enterprise drives specify a URE rate of roughly 1 in 10^15 bits read. A 16 TB drive contains about 1.4 x 10^14 bits. During a resilver of a failed drive, every bit on every surviving drive is read. With RAIDZ1, if a single URE occurs on any surviving drive during resilver, the entire pool is unrecoverable. At 16 TB per drive with 5 drives in a RAIDZ1, the probability of hitting a URE during resilver is approaching 50%. With RAIDZ2, you need two simultaneous UREs, which is vanishingly unlikely. Use RAIDZ2 as your minimum for drives 4 TB and above.

The sweet spot argument: A stripe of two RAIDZ2 vdevs, each with 4–6 drives, is the most common recommendation for a general-purpose NAS pool. You get good capacity efficiency (75–80% usable with 6-drive vdevs), resilience against two drive failures per vdev, decent sequential throughput from the stripe, and manageable resilver times. Twelve drives in a single RAIDZ2 is an antipattern — resilver time grows with pool size, and you have more data at risk.

RAIDZ Expansion: OpenZFS 2.3 and TrueNAS Fangtooth+

As of OpenZFS 2.3 (shipped with TrueNAS SCALE 25.04 Fangtooth), RAIDZ expansion is finally available. This lets you add one drive to an existing RAIDZ vdev, expanding its capacity without destroying and recreating it. A 6-drive RAIDZ2 can become a 7-drive RAIDZ2. The process (“reflow”) rewrites all data to incorporate the new drive, which takes time proportional to pool fullness. TrueNAS contributed a 5x performance improvement to the reflow algorithm in OpenZFS 2.3.0.

This is a game-changer for capacity planning — you no longer need to predict exactly how many drives you will need at pool creation. However, it only expands a single vdev. You cannot change the RAIDZ level. A RAIDZ2 stays RAIDZ2 after expansion. The TrueNAS SCALE UI in 25.04+ exposes this under Storage > Manage Devices > Extend Vdev.

Ashift

Ashift is the minimum block allocation size for the pool, expressed as a power of 2. Ashift=9 means 512-byte sectors (2^9). Ashift=12 means 4096-byte sectors (2^12). Modern drives — essentially all drives larger than 2 TB and many smaller ones — use 4096-byte physical sectors internally, even if they present a 512-byte logical interface. Writing to a drive with physical 4K sectors using 512-byte allocations causes read-modify-write cycles that tank performance and cause extra wear.

Always set ashift=12 for modern drives. Some newer high-capacity drives and certain NVMe have 8192-byte (8K) native sectors; for those, ashift=13 is appropriate. Check with smartctl -a /dev/sdX | grep "Sector Sizes" before creating your pool.

TrueNAS SCALE will attempt to auto-detect ashift, but verify it. Once the pool is created, ashift cannot be changed.

Typical Homelab Pool Layout

Pool: data (stripe of two RAIDZ2 vdevs + 1 mirror special vdev)
|
+-- vdev0: RAIDZ2
|     sda  (drive 0)
|     sdb  (drive 1)
|     sdc  (drive 2)
|     sdd  (drive 3)
|     sde  (drive 4)
|     sdf  (drive 5)
|
+-- vdev1: RAIDZ2
|     sdg  (drive 6)
|     sdh  (drive 7)
|     sdi  (drive 8)
|     sdj  (drive 9)
|     sdk  (drive 10)
|     sdl  (drive 11)
|
+-- special: mirror (metadata vdev)
|     nvme0n1  (NVMe 0)
|     nvme1n1  (NVMe 1)
|
+-- log: nvme2n1  (SLOG, power-loss-protected NVMe)

The special vdev holds metadata and small files, dramatically reducing fragmentation on the spinning drives and improving performance for workloads with many small files. It must be redundant (mirror) because loss of the special vdev destroys the pool. Do not use a single device for special.

Spare vdevs

TrueNAS supports designating drives as pool-level hot spares. When a drive fails, ZFS can automatically begin resilvering to the spare. Hot spares are a nice feature to have in a larger deployment, but they do not replace the importance of RAIDZ2 redundancy — a spare only helps after a failure is detected, and detection can take hours if you are not monitoring closely. In a homelab context, a spare sitting on a shelf is often more practical than a hot spare configured in the pool.


Dataset Hierarchy and Properties

The ZFS namespace under a pool is where you make decisions that affect day-to-day storage behavior. Getting the hierarchy right saves you from ugly workarounds later.

Dataset vs Zvol

Datasets are ZFS filesystems. They appear as directories and are the backing storage for SMB and NFS shares. Datasets inherit properties from parents, support snapshots, and are the right tool for file-based access.

Zvols are ZFS block volumes. They present as raw block devices and are the backing storage for iSCSI LUNs. They also have snapshots. Everything that a dataset can do, a zvol can do in the block world. Use datasets for shares. Use zvols for iSCSI.

Property Inheritance

Dataset properties cascade from parent to children unless explicitly overridden. This is your friend if you use it deliberately, and a footgun if you set properties at the wrong level.

The recommended dataset structure for a general-purpose build:

pool
 └── data
      ├── shares          (SMB + NFS shares live here)
      │    ├── media
      │    ├── documents
      │    └── backups
      ├── vms             (zvols for iSCSI LUNs live here)
      └── encrypted       (separate dataset with native ZFS encryption)

Creating a separate encrypted dataset (rather than encrypting the entire pool) lets you unlock it independently and means the pool can import without immediately decrypting sensitive data. If you encrypt the root of the pool, you need the passphrase at every pool import.

Dataset Properties Reference

Property Recommended Value Notes
compression lz4 or zstd Always enable compression. lz4 is near-zero CPU cost, zstd gives better ratios at higher CPU
recordsize 128K (default) Good for general file shares; 16K for databases; 1M for media/large sequential
atime off Eliminates a write on every file read; almost always the right call
sync standard Leave standard for most workloads; sync=always for databases or iSCSI with no SLOG
xattr sa Stores extended attributes in inodes rather than hidden files; much faster for Samba
acltype nfsv4 Required for proper Windows ACL inheritance on SMB shares
casesensitivity insensitive Needed for Windows SMB compatibility; cannot be changed after creation
dedup off Dedup has very high RAM requirements (DDT lives in RAM); almost never worth it for general use
copies 1 Increase to 2 only for extremely important single-copy data without a pool-level mirror

Compression notes: Enable lz4 everywhere by default — the compression ratio for typical data (documents, logs, source code) is 2:1 to 3:1 with essentially zero CPU overhead. For a cold-storage dataset containing already-compressed files (video, JPEG, ZIP), use lz4 anyway — it will detect incompressible data quickly and skip compression. Use zstd on datasets where you want better ratio and can afford the CPU: backups, archives, deduplicated content, text-heavy datasets. zstd-3 is a reasonable midpoint between ratio and speed.

Recordsize and workload matching is probably the most important tuning decision after compression. The default 128K is a solid general-purpose choice. For a dataset backing PostgreSQL or MySQL, set recordsize=16K to match the database’s typical I/O unit. For a dataset storing video or large archive files, setting recordsize=1M allows ZFS to read and write in larger chunks, improving sequential throughput significantly. Recordsize can be changed after creation, but existing data retains its old recordsize until it is rewritten.


SMB Shares: Windows File Serving Done Right

TrueNAS SCALE’s Samba implementation is solid. The rough edge is ACL configuration — it is easy to end up with a share that looks correct in the UI but behaves wrong from a Windows client.

ACL Types: Choose Before You Start

TrueNAS SCALE supports two ACL paradigms: POSIX and NFSv4. The critical rule: set the ACL type on the dataset before creating the share, before writing any files, and do not change it later. Changing ACL type on a dataset with existing data corrupts permissions.

  • NFSv4 ACLs are required for full Windows ACL behavior: inheritance, fine-grained permissions (read-only vs modify vs full control), and proper ACL propagation from folders to subfolders. If you are serving Windows clients and users are setting permissions through Windows Explorer, you must use NFSv4 ACLs.
  • POSIX ACLs are simpler and work fine for Unix-to-Unix sharing, or for shares where you only need basic read/write/execute control. Joining an Active Directory domain with POSIX ACLs works but the Windows ACL editor will not behave as Windows users expect.

Set the dataset property before anything else:

1
2
zfs set acltype=nfsv4 data/shares/documents
zfs set xattr=sa data/shares/documents

In the TrueNAS UI, when creating a dataset for an SMB share, select “SMB” as the share type and the UI handles both properties automatically.

SMB Configuration Essentials

Enable the SMB service under Services. Create the dataset, create the share pointing to the dataset path. The TrueNAS SMB share form has a number of options worth understanding:

Shadow Copies (VSS): Enable this if users are on Windows and you want them to be able to right-click > Restore Previous Versions. TrueNAS wires VSS to the ZFS snapshot list for that dataset. Users can browse snapshots directly through Windows Explorer without any admin intervention. This feature alone is worth running TrueNAS for Windows environments.

Apple Time Machine: TrueNAS can present an SMB share as a Time Machine target. Enable “Time Machine” on the share, set a quota, and macOS discovers it automatically via Bonjour/mDNS. Works well.

Oplocks: Opportunistic locks allow clients to cache file data locally for performance. Enabled by default. If you have legacy apps that do not handle oplocks correctly (some older Windows apps have bugs), you may need to disable them, but this is rare.

Multichannel SMB3: If your NAS has multiple NICs and clients are on Windows 10/11 or Server 2012+, enabling SMB Multichannel aggregates bandwidth across multiple network paths. Configure this in the SMB Service settings under Advanced. Each additional 10 GbE NIC adds another ~1 GB/s of potential throughput for large transfers.

Active Directory Integration

TrueNAS SCALE joins AD under Directory Services. The key settings are the AD domain, administrator credentials for the join, and the idmap backend (which maps AD user SIDs to Unix UIDs). Use rid for simple single-domain environments. Use autorid for multi-domain or environments with many users. After joining, run wbinfo -u from the TrueNAS shell to verify that domain users are visible to winbind.

A common headache: after joining AD, the SMB service needs a restart, and existing shares need their ACLs updated to include domain users. The TrueNAS UI has an “ACL Manager” that lets you apply domain group permissions to a share’s root without having to touch the CLI.

Testing and Troubleshooting

From a Linux client:

1
2
3
4
5
6
7
8
9
# List shares on the NAS
smbclient -L //192.168.1.100 -U username

# Mount an SMB share
mount -t cifs //192.168.1.100/documents /mnt/docs \
  -o username=youruser,password=yourpass,vers=3.0

# Test write performance
dd if=/dev/urandom of=/mnt/docs/testfile bs=1M count=1000

Common problems:

  • Permission denied despite correct share: ACL type mismatch. The dataset was created with POSIX ACLs but the share expects NFSv4, or vice versa. Check zfs get acltype <dataset>.
  • Windows cannot see the share: SMB service is running but the share is not advertising via NetBIOS or mDNS. Check that ws-discovery is enabled in the SMB service settings (used by Windows 10+ for share discovery).
  • ACL inheritance not working: Confirm xattr=sa is set on the dataset. Without this, Samba stores extended attributes in hidden .zfs files, and ACL inheritance can silently break.

NFS Shares: Hypervisor Datastores and Unix Clients

NFS is the right protocol for Linux clients, Proxmox datastores, VMware ESXi datastores, and anything that does not need Windows ACL semantics.

NFSv3 vs NFSv4

Feature NFSv3 NFSv4
State model Stateless Stateful
Locking NLM (separate protocol) Built-in
Security AUTH_SYS (UID/GID based) Kerberos supported
Character encoding No standard UTF-8
Performance Good Comparable or better
Compatibility Universal Requires NFSv4 aware client

Prefer NFSv4 for new deployments. Use NFSv3 only if you have a legacy client that requires it (older ESXi versions, embedded Linux systems). TrueNAS SCALE exports can be configured to allow both versions simultaneously.

NFS Share for Proxmox

This is one of the most common TrueNAS SCALE use cases. Configure the dataset with:

1
2
zfs set atime=off pool/vms
zfs set recordsize=128K pool/vms   # or 64K — Proxmox default qcow2 images work fine

NFS share options for Proxmox:

  • Maproot User: root (allows Proxmox root to write files as root on the NAS — required for VM image creation)
  • Networks: restrict to your Proxmox management subnet, not the entire LAN
  • Enabled Protocols: NFSv3+NFSv4 or NFSv4 only
  • Security: sys (AUTH_SYS — UID/GID matching between Proxmox and TrueNAS)

The no_root_squash equivalent in TrueNAS is setting Maproot User to root. Without this, Proxmox’s root process gets squashed to nobody/nogroup on the NAS and cannot create VM image files.

Mounting from a Proxmox host manually for testing:

1
2
3
4
5
showmount -e 192.168.1.100

mount -t nfs4 \
  -o rsize=1048576,wsize=1048576,timeo=600,retrans=2 \
  192.168.1.100:/mnt/data/vms /mnt/pve-nas

The rsize and wsize of 1M (1048576 bytes) tells the NFS client to use 1 MB I/O chunks. The default is often 128K or 256K, which limits throughput on high-latency or high-bandwidth links. Always set these explicitly.

NFS Performance Tuning

NFS thread count determines how many concurrent NFS requests TrueNAS can handle. The default in TrueNAS SCALE is 16. For a busy NFS server backing several Proxmox nodes, increasing to 32 or 64 is worthwhile. Set this under Services > NFS > Number of servers.

TrueNAS generates /etc/exports dynamically from the UI configuration. You can view the generated file from the TrueNAS shell at /etc/exports.d/ to verify your share options are correct. Do not edit these files directly — they will be overwritten by the UI.


iSCSI: Block Storage for VMs

iSCSI gives VMs a real block device. The guest OS formats it directly with its own filesystem. This is important for Windows VMs (which benefit from being on a real NTFS disk), for databases that perform raw device I/O, and for any workload where the guest needs to see drive geometry and handle its own I/O queuing.

Why iSCSI Over NFS for Certain Workloads

NFS presents a filesystem. The VM (or Proxmox) puts a VM image file inside that filesystem, and the guest’s I/O goes through: guest block driver > QEMU/KVM virtio > Proxmox filesystem driver > NFS client > TCP/IP > TrueNAS NFS server > ZFS. That is five layers. iSCSI shortens the path: guest block driver > iSCSI initiator > TCP/IP > TrueNAS iSCSI target > ZFS. The guest also gets direct control over write flushing and cache behavior, which matters for NTFS and for databases.

iSCSI also supports UNMAP/TRIM, which allows the guest OS to communicate freed blocks back to the storage target. TrueNAS translates UNMAP into ZFS thin provisioning reclamation — freed space in a zvol is actually returned to the pool over time.

iSCSI Path Architecture

Proxmox Host                          TrueNAS SCALE
+------------------+                  +-----------------------+
|  QEMU/KVM VM     |                  |  iSCSI Target         |
|  +----------+    |                  |  IQN: iqn.2005-10.    |
|  | virtio   |    |     10 GbE       |  org.freenas:target0  |
|  | disk     |    |   (iSCSI over    |  Portal: 192.168.1.   |
|  +----+-----+    |     TCP)         |  100:3260             |
|       |          |                  |  +------------------+ |
|  +----+-------+  |  +----------+   |  | zvol: data/vms/  | |
|  | iSCSI      +--+--+ iSCSI    +---+  | vm-100           | |
|  | initiator  |  |  | network  |   |  | (50 GB zvol)     | |
|  +------------+  |  +----------+   |  +--------+---------+ |
+------------------+                  |           |           |
                                      |      +----+------+    |
                                      |      |  ZFS pool |    |
                                      |      | (RAIDZ2)  |    |
                                      |      +-----------+    |
                                      +-----------------------+

Creating the Zvol and Target

First, create the zvol. In TrueNAS SCALE, go to Storage > Create Dataset > select “zvol” type. Key settings:

  • Size: Thin provisioning is supported (the zvol can be larger than allocated pool space), but only if you have a plan to monitor growth. Thick provisioning is safer for production.
  • Block size: Use 512B emulation for compatibility with most guest OSes. If you are provisioning for a modern Linux VM that you control, 4K native (volblocksize=8192 — TrueNAS uses this for 8K minimum) is more efficient.

From the CLI, creating a zvol:

1
2
3
4
zfs create -V 50G -s \
  -o volblocksize=4096 \
  -o compression=lz4 \
  data/vms/vm-100-disk0

Then in the TrueNAS UI under Shares > iSCSI:

  1. Portals: Create a portal, bind to the NAS IP on port 3260.
  2. Initiators: Create an initiator group; enter the IQN of your Proxmox host or leave blank (allow all — only do this on an isolated storage network).
  3. Targets: Create a target with a descriptive name (e.g., target-proxmox-vm100). Assign the portal and initiator group.
  4. Extents: Create an extent backed by your zvol. Set the logical block size to match your volblocksize.
  5. Associated Targets: Link the extent to the target as LUN 0.

Linux Initiator Setup

On the Proxmox host (or any Linux system):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Install initiator tools
apt install open-iscsi

# Discover targets on the NAS
iscsiadm -m discovery -t sendtargets -p 192.168.1.100

# Log into the target
iscsiadm -m node \
  --targetname iqn.2005-10.org.freenas:target-proxmox-vm100 \
  --portal 192.168.1.100:3260 \
  --login

# Verify the session
iscsiadm -m session -P 3

# The new block device appears as /dev/sdX or /dev/disk/by-path/...
lsblk

CHAP Authentication

On an isolated storage-only VLAN, CHAP is optional. On any network shared with other traffic, enable CHAP. Configure it in TrueNAS under the initiator’s authorized access settings. Mutual CHAP (target authenticates to initiator as well as initiator to target) is the more secure option.

Multipath

If you have two network interfaces on both the NAS and the initiator, iSCSI multipath (MPIO) provides both bandwidth aggregation and failover. On Linux:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apt install multipath-tools

# /etc/multipath.conf — add your TrueNAS targets
defaults {
    user_friendly_names yes
    find_multipaths yes
}

blacklist_exceptions {
    property "(SCSI_IDENT_|ID_WWN)"
}

On Windows, MPIO is built into the OS. Add the iSCSI initiator, discover both portals, and Windows MPIO handles aggregation automatically.

Performance reality check: iSCSI over a single 10 GbE link gives you roughly 1 GB/s theoretical, with practical throughput of 700–900 MB/s for large sequential reads/writes depending on protocol overhead. NFS over the same link is similar for large I/O. The real advantage of iSCSI is latency for small random I/O, not peak throughput.


Snapshots and Replication

ZFS snapshots are the most powerful protection mechanism available, and they cost almost nothing at creation time.

How ZFS Snapshots Work

A snapshot is an immutable point-in-time reference to the dataset’s block tree. Because ZFS uses Copy-on-Write, existing data is never modified in place — new writes go to new locations and the old data blocks remain referenced by the snapshot. The snapshot consumes only the delta between the snapshot state and the current state. A freshly taken snapshot consumes zero bytes. A snapshot of a dataset where 10 GB has changed since it was taken consumes approximately 10 GB.

Taking a snapshot manually:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Snapshot a single dataset
zfs snapshot data/shares/documents@2026-05-28_daily

# Recursive snapshot (all child datasets)
zfs snapshot -r data/shares@2026-05-28_daily

# List snapshots
zfs list -t snapshot -o name,creation,used,refer

# Roll back to a snapshot (DESTRUCTIVE — destroys all changes after the snapshot)
zfs rollback data/shares/documents@2026-05-28_daily

What Snapshots Protect Against (and What They Don’t)

Snapshots protect against: accidental deletion, accidental overwrites, ransomware (files encrypted by ransomware appear as changes, the pre-encryption state is preserved in snapshots), and partial corruption from an application crash.

Snapshots do not protect against: hardware failure (snapshots live on the same pool as the data), catastrophic pool failure, or administrator-initiated zfs destroy. They are not a replacement for off-system backups.

TrueNAS Periodic Snapshot Tasks

In the TrueNAS UI under Data Protection > Periodic Snapshot Tasks, configure automated snapshot schedules. A reasonable baseline policy:

  • Hourly snapshots, retain 24
  • Daily snapshots, retain 30
  • Weekly snapshots, retain 8
  • Monthly snapshots, retain 12

The UI shows you the projected space usage based on your change rate. Watch the “Used” column on your snapshot list — if snapshots are consuming more than 20% of your pool, either your change rate is high or your retention policy is too aggressive.

Restoring Individual Files

Snapshots are directly accessible through the filesystem via the .zfs/snapshot directory at the root of each dataset mount point:

1
2
3
4
5
6
ls /mnt/data/shares/documents/.zfs/snapshot/
# 2026-05-28_daily  2026-05-27_daily  2026-05-26_daily ...

# Restore a single file
cp /mnt/data/shares/documents/.zfs/snapshot/2026-05-27_daily/report.docx \
   /mnt/data/shares/documents/report_restored.docx

This is invisible to users on SMB if you do not expose .zfs, but TrueNAS’s VSS integration makes this accessible to Windows clients via Previous Versions. The user experience is seamless.

Remote Replication

TrueNAS replication sends ZFS snapshots to another system using zfs send | zfs receive over SSH. This is true replication of the storage tree — not rsync, not block-level copy, but the actual ZFS change stream. The receiving system gets a perfect replica that can be promoted to a live pool in a disaster recovery scenario.

Setting up replication in TrueNAS:

  1. On the destination TrueNAS, create an SSH connection profile under System > SSH Connections.
  2. On the source, go to Data Protection > Replication Tasks > Add.
  3. Select source datasets, destination, SSH connection, and schedule.
  4. The first replication sends a full stream (can take hours for large pools). All subsequent runs send only the incremental delta since the last common snapshot.

Bandwidth throttle: Under the Advanced options of a replication task, you can set a bandwidth limit in Kbps. Use this if you are replicating over a WAN connection that you do not want to saturate.

Compression in transit: zfs send can compress the stream before sending. Enable this for WAN replication. The CPU cost on the source is modest, and WAN bandwidth is expensive.

Incremental replication mechanics: The source holds a bookmark (or snapshot) of the last successfully replicated state. The next replication sends zfs send -i source@lastsnap source@newsnap — only the blocks that changed between those two snapshots. This is why the replication schedule must be coordinated with the snapshot schedule: if you delete a snapshot on the source that the replication stream was built on, the next replication will require a full send again.

Cloud Replication via Rclone

TrueNAS SCALE includes Rclone integration under Cloud Sync Tasks. Configure an S3-compatible target (Backblaze B2, Wasabi, AWS S3, Cloudflare R2) and set up a sync or copy task. This is not ZFS-native — it is file-level sync, not snapshot replication. It is suitable for secondary copies of important files but should not replace a ZFS replication target if you have one available.


ZFS ARC Tuning

The ARC (Adaptive Replacement Cache) is one of ZFS’s most sophisticated features and one of the most misunderstood. It is not a simple LRU cache. The ARC tracks both recently used data (MRU — Most Recently Used) and frequently used data (MFU — Most Frequently Used), and adaptively shifts the balance between them based on access patterns. Data that is accessed frequently gets promoted and stays cached even if it has not been touched recently. This is why the ARC outperforms the page cache for storage workloads.

ARC Size and the OS Memory Tension

On Linux, the ARC competes with the OS page cache and application memory for RAM. TrueNAS SCALE configures the ARC to use up to (total RAM - 1 GB) by default, with a floor of 64 MB. In practice, the ARC will grow to fill available RAM and the kernel’s memory pressure mechanism will ask it to shrink when applications need memory.

For a dedicated NAS (no VMs running directly on TrueNAS, no heavy apps), you want the ARC to have as much RAM as possible. The constraint is only what TrueNAS itself needs: the OS, the middleware, Samba, the NFS daemon, and any apps you run. In practice, 4–8 GB reserved for non-ARC use is sufficient on a dedicated NAS.

Setting a hard cap on ARC size prevents the OS from taking RAM from the ARC during peaks:

1
2
3
4
5
6
7
8
# View the current ARC max (in bytes)
cat /sys/module/zfs/parameters/zfs_arc_max

# ARC statistics
arc_summary

# Detailed arcstats
cat /proc/spl/kstat/zfs/arcstats | grep -E "^(size|c_max|c_min|hits|misses|demand)"

In TrueNAS SCALE, set the ARC max via System > Advanced > Sysctl Tunables. Add:

Variable Value Notes
zfs_arc_max 34359738368 32 GB in bytes — example for a 64 GB RAM system
zfs_arc_min 4294967296 4 GB minimum; ARC won’t drop below this

Interpreting ARC stats:

  • arc_hits / (arc_hits + arc_misses) = hit rate. Healthy production NAS should see 80–95%+ hit rate once warmed up.
  • c_max = current ARC size cap (in bytes)
  • size = actual current ARC size

If your hit rate is below 60%, you either have a working set larger than your RAM (consider L2ARC, or buy more RAM), or you have a streaming workload that naturally does not benefit from caching (sequential reads of unique files).

1
2
3
4
5
# Real-time pool I/O stats
zpool iostat -v 5

# Check if the ARC is actually being used
arc_summary | grep -A5 "ARC Summary"

L2ARC: When It Actually Makes Sense

L2ARC is a valid tool for a specific scenario: you have a large working set (several TB of data that is accessed regularly), you cannot add more RAM, and you have a fast SSD available. A homelab doing Plex transcoding from a 10 TB media library where users regularly access any part of the library is a candidate. A NAS serving a software development team accessing a 50 GB source repository is not — the working set fits in RAM.

The RAM overhead of L2ARC matters. Each 512 bytes of L2ARC requires ~70 bytes of RAM for index entries. A 2 TB L2ARC device requires roughly 280 GB of RAM just for the index — clearly impractical. In practice, L2ARC is only useful when it is small enough that the index fits in a reasonable fraction of your RAM. 100–500 GB L2ARC on a system with 64+ GB of RAM can be beneficial.

Pool import after a reboot rebuilds the L2ARC from scratch (the cache is cold), so the benefit disappears after every restart until the cache warms again.


SMART Monitoring and Disk Health

Drives fail. The question is whether you find out through an alert or through a degraded pool notification at 2am.

SMART Tests

TrueNAS schedules SMART tests under Data Protection > S.M.A.R.T. Tests. Three test types:

  • Short: Runs the drive’s built-in quick self-test (2–5 minutes). Good for weekly automated checks.
  • Long: Full surface scan (4–24 hours depending on drive size). Run monthly. This is the real health indicator.
  • Conveyance: Tests for damage incurred during transport. Run once on new drives.

Critical SMART attributes to watch — any non-zero value in these columns is a red flag:

SMART Attribute ID Name What It Means
5 Reallocated Sectors Count Bad sectors found and remapped. Drive is compensating for physical damage.
187 Reported Uncorrectable Errors Errors the drive could not fix via ECC. Serious.
188 Command Timeout Commands timing out. Often a sign of a failing drive or cabling issue.
197 Current Pending Sectors Sectors waiting to be reallocated; reads from these sectors may fail.
198 (Offline) Uncorrectable Sectors found during background scan that cannot be read. Critical.

TrueNAS sends email alerts when SMART tests fail or when these attributes cross thresholds. Configure alerts under System > Alert Settings. Set up an email notification or, for more urgency, a Slack webhook or PagerDuty integration.

Burn-In Testing New Drives

Before adding a new drive to a pool, stress-test it. The DOA and infant mortality window for drives is real, and better to find a bad drive before it is in a pool than after.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Full destructive write test (use with caution — wipes the drive)
badblocks -v -w -s -b 4096 /dev/sdX

# Non-destructive read test
badblocks -v -n -s -b 4096 /dev/sdX

# Long SMART test
smartctl -t long /dev/sdX
# Check results after completion:
smartctl -a /dev/sdX

The badblocks write test on a 16 TB drive takes 12–24 hours. This is worth the time before committing the drive to a production pool.

Reading zpool status

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
zpool status -v

  pool: data
 state: ONLINE
status: Some supported features are not enabled on the pool.
  scan: scrub repaired 0B in 02:14:37 with 0 errors on Sun May 25 02:14:37 2026
config:

        NAME           STATE     READ WRITE CKSUM
        data           ONLINE       0     0     0
          raidz2-0     ONLINE       0     0     0
            sda        ONLINE       0     0     0
            sdb        ONLINE       0     0     0
            sdc        ONLINE       0     0     0
            sdd        ONLINE       0     0     0
          raidz2-1     ONLINE       0     0     0
            sde        ONLINE       0     0     0
            sdf        ONLINE       0     0     0
            sdg        ONLINE       0     0     0
            sdh        ONLINE       0     0     0
          nvme0n1      ONLINE       0     0     0  (log)

State meanings:

  • ONLINE: Healthy.
  • DEGRADED: One or more drives failed but the pool is still accessible due to redundancy.
  • FAULTED: Too many failures, pool is inaccessible (redundancy exhausted).
  • REMOVED: A drive was physically removed from a running pool.
  • UNAVAIL: Drive present but not accessible (cabling, driver issue).

The READ WRITE CKSUM columns show I/O errors since the pool was last imported. Any non-zero value warrants investigation.

Drive Replacement Procedure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Identify the failing drive's device path
zpool status -v data

# Offline the failing drive (optional but cleaner)
zpool offline data /dev/sdb

# Physically replace the drive, then online the new drive
zpool replace data /dev/sdb /dev/sdn

# Monitor resilver progress
watch zpool status data

During resilver, the pool remains fully accessible. Resilver time depends on pool size and drive speed — expect 4–24 hours for multi-TB pools on spinning rust. Do not replace a second drive during an active resilver if you are on RAIDZ2; you are down to your last redundancy layer.

Scrub Schedule

Scrub reads every block on the pool and verifies checksums, repairing silent corruption if possible using parity data. Run scrubs monthly. TrueNAS configures a default scrub schedule under Data Protection > Scrub Tasks.

After a scrub, zpool status shows the results:

scan: scrub repaired 0B in 02:14:37 with 0 errors on Sun May 25 02:14:37 2026

repaired 0B with 0 errors is what you want to see. If errors appear, investigate SMART attributes on all drives in the affected vdev immediately.


The App Ecosystem: From Kubernetes to Docker

This area has been the most turbulent part of TrueNAS SCALE’s evolution. Understanding the history matters because you will still encounter documentation, tutorials, and forum posts describing the old system.

The Kubernetes Era (SCALE 22.12 through 24.04)

TrueNAS SCALE Bluefin (22.12) through Dragonfish (24.04) shipped with an embedded k3s (lightweight Kubernetes) cluster for running applications. Apps were packaged as Helm charts and managed through the TrueNAS UI. The official iXSystems catalog provided a curated set of apps. TrueCharts, a third-party project, provided a much larger and more feature-rich catalog of several hundred Helm chart applications.

This system worked, but it had real problems. k3s adds significant complexity overhead to what is supposed to be a NAS appliance. Updates to the catalog were sometimes opaque. TrueCharts apps used a shared “operator” framework that created deep interdependencies. When iXSystems decided to remove Kubernetes in 24.10, TrueCharts was in the difficult position of having its entire library become incompatible.

The Docker Transition (24.10 Electric Eel and 25.04 Fangtooth)

TrueNAS SCALE 24.10 (ElectricEel) replaced the k3s backend with Docker. Official catalog apps were rewritten as Docker-based deployments. The app UI remained, but the underlying engine changed completely. Kubernetes-based TrueCharts apps did not automatically migrate — users with TrueCharts-dependent setups had to manually rebuild their configurations.

As of 25.04 Fangtooth and 25.10 Goldeye, the app system is Docker-native. The official iXSystems “TrueNAS Apps” catalog provides around 100+ applications — common services like Plex, Nextcloud, Jellyfin, Home Assistant, and similar. Custom apps can be deployed via a guided wizard (Docker image + environment variables) or a full Docker Compose YAML file.

The “Install via YAML” option in the TrueNAS 25.x UI opens a Compose editor where you paste a standard docker-compose.yml. Most application documentation on the internet shows Docker Compose syntax, which means you can deploy any containerized app without waiting for a catalog entry.

TrueCharts in the Docker Era

TrueCharts adapted to the Docker transition by developing a new framework outside of TrueNAS’s app system. They now maintain a library of TrueNAS-compatible compose stacks, available from truecharts.org. Installing a TrueCharts app in Fangtooth+ involves importing their compose YAML through the custom app interface. This works, but it is more manual than the old one-click Helm chart installation.

TrueCharts is a community project. The quality is generally high, but stability can vary — the project moves fast and has broken things during major transitions. For critical services, running a dedicated VM or LXC container (on Proxmox, for example) is often a better choice than relying on TrueNAS apps.

The NAS-as-NAS Philosophy

Here is the honest opinion: TrueNAS is an excellent NAS platform. It is a mediocre application hosting platform. The ZFS storage engine, the share protocols, the snapshot and replication system — these are rock-solid and purpose-built. The app ecosystem, whether Kubernetes or Docker, exists because users want it, but it adds complexity to a system whose primary job is storing and serving data reliably.

The argument for keeping your NAS as a NAS: if the TrueNAS system crashes or requires a reboot for a pool operation, all your apps go down with it. If an app on TrueNAS consumes runaway memory, it competes with the ZFS ARC. If a Docker volume mounts the wrong dataset with the wrong permissions, it can interfere with share ACLs. None of these are theoretical.

For production environments, the cleaner architecture is: TrueNAS for storage, a separate Proxmox node for VMs and LXC containers. TrueNAS serves iSCSI or NFS to Proxmox; Proxmox runs your apps. Each system does one thing well. For a homelab where you want everything on one box and understand the trade-offs, TrueNAS apps are fine — run them with eyes open.


Putting It Together: Operational Checklist

A TrueNAS SCALE installation is not “set it and forget it.” These are the recurring operational tasks that keep a production system healthy:

Weekly:

  • Review alert emails/notifications. Do not dismiss SMART warnings.
  • Check zpool status output manually or via the dashboard. READ/WRITE/CKSUM columns should be zero.
  • Verify that snapshot tasks ran successfully.

Monthly:

  • Run long SMART tests on all drives.
  • Run a pool scrub (TrueNAS schedules one by default).
  • Verify that remote replication tasks completed successfully and the destination pool is current.
  • Review snapshot space consumption.

On every pool event (degraded, new drive added, resilver):

  • Watch resilver completion before touching anything else in the pool.
  • Verify new drive SMART baseline after resilver.
  • Update your hardware inventory notes.

When planning hardware changes:

  • Check your current ashift before adding drives (all drives in a pool should match ashift).
  • If adding a vdev, ensure the new vdev has the same drive count and size as existing vdevs to keep striped performance balanced. (RAIDZ expansion now allows growing individual vdevs, but starting balanced is still best practice.)
  • Never mix CMR and SMR drives in a pool, or even on the same controller if possible.

TrueNAS SCALE is, at its core, a ZFS management appliance. Everything else — the shares, the apps, the UI — is scaffolding around a very sophisticated storage engine. Understand ZFS first, and the rest follows naturally. Build your pool correctly, monitor your drives, take your snapshots, and replicate off-system. The storage engineering fundamentals have not changed in twenty years, and TrueNAS makes them more accessible than they have ever been.

Comments