Skip to content

SnapRAID Configuration Guide

SnapRAID Official Docs


Overview

SnapRAID is a backup program for disk arrays. It stores parity information of the data to recover from up to six disk failures.

Unlike traditional RAID 5 or 6, SnapRAID is not real-time; it is a snapshot-based system.

  • Provide fault tolerance to protect against (inevitable) hard drive failure
  • Checksum files to guard against bitrot
  • Support hard drives of differing / mismatched sizes
  • Enable incremental upgrading of hard drives in batches as small as one
  • Each drive should have a separately readable filesystem with no striping of data

The Parity Concept

SnapRAID requires dedicating specific disks to "Parity."

  • Parity Level: One parity disk protects against one drive failure. Two parity disks protect against two failures, and so on.
  • Sizing: The parity disk must be equal to or larger than the largest single data disk in the array.
  • Storage: Parity disks contain only the large .parity file; they cannot be used for standard data storage.

Installation

Debian package (what I run)

Debian 13 "trixie" ships SnapRAID 12.4 in main. It's what my NAS runs: it's stable, it gets security updates with the rest of the system, and nothing in my setup needs a newer feature.

sudo apt update && sudo apt install snapraid
snapraid -V

Compile from Source

Upstream is ahead of Debian (v15.0 at the time of writing). If you want the newest release, build it yourself. Check the releases page for the current version first.

sudo apt install build-essential
VER=15.0   # current release from the releases page

# Download source
wget https://github.com/amadvance/snapraid/releases/download/v$VER/snapraid-$VER.tar.gz

# Extract archive
tar xzvf snapraid-$VER.tar.gz

# Enter directory
cd snapraid-$VER

# Compile and Install (to /usr/local/bin, so it doesn't clash with the Debian package)
./configure
make
make check
sudo make install

# Verify installation
snapraid -V

Configuration

SnapRAID is configured via a single text file located at /etc/snapraid.conf. This file defines the parity volumes, content files, and data disks.

Key Components

  1. Parity Files: The destination for redundancy data.
  2. Content Files: These act as the "index" or "database" of the array. They contain checksums and file maps.
  3. Critical: Multiple copies should be stored on separate physical disks (e.g., one on the boot drive, others on data drives) to ensure the index survives a disk failure.

  4. Data Disks: The actual storage drives containing the media/files to protect.

Configuration Example (/etc/snapraid.conf)

This is the structure my NAS uses: one parity disk, two data disks, and a content file on every physical disk (the boot NVMe plus each data disk), so the index survives any single disk failure.

# --- Parity Location ---
# The parity file must be on the dedicated parity drive
parity /mnt/parity1/snapraid.parity

# --- Content files ---
# Store copies on multiple physical drives for safety
content /var/snapraid/snapraid.content
content /mnt/disk1/snapraid.content
content /mnt/disk2/snapraid.content

# --- Data Disks ---
# Assign a name (d1, d2) and a mount point for each disk.
# These are the mergerfs BRANCHES, never the pool (/mnt/storage).
data d1 /mnt/disk1
data d2 /mnt/disk2

# --- Excludes ---
# Prevent temporary files from breaking the sync
exclude *.unrecoverable
exclude /tmp/
exclude /lost+found/

Keep busy data off the protected disks

Container databases (/mnt/appdata on an SSD) and camera recordings (their own disk) are not on the data disks. Files that change constantly make every sync big and produce "file changed during sync" warnings.


Usage & Maintenance

Because SnapRAID is snapshot-based, the array is not protected until a "sync" is performed.

Syncing

Run the sync command to update the parity information. This reads data from the data disks and computes the parity.

snapraid sync
  • Note: The first sync may take several hours. Subsequent syncs only process changed data.
  • Interruptible: The process can be stopped (Ctrl+C) and resumed later.

Scrubbing

Scrubbing checks the data and parity for silent corruption (bitrot).

