SnapRAID + MergerFS: A NAS Without the Rebuild Dread

Pool mismatched disks, add parity, and lose only what you actually lose

Contents

Every conventional RAID array has the same nasty property: it’s all or nothing. Stripe six disks together in RAID5 or RAIDZ1 and lose two at once — which happens more often than the marketing suggests, because drives from the same batch tend to fail in the same window — and the entire array is gone in one stroke, five-sixths of it just as unreadable as the missing sixth. I ran a NAS that way for years, dreading every rebuild, because a rebuild is the single most stressful thing you can do to a hard drive: hours of sustained full-speed reads across every remaining disk, which is exactly the workload most likely to surface a second failure on an already-aging array.

SnapRAID plus MergerFS is the combination that got me off that treadmill. It isn’t RAID in the traditional sense at all, and that’s the point: each disk in the pool keeps its own independent filesystem, MergerFS glues them together into one logical mount point, and SnapRAID computes parity data separately, on a schedule you control rather than in real time. Lose a disk and you lose exactly the files that were on it, recoverable from parity, while every other disk keeps working through the incident completely undisturbed.

Why This Beats Traditional RAID for a Media/Archive NAS

Advertisement

Traditional RAID and ZFS earn their complexity when you need real-time protection and don’t mind that every disk in a vdev has to be the same size, spin at the same speed, and get replaced as a matched set. That’s the right tool for a database or a VM datastore where write-in-progress consistency actually matters minute to minute.

A media library or a backup archive has different needs. Files get written once and read many times. A parity update that lags behind the actual writes by a few hours is a completely acceptable trade, because in exchange you get to build a pool out of whatever mismatched disks you happen to own — a 4TB drive bought two years ago sitting next to an 8TB drive bought last month, both fully usable, no matched-set tax. You can add a single new disk to grow the pool without touching the rest. And if a disk dies, you don’t rebuild an array; you replace that one disk and restore its contents from parity, while the rest of your files stay put, untouched and immediately accessible, the whole time.

The trade-off is honest and worth stating plainly: SnapRAID parity is a point-in-time snapshot rather than a live mirror. Anything written between snapshots isn’t protected. This makes it wrong for actively-changing working data and exactly right for a library that fills up gradually and doesn’t get rewritten.

MergerFS: Pooling Without Striping

MergerFS is a FUSE filesystem that presents several independent disks as one directory tree. There’s no striping — a given file lives entirely on one physical disk — which is precisely what makes disk-level recovery possible: pull one disk, and you’ve lost only the files that were on it, cleanly and completely, with everything else on the pool still intact.

1
2
3
# /etc/fstab entry pooling three data disks under /mnt/storage
/mnt/disk1:/mnt/disk2:/mnt/disk3 /mnt/storage fuse.mergerfs \
  defaults,allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=mfs 0 0

The category.create=mfs policy (“most free space”) decides which physical disk a new file lands on — write a new file into /mnt/storage/movies/, and MergerFS picks whichever underlying disk has the most room. Other useful create policies exist: epmfs keeps files within an existing path on the same disk they’re already on where possible, useful if you want a given show’s episodes to stay together rather than scattering across disks — SnapRAID doesn’t strictly require this, but it makes manual disk-by-disk browsing more sane when you’re troubleshooting.

Mount your individual disks under stable, boring paths first:

1
2
3
4
5
mkdir -p /mnt/disk1 /mnt/disk2 /mnt/disk3
# each disk formatted separately, ext4 or xfs, mounted by UUID in fstab
UUID=xxxxxxxx-1111 /mnt/disk1 ext4 defaults 0 2
UUID=xxxxxxxx-2222 /mnt/disk2 ext4 defaults 0 2
UUID=xxxxxxxx-3333 /mnt/disk3 ext4 defaults 0 2

Each disk is a completely normal, independently readable filesystem. That’s deliberate: if MergerFS or SnapRAID vanished from the earth tomorrow, you could still mount any single disk and read its files with ls. There’s no proprietary on-disk format to hold your data hostage.

SnapRAID: Parity on Your Schedule

Advertisement

SnapRAID computes parity across your data disks and stores it on one or more dedicated parity disks — disks that hold no data of their own, only recovery information, and must be at least as large as your biggest data disk. One parity disk protects against one simultaneous disk failure; run two parity disks for two-disk protection, mirroring the trade-off RAID6/RAIDZ2 makes, but without requiring the disks to match in size.

Configuration lives in a plain text file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# /etc/snapraid.conf
parity /mnt/parity/snapraid.parity
content /mnt/disk1/.snapraid.content
content /mnt/disk2/.snapraid.content
content /mnt/disk3/.snapraid.content

data d1 /mnt/disk1
data d2 /mnt/disk2
data d3 /mnt/disk3

exclude *.tmp
exclude /lost+found/
exclude Thumbs.db

Note the content files are deliberately duplicated across multiple data disks — this file tracks what’s supposed to be where, and if it only existed on one disk, losing that disk would blind SnapRAID to its own state at the worst possible moment.

The actual workflow is two commands, run on a schedule via cron or systemd timers:

1
2
3
4
5
# sync: update parity to reflect current file state (run nightly)
snapraid sync

# scrub: verify a slice of already-synced data against parity (run weekly)
snapraid scrub -p 10 -o 10

sync is the step that actually protects new or changed files — until it runs, anything written since the last sync has no parity coverage. scrub checks a percentage of blocks each run (here, 10%, skipping blocks scrubbed in the last 10 days) to catch silent bit rot before you’d ever notice it on a normal read.

Sizing the Parity Disk and Planning Growth

The parity disk has to be at least as large as your single largest data disk, because parity is computed as if every data disk were that size — SnapRAID pads smaller disks conceptually to match. This has a practical consequence for growth planning: if you buy an 8TB disk today as your biggest data disk and a matching 8TB parity disk, then buy a 12TB disk next year to expand the pool, your existing parity disk is now too small to protect it. You’d need to either replace the parity disk with something ≥12TB, or accept that the new disk sits outside parity protection until you do.

The way I plan around this now: buy the parity disk one size class above whatever I expect to buy as data disks over the pool’s next couple of years, accepting some wasted capacity today in exchange for not having to replace parity disks reactively. It’s a minor tax against the alternative of RAID, where every disk in a vdev has to match from day one regardless of growth plans.

Two parity disks (2-parity, protecting against two simultaneous failures) roughly double the parity disk cost but are worth considering once a pool grows past six or seven data disks, simply because the odds of a second disk dying during the recovery window after a first failure climb with every disk you add to the pool.

Recovering From a Dead Disk

This is the whole point, so it’s worth walking through concretely. Say disk2 dies:

1
2
3
4
5
6
7
8
9
# 1. Physically replace the failed drive, format it, mount at the same path
mkfs.ext4 /dev/sdX1
mount /dev/sdX1 /mnt/disk2

# 2. Tell SnapRAID to rebuild that disk's contents from parity
snapraid -d d2 fix

# 3. Verify the rebuilt data checks out
snapraid scrub

While that rebuild runs, disk1 and disk3 are completely idle as far as SnapRAID is concerned — no rebuild I/O touches them, no elevated failure risk, no array-wide downtime. MergerFS keeps serving reads for every file that lives on the healthy disks the entire time. Compare that to a RAID5 rebuild, where every surviving disk gets hammered with reads for hours and the whole array is degraded (meaning zero fault tolerance) until it finishes.

Where SnapRAID Genuinely Falls Short

Worth being upfront about the sharp edges rather than only selling the strengths. SnapRAID has no concept of live redundancy — between sync runs, new and modified files have zero protection, so a disk dying an hour after a large import can lose that import entirely. It also doesn’t checksum data on every read the way ZFS does; scrub only checks whatever percentage you configure, on whatever schedule you run it, so silent corruption between scrub passes can sit undetected longer than it would under ZFS. And because parity is disk-content-aware rather than block-striped, performance for small random writes across the pool is nowhere near what a proper RAID controller or ZFS mirror delivers — this setup is built for throughput on large sequential files rather than the small random I/O that IOPS-heavy workloads demand.

None of this is a flaw in the tool so much as a mismatch if you apply it to the wrong workload. I’d never put a database or an actively-written VM disk image on a SnapRAID-protected pool. For the media library and archive use case it’s built for, these limits rarely matter in practice, because the files in question are written once, read constantly, and rarely modified in place.

Troubleshooting

“Files changed since last sync” warnings on sync. This is SnapRAID doing its job — it flags large numbers of deletions or changes as a possible sign of a filesystem problem or a mistake, rather than blindly committing parity that might reflect a mistake, and asks you to confirm with snapraid sync -f if it’s actually intentional (a big library reorganisation, say).

A file is unrecoverable (“silent errors” during fix). This means the specific blocks for that file were also bad on the parity disk, or on another data disk in a two-parity setup where corruption overlapped. It happens rarely, but it’s exactly why scrub runs matter — they surface rot on parity itself, which sync alone won’t check.

MergerFS shows a disk as read-only or missing after remount. Check use_ino and your fstab mount order; if a data disk fails to mount at boot, MergerFS will happily present the pool with that disk simply absent from the union, which can look like missing files rather than an obvious error. Add a boot check that fails loudly (a systemd unit that verifies all expected mounts exist) rather than relying on noticing gaps.

Performance dips on the disk MergerFS picked. Because create policies choose a disk per new file, you can end up hammering one disk during a big batch import. Switch policy to lus (least used space, spread differently) or manually direct large imports to specific disks if this bites you.

Verdict

SnapRAID and MergerFS aren’t trying to be ZFS, and pretending otherwise sets you up for disappointment — there’s no real-time protection, no snapshots in the ZFS sense, no checksumming beyond what scrub catches on its schedule. What they are is the right tool for a library that grows slowly, gets read constantly, and needs to survive a single dead disk without turning that into an array-wide event. If that describes your media collection or archive, this pairing gets you flexible, mismatched-size pooling and honest, boring recovery. For anything with active, minute-to-minute writes you can’t afford to lose since the last sync, look at ZFS for Mortals instead, or read on for the appliance route in TrueNAS Scale.

Advertisement
Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.