NAS16 serves live websites via Apache/PHP and hosts their databases in MariaDB. A software or hardware failure โ corrupt SD card, bad OMV update, runaway script โ would take down all hosted sites and lose database state with no documented recovery path and no saved configuration.
The goal was to create a fully automated, scheduled backup of the OS and configuration layer โ including all databases โ that could restore NAS16 to full operation after a failure with no manual intervention during normal operation. Website files on the NAS drives are intentionally excluded; those are covered separately by NAS-to-NAS redundancy.
Keep a copy of this document on your workstation, a USB drive, or in print. If NAS16 is down you cannot read files stored on it.
/usr/scripts/omv/nas16-backup.sh
OMV config โ omv-confbak export + raw /etc/openmediavault/config.xml
/etc โ full system config (network, fstab, cron, etc.)
Apache config โ sites-available, sites-enabled, mods-enabled, conf-available,
conf-enabled, apache2.conf
PHP config โ all installed PHP version ini + FPM pool configs (/etc/php/*)
MariaDB databases โ mysqldump of every user database (.sql.gz per database)
system schemas excluded (information_schema, performance_schema,
sys, mysql)
Webmin config โ /etc/webmin (Webmin and Adminer settings)
Crontab โ root crontab + /etc/cron.d entries
MANIFEST.txt โ baked-in restore instructions and version info
NOT INCLUDED (by design):
Website files on NAS drives โ covered by NAS-to-NAS redundancy
/export/kingdezignsnas-16/Backups/NAS16/nas16-backup-YYYY-MM-DD.tar.gz /export/kingdezignsnas-16/Backups/NAS16/backup.log
10 archives retained (~30 days coverage) โ older archives auto-deleted on each run
Varies based on database sizes โ /etc + Apache + PHP + Webmin are small. Primary size driver is MariaDB dumps. Monitor backup.log after first run for actual size.
System โ Scheduled Jobs โ Add Name: NAS16 Backup Command: sudo /usr/scripts/omv/nas16-backup.sh Minute: 0 Hour: 2 Day of month: */3 Month: * Day of week: * Runs automatically at 2:00 AM every 3 days
sudo /usr/scripts/omv/nas16-backup.sh # or: OMV UI โ System โ Scheduled Jobs โ Run
sudo mkdir -p /usr/scripts/omv sudo chown rufusking:rufusking /usr/scripts/omv
Placing scripts in /usr/scripts/omv/ avoids the root-SCP requirement of /usr/local/bin/. The rufusking user can copy files here directly.
sudo mkdir -p /export/kingdezignsnas-16/Backups/NAS16
The script creates this automatically via mkdir -p on every run, but creating it manually avoids a tee log error on the very first run if the path doesn't exist yet.
# From your workstation: scp nas16-backup.sh rufusking@<NAS16-IP>:/usr/scripts/omv/nas16-backup.sh
chmod +x /usr/scripts/omv/nas16-backup.sh
sudo /usr/scripts/omv/nas16-backup.sh
Watch for any WARNING or ERROR lines in the output. Then verify the archive was created:
ls -lh /export/kingdezignsnas-16/Backups/NAS16/ cat /export/kingdezignsnas-16/Backups/NAS16/backup.log
tar -tzf /export/kingdezignsnas-16/Backups/NAS16/nas16-backup-$(date +%Y-%m-%d).tar.gz | head -60
You should see folders: omv-config/ etc/ apache/ php/ databases/ webmin/ cron/ MANIFEST.txt
OMV UI โ System โ Scheduled Jobs โ Add Enabled: Yes Name: NAS16 Backup Command: sudo /usr/scripts/omv/nas16-backup.sh Minute: 0 Hour: 2 Day of month: */3 Month: * Day of week: * โ Save โ Apply
You need: a workstation with internet, a replacement SD card (16GB+), Raspberry Pi Imager, SSH access, and your rufusking password. Physically connect all ZFS drives to the Penta SATA HAT before powering on.
https://www.raspberrypi.com/software/
Download and install for your OS (Windows / Mac / Linux).
Open Raspberry Pi Imager
โ Choose Device : Raspberry Pi 5
โ Choose OS : Raspberry Pi OS Lite (64-bit) โ NOT the Desktop version
โ Choose Storage : your SD card
โ Next โ Edit Settings:
Hostname : NAS16
Username : rufusking
Password : your usual password
Services : Enable SSH โ Use password authentication
โ Save โ Yes โ Yes (confirm flash and verify)
Wait for the flash and verify to complete fully before removing the SD card.
1. Insert SD card into Raspberry Pi 5 2. Connect Penta SATA HAT with all ZFS drives plugged in 3. Power on 4. Wait 2โ3 minutes for first boot to complete
Verify the current OMV install script at https://github.com/OpenMediaVault-Plugin-Developers/installScript before running. Steps below reflect the method as of 2026-05-12.
ssh rufusking@<NAS16-IP>
If the static IP is not yet assigned, log into UniFi, find NAS16 in Clients, and SSH to its temporary IP instead.
sudo apt-get update && sudo apt-get upgrade -y
Wait for the prompt to return before continuing.
sudo wget -O - https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install | sudo bash
Takes 10โ20 minutes. The Pi may reboot automatically. If it does, SSH back in and wait for the script to finish.
http://<NAS16-IP> Default login: Username: admin Password: openmediavault
Confirm the OMV login page loads. Do not configure anything yet โ the restore handles all configuration.
The Raspberry Pi 5 does not expose PCIe by default. Without enabling it, the Penta SATA HAT and all ZFS drives are completely invisible to the OS. This must be done before any ZFS commands will work.
sudo nano /boot/firmware/config.txt
Scroll to find the line arm_boost=1 and add these lines immediately after it:
# Enable PCIe dtparam=pciex1 dtparam=pciex1_gen=3
Save and exit:
Ctrl+X โ Y โ Enter
sudo reboot
Wait 2โ3 minutes, then SSH back in.
sudo apt-get install -y zfsutils-linux
Required on every fresh OS install.
lsblk
All drives attached to the Penta SATA HAT should be listed. If any are missing, check physical connections and reboot.
sudo zpool import kingdezignsnas-16
If the previous OS failed uncleanly, force the import:
# Only use -f if the standard import fails: sudo zpool import -f kingdezignsnas-16
sudo zpool status
All drives must show ONLINE and errors should be No known data errors.
If any drive shows FAULTED or DEGRADED, do not proceed. See ZFS Troubleshooting at the bottom of this document.
ls /kingdezignsnas-16/Backups/NAS16/ # List archives sorted newest first: ls -lht /kingdezignsnas-16/Backups/NAS16/nas16-backup-*.tar.gz
Use /kingdezignsnas-16/ directly at this stage. The /export/kingdezignsnas-16/ path is recreated by OMV after the config restore in Phase 6.
sudo mkdir -p /tmp/nas16-restore
# Replace YYYY-MM-DD with the actual archive date from step 14
sudo tar -xzf /kingdezignsnas-16/Backups/NAS16/nas16-backup-YYYY-MM-DD.tar.gz \
-C /tmp/nas16-restore
ls /tmp/nas16-restore/ ls /tmp/nas16-restore/nas16-backup-*/ cat /tmp/nas16-restore/nas16-backup-*/MANIFEST.txt
You should see: omv-config/ etc/ apache/ php/ databases/ webmin/ cron/ MANIFEST.txt
sudo rsync -a /tmp/nas16-restore/nas16-backup-*/etc/ /etc/
Restores all system configuration: network settings, fstab, cron, and everything else under /etc.
# Copy saved OMV config back into place:
sudo cp /tmp/nas16-restore/nas16-backup-*/omv-config/config.xml.raw \
/etc/openmediavault/config.xml
# Load it into the OMV database:
sudo omv-confdbadm populate
# Re-apply all settings to the system:
sudo omv-salt deploy run all
The last command takes several minutes. Do not interrupt it โ let it complete fully.
sudo reboot
After 2โ3 minutes, SSH back in. Then open a browser:
http://<NAS16-IP>
Log in and verify shares, users, and settings are present. Confirm the ZFS pool is mounted and /export/kingdezignsnas-16 is available under Storage โ File Systems.
The web stack packages must be reinstalled before restoring configuration files. Restoring config before the packages exist will have no effect and may be overwritten by the installer.
sudo apt-get install -y apache2 php libapache2-mod-php php-mysql php-cli php-curl \
php-mbstring php-xml php-zip php-gd
Install the same PHP version that was running before. Check the MANIFEST.txt from the archive for the exact version if unsure.
sudo apt-get install -y mariadb-server mariadb-client
sudo systemctl start mariadb sudo systemctl enable mariadb sudo systemctl status mariadb
Do NOT run mysql_secure_installation before restoring databases โ the debian.cnf maintenance account needs to remain intact for the restore steps to work without a password.
# Add Webmin repository and install: curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh sudo sh setup-repos.sh sudo apt-get install -y webmin
Verify the current install method at https://webmin.com/download/ before running โ the method may change.
sudo apt-get install -y adminer sudo a2enconf adminer sudo systemctl reload apache2
Or manually place adminer.php in your web root if you use a custom location:
sudo wget -O /var/www/html/adminer.php https://www.adminer.org/latest.php
sudo rsync -a /tmp/nas16-restore/nas16-backup-*/apache/sites-available/ \
/etc/apache2/sites-available/
sudo rsync -a /tmp/nas16-restore/nas16-backup-*/apache/sites-enabled/ \
/etc/apache2/sites-enabled/
sudo rsync -a /tmp/nas16-restore/nas16-backup-*/apache/conf-available/ \
/etc/apache2/conf-available/
sudo rsync -a /tmp/nas16-restore/nas16-backup-*/apache/conf-enabled/ \
/etc/apache2/conf-enabled/
# Restore main apache2.conf:
sudo cp /tmp/nas16-restore/nas16-backup-*/apache/apache2.conf \
/etc/apache2/apache2.conf
Do not overwrite mods-enabled directly โ Apache manages these symlinks internally. Re-enable required mods manually if needed (see step 27).
# Check what modules were enabled (from your backup): ls /tmp/nas16-restore/nas16-backup-*/apache/mods-enabled/ # Re-enable common modules as needed: sudo a2enmod rewrite ssl headers proxy proxy_http sudo systemctl restart apache2
Enable only the mods you see in the backup snapshot. The full list is in the mods-enabled/ folder inside the archive.
# Replace X.X with your PHP version (e.g. 8.2): sudo rsync -a /tmp/nas16-restore/nas16-backup-*/php/X.X/ /etc/php/X.X/
sudo rsync -a /tmp/nas16-restore/nas16-backup-*/webmin/ /etc/webmin/
sudo systemctl restart apache2 sudo systemctl restart mariadb sudo systemctl restart webmin # Verify all are running: sudo systemctl status apache2 mariadb webmin
ls /tmp/nas16-restore/nas16-backup-*/databases/
You should see one .sql.gz file per database. Each file is a complete dump of that database including schema and data.
# For each database (replace DB_NAME with the actual name):
gunzip -c /tmp/nas16-restore/nas16-backup-*/databases/DB_NAME.sql.gz \
| sudo mysql --defaults-file=/etc/mysql/debian.cnf DB_NAME
# If the database does not exist yet, create it first:
sudo mysql --defaults-file=/etc/mysql/debian.cnf \
-e "CREATE DATABASE IF NOT EXISTS DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# Then restore:
gunzip -c /tmp/nas16-restore/nas16-backup-*/databases/DB_NAME.sql.gz \
| sudo mysql --defaults-file=/etc/mysql/debian.cnf DB_NAME
Repeat for every .sql.gz file in the databases/ folder. Take your time โ one at a time to catch any individual errors.
sudo mysql --defaults-file=/etc/mysql/debian.cnf \
-e "SHOW DATABASES;"
# Spot-check row counts in a key table (replace DB_NAME and TABLE_NAME):
sudo mysql --defaults-file=/etc/mysql/debian.cnf \
-e "SELECT COUNT(*) FROM DB_NAME.TABLE_NAME;"
sudo crontab /tmp/nas16-restore/nas16-backup-*/cron/root-crontab.txt # Verify it was applied: sudo crontab -l
OMV UI โ System โ Scheduled Jobs โ Add Enabled: Yes Name: NAS16 Backup Command: sudo /usr/scripts/omv/nas16-backup.sh Minute: 0 Hour: 2 Day of month: */3 Month: * Day of week: * โ Save โ Apply
scp nas16-backup.sh rufusking@<NAS16-IP>:/usr/scripts/omv/nas16-backup.sh chmod +x /usr/scripts/omv/nas16-backup.sh
The script lives outside /etc so it is not automatically restored by the /etc rsync. Always re-deploy it manually.
# Test each hosted domain or IP in your browser. # Check Apache error log if anything fails: sudo tail -50 /var/log/apache2/error.log
sudo rm -rf /tmp/nas16-restore
# Option A โ OMV UI: System โ Scheduled Jobs โ NAS16 Backup โ Run # Option B โ SSH on NAS16: sudo /usr/scripts/omv/nas16-backup.sh # Verify it completed successfully: ls -lh /export/kingdezignsnas-16/Backups/NAS16/ cat /export/kingdezignsnas-16/Backups/NAS16/backup.log
sudo zpool scrub kingdezignsnas-16 # Check results a few minutes later: sudo zpool status
A healthy result:
scan: scrub repaired 0B in 00:xx:xx with 0 errors
sudo zpool status โ failed drive shows FAULTED or UNAVAIL
RAIDZ2 tolerates up to 2 simultaneous drive failures. The pool is still fully readable and writable. Complete the full restore procedure first, then replace the failed drive.
sudo zpool status โ two drives show FAULTED or UNAVAIL
Data is at risk but still accessible. Complete the restore immediately and replace both drives as fast as possible.
# Scan all connected devices for importable pools: sudo zpool import # If kingdezignsnas-16 appears in the list, force import: sudo zpool import -f kingdezignsnas-16
If no pools are found at all, PCIe is likely not enabled. Verify Steps 8โ9 (boot config) were applied correctly and reboot again before retrying.
# Access backup files directly via the ZFS mount point: ls /kingdezignsnas-16/Backups/NAS16/
/export/kingdezignsnas-16/ is created by OMV when it mounts the filesystem. Use /kingdezignsnas-16/ as the base path for all restore commands until OMV is fully restored.
| Area | NAS08 | NAS16 |
|---|---|---|
| Primary role | Docker containers (Pi-hole, Plex, Vaultwarden, Nextcloud, NPM) | Web server (Apache/PHP), databases (MariaDB), Webmin admin |
| What's backed up beyond /etc + OMV | Docker Compose files, Pi-hole data, Plex config/metadata | Apache vhosts, PHP config, MariaDB dumps, Webmin config |
| Website files | N/A | Intentionally excluded โ stored on NAS drives, covered by redundancy |
| Database backup | None (no databases) | Full mysqldump of all user databases, .sql.gz per database |
| Backup destination | /export/kingdezigns-all/Backups/NAS08/ | /export/kingdezignsnas-16/Backups/NAS16/ |
| ZFS pool name | kingdezignsnas | kingdezignsnas-16 (assumed โ verify with sudo zpool list) |
| Recovery phases | 9 phases, 34 steps | 10 phases, 40 steps |
The script was written based on information provided and follows Raspberry Pi OS / Debian conventions. Verify the following on NAS16 before treating any backup as production-ready.
| Item | Assumed value | How to verify |
|---|---|---|
| ZFS pool name | kingdezignsnas-16 |
sudo zpool list |
| Backup destination path | /export/kingdezignsnas-16/Backups/NAS16/ |
ls /export/ โ confirm share name matches |
| MariaDB auth method | Uses /etc/mysql/debian.cnf (maintenance account, no password when run as root) |
Run: sudo mysql --defaults-file=/etc/mysql/debian.cnf -e "SHOW DATABASES;" โ should work without password |
| PHP version(s) | Auto-detected from /etc/php/*/ |
php -v and ls /etc/php/ |
| Apache config location | /etc/apache2/ (standard Debian) |
apache2 -V โ confirms config path |
| Webmin config location | /etc/webmin/ |
ls /etc/webmin/ |
| Item | Old value | New value |
|---|---|---|
| NAS16 โ Backup status | None |
Automated โ every 3 days โ 30-day retention |
| NAS16 โ Backup destination | None |
/export/kingdezignsnas-16/Backups/NAS16/ |
| NAS16 โ Backup script | None |
/usr/scripts/omv/nas16-backup.sh |
| NAS16 โ PCIe requirement | not documented |
dtparam=pciex1 + dtparam=pciex1_gen=3 required in /boot/firmware/config.txt on fresh OS |
| NAS16 โ Web stack | not documented |
Apache ยท PHP ยท MariaDB ยท Webmin ยท Adminer |
| NAS16 โ Recovery plan | None |
NAS16-Backup-Summary.html โ 40 steps across 10 phases + ZFS troubleshooting |