snapraid scrub
  • Default Behavior: Checks approximately 8% of the array that hasn't been scrubbed in the last 10 days.
  • Custom Plan: To check a specific percentage (e.g., 5%) of blocks older than 20 days:
    snapraid -p 5 -o 20 scrub
    

Automation: snapraid-aio + wrapper

Since SnapRAID requires manual commands, it is highly recommended to automate these tasks using scripts. I use snapraid-aio-script (installed in /usr/sbin/snapraid/), run nightly from root's crontab through a small wrapper.

What snapraid-aio does

Each run: diff → (if the counts look sane) sync → scrub, then a summary to its notification channel (Discord in my case). The settings in script-config.conf that matter:

Setting Value Why
DEL_THRESHOLD 1500 Refuse to sync if more files than this were deleted. A failing disk or a runaway script shouldn't be written into parity.
UP_THRESHOLD 3000 Same for updated files.
ADD_DEL_THRESHOLD 0.7 ...but allow the sync anyway when the ratio of added to deleted files is above 0.7: lots of deletes and lots of new files is what a normal library reorganisation (rename/move) looks like. With this at 0, one legitimate cleanup blocked my syncs for a month.
SCRUB_PERCENT / SCRUB_AGE 5 / 10 Scrub 5% of the array each night, picking blocks older than 10 days. The whole array gets checked roughly every 3 weeks.
PREHASH 1 "Pre-hash" mode: new data is read twice, so a bad read can't end up in parity.
MANAGE_SERVICES / DOCKER_MODE 1 / 1 Pause containers during the run (mode 2 would stop them).
SERVICES every running container except the NVR Nothing writes to the protected disks while parity is computed. The NVR records to its own disk outside the array, so it keeps running.
SMART_LOG, SNAP_STATUS 1 Include SMART and snapraid status in the report.
script-config.conf (excerpt)
SERVICES="$(docker ps --format '{{.Names}}' | grep -v '^frigate$' | tr '\n' ' ')"

Why pause the containers at all? A file that changes between SnapRAID reading it and writing parity gives parity that doesn't match the data. Pausing everything is the blunt-but-simple option. A narrower list (only the containers that write to the pool: the download client, the *arrs, the photo server, sync tools) also works and keeps databases and monitoring agents running; that's a trade-off to make for your own box.

Why Plex is stopped, not paused

A paused container keeps its sockets open but doesn't answer. Plex clients on the LAN (a TV app polls Plex every few seconds) kept opening connections for the whole ~50 minute scrub, and on un-pause Plex answered hundreds of them in the same instant. The firewall saw replies for connections it had already timed out, dropped them as out-of-state, and its IDS (CrowdSec's port-scan scenario) banned the NAS for four hours, every morning. The offsite backup that ran right after failed on each of those days.

So the wrapper stops Plex before the run and starts it again when the run ends:

  • Stopped Plex refuses connections at once. Nothing queues, so there's no burst afterwards.
  • Plex still doesn't run during sync/scrub (it writes metadata to the pool, which is the point of pausing it).
  • Active streams get a "nightly maintenance" terminate message first instead of just freezing.
  • The start is in an EXIT trap, so it happens even if snapraid-aio fails. If docker start fails, an alert goes out.

See CrowdSec banning your own server for how to spot this kind of ban.

The wrapper: dead-man switch + ntfy

snapraid-aio's own notification is not enough on its own: if the job stops running, or the webhook can't be delivered, you hear nothing. The wrapper adds two independent paths:

  • Uptime Kuma push monitor: status=up after a clean run, status=down on a problem, and it goes DOWN by itself when no run reports for 25 h. That's the part that catches "cron didn't run" or "the box was off".
  • ntfy: a quiet "SnapRAID OK" to a low-priority topic, or a priority-4 "SnapRAID needs attention" with the WARN lines (for example the deleted-files threshold) to the alerts topic.

A run counts as clean only when the script exits 0, logs no WARN/ERROR line, and logs its [COMPLETED] marker.

/usr/local/sbin/snapraid-run (simplified)
#!/bin/bash
LOG=/var/log/snapraid.log
PLEX=plex
start=$(wc -l < "$LOG" 2>/dev/null || echo 0)

# Stop Plex for the run (instead of letting snapraid-aio pause it), start it again on exit
if [ "$(docker inspect -f '{{.State.Running}}' "$PLEX" 2>/dev/null)" = true ]; then
  trap 'docker start "$PLEX" >/dev/null || ntfy-send alerts 4 "Plex did not come back after SnapRAID"' EXIT
  docker stop -t 30 "$PLEX" >/dev/null
fi

/usr/sbin/snapraid/snapraid-aio-script.sh; rc=$?

# Only look at what this run appended to the log
new=$(tail -n +"$((start+1))" "$LOG")
warn=$(printf '%s\n' "$new" | grep -E 'snapraid-aio-script.sh: (WARN|ERROR):' | head -6)
done_line=$(printf '%s\n' "$new" | grep -oE "\[COMPLETED\][^']*" | tail -1)

if [ "$rc" -eq 0 ] && [ -z "$warn" ] && [ -n "$done_line" ]; then
  status=up;   msg="$done_line";              ntfy-send hosts 1 "SnapRAID OK" "$done_line"
else
  status=down; msg="exit $rc: ${warn:-no [COMPLETED] marker}"
  ntfy-send alerts 4 "SnapRAID needs attention" "$msg"
fi

# Push URL contains a token: keep it in a root-only file, not in the script
url=$(cat /etc/snapraid/kuma-push-url 2>/dev/null)
[ -n "$url" ] && curl -fsS -m 15 -G -o /dev/null \
  --data-urlencode "status=$status" --data-urlencode "msg=$msg" "$url"
exit "$rc"

ntfy-send stands for whatever you use to publish to ntfy (a curl with a per-publisher token works). The real script also terminates active Plex sessions through the Plex API before stopping it, reading the Plex token into a 0600 header file so it never shows up in ps or logs.

sudo crontab -e
# Nightly, at a quiet hour. Pick a time clear of your backups and update reboots.
0 3 * * * /usr/local/sbin/snapraid-run

Line up the rest of the night around it

  • Put the NAS's media monitors (Uptime Kuma, Komodo container alerts) in a maintenance window that covers the run, so paused containers don't page you. A run that's still going after the window alerts normally.
  • The NAS's own borgmatic run waits for SnapRAID to finish and refuses to dump a paused Postgres container (see Borgmatic).
  • Update reboots wait for a running sync/scrub instead of interrupting it.
  • Schedule the monthly SMART long self-test after the SnapRAID run.

Recovery

Undeleting Files

If a file is accidentally deleted, SnapRAID can restore it to its previous state (like a backup).

Restore specific file:

snapraid fix -f /path/to/file

Restore specific directory:

snapraid fix -f /path/to/directory/

Restore only missing files: Use the -m flag to recover deleted files without overwriting existing changed files.

snapraid fix -m -f /path/to/directory/

Recovering a Failed Drive

In the event of a total disk failure, follow this procedure strictly.

1. Halt Operations Disable any automated tasks (cron jobs, AIO scripts) and stop writing new data to the array.

2. Reconfigure Install the replacement disk and mount it. Edit /etc/snapraid.conf to point the failed disk identifier to the new mount point.

  • Example: Change data d1 /mnt/failed_disk to data d1 /mnt/new_disk.

3. Fix (Restore Data) Run the fix command targeting the specific disk identifier (-d). Log the output to a file on a different drive for review.

snapraid -d d1 -l fix.log fix
  • Note: This process will read from all other disks to reconstruct the missing data. It runs at the speed of the slowest drive.

4. Review Check fix.log for "unrecoverable" errors. If files were modified since the last sync, they may not be fully recoverable.

5. Verification (Optional) Run a check on the restored disk to verify integrity.

snapraid -d d1 -a check

6. Resync Once verified, run a standard sync to update the array status.

snapraid sync

Sources & further reading