nas08-scripts/Backup Scripts/NAS08-Backup-Summary.html

924 lines
39 KiB
HTML
Raw Permalink Normal View History

2026-07-26 21:34:22 -04:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KingDezigns — NAS08 Automated Backup Setup Summary</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #f7f6f2;
--surface: #ffffff;
--surface-alt: #f1f0eb;
--border: #e2e0d8;
--border-strong: #c8c5ba;
--text-primary: #1a1917;
--text-secondary: #6b6960;
--text-muted: #9b9890;
--green-bg: #eaf3de;
--green-border: #97c459;
--green-text: #2d5a0e;
--red-bg: #fcebeb;
--red-border: #f09595;
--red-text: #7a1f1f;
--amber-bg: #faeeda;
--amber-border: #fac775;
--amber-text: #633806;
--coral-bg: #faece7;
--coral-border: #f0997b;
--coral-text: #4a1b0c;
--mono: 'IBM Plex Mono', monospace;
--sans: 'IBM Plex Sans', sans-serif;
}
body {
font-family: var(--sans);
font-size: 14px;
background: var(--bg);
color: var(--text-primary);
line-height: 1.7;
padding: 2.5rem 1.5rem;
}
.page { max-width: 860px; margin: 0 auto; }
header {
border-bottom: 1px solid var(--border-strong);
padding-bottom: 1.25rem;
margin-bottom: 2rem;
}
header h1 {
font-family: var(--mono);
font-size: 18px;
font-weight: 500;
letter-spacing: -0.02em;
margin-bottom: 6px;
}
.meta {
font-size: 12px;
color: var(--text-muted);
font-family: var(--mono);
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.section { margin-bottom: 2.25rem; }
.section-title {
font-family: var(--mono);
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 10px;
}
.section-title::before {
content: attr(data-num);
background: var(--text-primary);
color: var(--bg);
font-size: 10px;
width: 18px;
height: 18px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.section-title::after {
content: '';
flex: 1;
height: 1px;
background: var(--border);
}
p { margin-bottom: 0.75rem; color: var(--text-primary); }
p:last-child { margin-bottom: 0; }
.badge-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 1rem; }
.badge {
font-family: var(--mono);
font-size: 11px;
padding: 3px 10px;
border-radius: 3px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text-secondary);
}
.badge.red { background: var(--red-bg); color: var(--red-text); border-color: var(--red-border); }
.badge.green { background: var(--green-bg); color: var(--green-text); border-color: var(--green-border); }
.badge.amber { background: var(--amber-bg); color: var(--amber-text); border-color: var(--amber-border); }
.step {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
padding: 1rem 1.25rem;
margin-bottom: 0.6rem;
}
.step-header {
font-family: var(--mono);
font-size: 12px;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 0.6rem;
display: flex;
align-items: center;
gap: 8px;
}
.step-num {
background: var(--surface-alt);
border: 1px solid var(--border);
border-radius: 50%;
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 10px;
flex-shrink: 0;
color: var(--text-muted);
}
pre {
background: var(--surface-alt);
border: 1px solid var(--border);
border-radius: 4px;
padding: 10px 12px;
font-family: var(--mono);
font-size: 12px;
overflow-x: auto;
margin: 0.5rem 0;
white-space: pre;
line-height: 1.6;
}
code {
font-family: var(--mono);
font-size: 12px;
background: var(--surface-alt);
padding: 1px 5px;
border-radius: 3px;
border: 1px solid var(--border);
}
.why {
font-size: 12px;
color: var(--text-muted);
margin-top: 0.4rem;
padding-left: 2px;
}
.why::before { content: '↳ why: '; font-family: var(--mono); }
.note {
font-size: 12px;
color: var(--text-secondary);
margin-top: 0.5rem;
padding-left: 2px;
}
.note::before { content: '📌 '; }
.result { font-size: 12px; margin-top: 0.35rem; padding-left: 2px; }
.result.pass { color: var(--green-text); }
.result.pass::before { content: '✓ '; font-family: var(--mono); }
.result.fail { color: var(--red-text); }
.result.fail::before { content: '✗ '; font-family: var(--mono); }
.result.neutral { color: var(--text-secondary); }
.result.neutral::before { content: '→ '; font-family: var(--mono); }
.callout { border-radius: 6px; padding: 1rem 1.25rem; margin-bottom: 0.75rem; }
.callout.coral { background: var(--coral-bg); border: 1px solid var(--coral-border); }
.callout.coral p { color: var(--coral-text); }
.callout.coral pre { background: #fdf0eb; border-color: var(--coral-border); }
.callout.amber { background: var(--amber-bg); border: 1px solid var(--amber-border); }
.callout.amber p { color: var(--amber-text); }
.callout.amber pre { background: #fdf5e6; border-color: var(--amber-border); }
.callout.amber code { background: #fdf5e6; border-color: var(--amber-border); color: var(--amber-text); }
.callout.green { background: var(--green-bg); border: 1px solid var(--green-border); }
.callout.green p { color: var(--green-text); }
.callout.green pre { background: #d8efc0; border-color: var(--green-border); }
.clue-label {
font-family: var(--mono);
font-size: 10px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--amber-text);
margin-bottom: 8px;
}
.phase-label {
font-family: var(--mono);
font-size: 10px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-primary);
background: var(--surface-alt);
border: 1px solid var(--border-strong);
border-radius: 4px;
padding: 5px 12px;
margin: 1.5rem 0 0.6rem 0;
display: inline-block;
}
.script-box { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; margin-bottom: 1rem; }
.script-row { padding: 0.75rem 1.25rem; border-bottom: 1px solid var(--border); }
.script-row:last-child { border-bottom: none; }
.script-label { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); margin-bottom: 6px; }
.script-row pre { margin: 0; }
table { width: 100%; border-collapse: collapse; font-size: 13px; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
th { text-align: left; padding: 8px 14px; font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); background: var(--surface-alt); border-bottom: 1px solid var(--border); font-weight: 500; }
td { padding: 9px 14px; border-bottom: 1px solid var(--border); vertical-align: top; line-height: 1.5; }
tr:last-child td { border-bottom: none; }
.footer {
font-family: var(--mono);
font-size: 11px;
color: var(--text-muted);
margin-top: 2.5rem;
padding-top: 1rem;
border-top: 1px solid var(--border);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 8px;
}
</style>
</head>
<body>
<div class="page">
<header>
<h1>KingDezigns — NAS08 Automated Backup Setup summary</h1>
<div class="meta">
<span>📅 2026-05-11</span>
<span>🖥 NAS08 / Raspberry Pi 5</span>
<span>⚙️ OpenMediaVault (OMV)</span>
<span>🐳 Docker Compose</span>
<span>💾 ZFS RAIDZ2 — Penta SATA HAT</span>
</div>
</header>
<!-- SECTION 1 — THE GOAL -->
<div class="section">
<div class="section-title" data-num="1">The goal</div>
<p>NAS08 had no automated recovery path. A software or hardware failure — corrupt SD card, bad OMV update, runaway script — would have required a full manual rebuild of OMV, all Docker containers, Pi-hole, Plex, Vaultwarden, Nextcloud, and nginx-proxy-manager with no documented procedure and no saved state.</p>
<div class="badge-row">
<span class="badge amber">No OS backup</span>
<span class="badge amber">No automated recovery plan</span>
<span class="badge amber">No ZFS restore procedure</span>
<span class="badge amber">Plex music library previously lost to a bad script</span>
</div>
<p>The goal was to create a fully automated, scheduled backup of the OS and configuration layer — not the NAS data drives — that could restore NAS08 to full operation within approximately 90 minutes after a failure, with no manual intervention during normal operation.</p>
<div class="callout amber" style="margin-top:1rem;">
<div class="clue-label">⚠ Critical — store this document off NAS08</div>
<p>Keep a copy of this document on your workstation, a USB drive, or in print. If NAS08 is down you cannot read files stored on it.</p>
</div>
</div>
<!-- SECTION 2 — DIAGNOSTIC COMMANDS -->
<div class="section">
<div class="section-title" data-num="2">Discovery commands run &amp; why</div>
<div class="step">
<div class="step-header"><span class="step-num">1</span> Locate Docker app data directories</div>
<pre>ls /export/kingdezigns-all/Docker
ls /export/kingdezigns-all/Docker/Compose</pre>
<p class="why">Needed to confirm where application configs and compose files lived before writing backup paths into the script.</p>
<p class="result pass">Docker root confirmed at <code>/export/kingdezigns-all/Docker/</code> with Compose subfolder containing all stacks: nextcloud, nginx-proxy-manager, pihole, plex, vaultwarden.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">2</span> Check first archive size and contents</div>
<pre>ls -lh /export/kingdezigns-all/Backups/NAS08/nas08-backup-2026-05-11.tar.gz
tar -tzf /export/kingdezigns-all/Backups/NAS08/nas08-backup-2026-05-11.tar.gz | head -40</pre>
<p class="why">Verified the archive was created and inspected its contents to catch bloat or missing sections.</p>
<p class="result fail">Archive was 1.4GB — Vaultwarden icon_cache and full Plex config were included without exclusions, inflating the size unnecessarily.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">3</span> Measure sizes across all Docker folders</div>
<pre>sudo du -sh /export/kingdezigns-all/Docker/Compose/*/
sudo du -sh /export/kingdezigns-all/Docker/pihole/
sudo du -sh /export/kingdezigns-all/Docker/plex/</pre>
<p class="why">Identify where archive bulk was coming from before adding exclusions.</p>
<p class="result neutral">Plex at 1.8GB was the dominant size. Pi-hole at 27MB acceptable as-is. Compose folders were tiny (3.5K–7.4M each).</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">4</span> Drill into Plex config subfolder breakdown</div>
<pre>sudo du -sh /export/kingdezigns-all/Docker/plex/config/Library/Application\ Support/Plex\ Media\ Server/*/</pre>
<p class="why">Identify which Plex subfolders were safe to exclude vs which contained manually curated data worth preserving.</p>
<p class="result pass">Cache (24M), Logs (2M), Crash Reports (23K) identified as safe exclusions. Media (655M) and Metadata (956M) confirmed as music organization and library data — kept.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">5</span> Inspect ZFS pool configuration</div>
<pre>sudo zpool list
sudo zpool status
sudo zfs list</pre>
<p class="why">Document exact pool name, drive identifiers, RAID type, and mount point needed for recovery plan ZFS steps.</p>
<p class="result pass">Pool: <code>kingdezignsnas</code> — RAIDZ2 across 4 × 1TB SSDs — ONLINE — mounted at <code>/kingdezignsnas</code> — last scrub clean, no errors.</p>
</div>
</div>
<!-- SECTION 3 — ISSUES ENCOUNTERED -->
<div class="section">
<div class="section-title" data-num="3">Issues encountered during setup</div>
<div class="callout coral">
<p>On first run the backup destination directory did not exist, causing the logging system to fail immediately before any backup work could begin.</p>
</div>
<div class="callout amber">
<div class="clue-label">⚠ Error — first run</div>
<p style="margin-bottom:6px;">Script failed with a tee write error before reaching any backup steps.</p>
<pre>tee: /export/kingdezigns-all/Backups/NAS08/backup.log: No such file or directory</pre>
<p style="margin-top:8px;"><code>Backups/NAS08/</code> had not been created yet. Fixed by creating it manually. The script now handles this automatically via <code>mkdir -p</code> on every run.</p>
</div>
<div class="callout coral" style="margin-top: 0.75rem;">
<p>SCP to <code>/usr/local/bin/</code> failed with permission denied — that path requires root SCP access which rufusking does not have.</p>
</div>
<div class="callout green">
<p><strong>Resolution:</strong> Created <code>/usr/scripts/omv/</code> owned by rufusking. SCP now works without root. Script still runs with <code>sudo</code> for root-level operations at runtime.</p>
</div>
</div>
<!-- SECTION 4 — SCRIPTS / FILES CREATED -->
<div class="section">
<div class="section-title" data-num="4">Scripts / files created</div>
<div class="script-box">
<div class="script-row">
<div class="script-label">Backup Script Location</div>
<pre>/usr/scripts/omv/nas08-backup.sh</pre>
</div>
<div class="script-row">
<div class="script-label">What It Backs Up</div>
<pre>OMV config — omv-confbak export + raw /etc/openmediavault/config.xml
/etc — full system config (network, fstab, nginx, cron, etc.)
Docker Compose — all stacks + global.env (vaultwarden icon_cache excluded)
Pi-hole data — /export/kingdezigns-all/Docker/pihole/
Plex data — full config minus Cache/, Logs/, Crash Reports/
Media/ and Metadata/ KEPT (music org + library data)
Shared folder — /export/kingdezigns-all/Docker/Shared/
Crontab — root crontab + /etc/cron.d entries
MANIFEST.txt — baked-in restore instructions and OMV version info</pre>
</div>
<div class="script-row">
<div class="script-label">Output Paths</div>
<pre>/export/kingdezigns-all/Backups/NAS08/nas08-backup-YYYY-MM-DD.tar.gz
/export/kingdezigns-all/Backups/NAS08/backup.log</pre>
</div>
<div class="script-row">
<div class="script-label">Retention</div>
<pre>10 archives retained (~30 days coverage) — older archives auto-deleted on each run</pre>
</div>
<div class="script-row">
<div class="script-label">Expected Size</div>
<pre>~1.4GB per archive — ~14GB total at max retention
450GB free on data drive — well within capacity</pre>
</div>
<div class="script-row">
<div class="script-label">Schedule via OMV UI</div>
<pre>System → Scheduled Jobs → Add
Name: NAS08 Backup
Command: /usr/scripts/omv/nas08-backup.sh
Minute: 0
Hour: 2
Day of month: */3
Month: *
Day of week: *
Runs automatically at 2:00 AM every 3 days</pre>
</div>
<div class="script-row">
<div class="script-label">Manual Run</div>
<pre>sudo /usr/scripts/omv/nas08-backup.sh
# or: OMV UI → System → Scheduled Jobs → Run</pre>
</div>
</div>
</div>
<!-- SECTION 5 — FULL RECOVERY PROCEDURE -->
<div class="section">
<div class="section-title" data-num="5">Full recovery procedure</div>
<div class="callout amber">
<div class="clue-label">⚠ Before You Start</div>
<p>You need: a workstation with internet, a replacement SD card (16GB+), Raspberry Pi Imager, SSH access, and your rufusking password. Physically connect all 4 ZFS drives to the Penta SATA HAT before powering on.</p>
</div>
<!-- PHASE 1 -->
<div class="phase-label">Phase 1 — Flash the OS</div>
<div class="step">
<div class="step-header"><span class="step-num">1</span> Download Raspberry Pi Imager — workstation</div>
<pre>https://www.raspberrypi.com/software/</pre>
<p class="note">Download and install for your OS (Windows / Mac / Linux).</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">2</span> Flash Raspberry Pi OS Lite (64-bit) — workstation</div>
<pre>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 : NAS08
Username : rufusking
Password : your usual password
Services : Enable SSH → Use password authentication
→ Save → Yes → Yes (confirm flash and verify)</pre>
<p class="note">Wait for the flash and verify to complete fully before removing the SD card.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">3</span> Boot the Raspberry Pi</div>
<pre>1. Insert SD card into Raspberry Pi 5
2. Connect Penta SATA HAT with all 4 ZFS drives plugged in
3. Power on
4. Wait 2–3 minutes for first boot to complete</pre>
</div>
<!-- PHASE 2 -->
<div class="phase-label">Phase 2 — Install OpenMediaVault</div>
<div class="callout amber">
<div class="clue-label">⚠ Note</div>
<p>The OMV install method may change in the future. Verify the current script at <code>https://github.com/OpenMediaVault-Plugin-Developers/installScript</code> before running. Steps below reflect the method as of 2026-05-11.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">4</span> SSH into NAS08 — workstation</div>
<pre>ssh rufusking@192.168.150.35</pre>
<p class="note">If the static IP is not yet assigned, log into UniFi at <code>http://192.168.100.1</code>, find NAS08 in Clients, and SSH to its temporary IP instead.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">5</span> Update the OS — NAS08</div>
<pre>sudo apt-get update && sudo apt-get upgrade -y</pre>
<p class="note">Wait for the prompt to return before continuing. This may take a few minutes.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">6</span> Install OpenMediaVault — NAS08</div>
<pre>sudo wget -O - https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install | sudo bash</pre>
<p class="note">Takes 10–20 minutes. The Pi may reboot automatically. If it does, SSH back in and wait for the script to finish. Do not interrupt it.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">7</span> Verify OMV is running — browser on workstation</div>
<pre>http://192.168.150.35
Default login:
Username: admin
Password: openmediavault</pre>
<p class="note">Confirm the OMV login page loads. Do not configure anything yet — the restore handles all configuration.</p>
</div>
<!-- PHASE 3 -->
<div class="phase-label">Phase 3 — Enable PCIe for Penta SATA HAT</div>
<div class="callout coral">
<p>The Raspberry Pi 5 does not expose PCIe by default. Without enabling it, the Penta SATA HAT and all 4 ZFS drives are completely invisible to the OS. This must be done before any ZFS commands will work.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">8</span> Edit boot config to enable PCIe — NAS08</div>
<pre>sudo nano /boot/firmware/config.txt</pre>
<p>Scroll to find the line <code>arm_boost=1</code> and add these lines immediately after it:</p>
<pre># Enable PCIe
dtparam=pciex1
dtparam=pciex1_gen=3</pre>
<p>Save and exit:</p>
<pre>Ctrl+X → Y → Enter</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">9</span> Reboot to apply PCIe config — NAS08</div>
<pre>sudo reboot</pre>
<p>Wait 2–3 minutes, then SSH back in:</p>
<pre>ssh rufusking@192.168.150.35</pre>
</div>
<!-- PHASE 4 -->
<div class="phase-label">Phase 4 — Import ZFS Pool</div>
<div class="step">
<div class="step-header"><span class="step-num">10</span> Install ZFS tools — NAS08</div>
<pre>sudo apt-get install -y zfsutils-linux</pre>
<p class="note">Installs the ZFS kernel modules and CLI tools. Required on every fresh OS install.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">11</span> Verify all 4 drives are visible — NAS08</div>
<pre>lsblk</pre>
<p>You should see 4 drives listed (typically <code>sda</code> through <code>sdd</code>). If any are missing, check physical connections and reboot:</p>
<pre>sudo reboot
# SSH back in, then run lsblk again</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">12</span> Import the ZFS pool — NAS08</div>
<pre>sudo zpool import kingdezignsnas</pre>
<p class="note">The pool name <code>kingdezignsnas</code> is stored on the drives themselves — it will be recognized on a fresh OS automatically. If the previous OS failed uncleanly, force the import:</p>
<pre># Only use -f if the standard import fails:
sudo zpool import -f kingdezignsnas</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">13</span> Verify pool imported correctly — NAS08</div>
<pre>sudo zpool status</pre>
<p>All 4 drives must show <strong>ONLINE</strong>. Expected output:</p>
<pre> pool: kingdezignsnas
state: ONLINE
config:
kingdezignsnas ONLINE
raidz2-0 ONLINE
ata-CT1000BX500SSD1_2539E9CB8529 ONLINE
ata-CT1000BX500SSD1_2534E9C97DAD ONLINE
ata-CT1000BX500SSD1_2530E9C74CD1 ONLINE
ata-CT1000BX500SSD1_2539E9CB84F8 ONLINE
errors: No known data errors</pre>
<p class="note">If any drive shows FAULTED or DEGRADED, do not proceed. See ZFS Troubleshooting at the bottom of this document.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">14</span> Confirm backup files are accessible — NAS08</div>
<pre>sudo zfs list
ls /kingdezignsnas/
ls /kingdezignsnas/Backups/NAS08/
# List archives sorted newest first:
ls -lht /kingdezignsnas/Backups/NAS08/nas08-backup-*.tar.gz</pre>
<p class="note">Use <code>/kingdezignsnas/</code> directly at this stage. The <code>/export/kingdezigns-all/</code> path is recreated by OMV after the config restore in Phase 6.</p>
</div>
<!-- PHASE 5 -->
<div class="phase-label">Phase 5 — Extract the Backup Archive</div>
<div class="step">
<div class="step-header"><span class="step-num">15</span> Create restore working directory — NAS08</div>
<pre>sudo mkdir -p /tmp/nas08-restore</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">16</span> Extract the most recent backup — NAS08</div>
<pre># Replace YYYY-MM-DD with the actual archive date from step 14
sudo tar -xzf /kingdezignsnas/Backups/NAS08/nas08-backup-YYYY-MM-DD.tar.gz \
-C /tmp/nas08-restore</pre>
<p class="note">This takes a few minutes — the archive is ~1.4GB. Wait for the prompt to return.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">17</span> Confirm extraction and read the manifest — NAS08</div>
<pre># Confirm all folders are present:
ls /tmp/nas08-restore/
ls /tmp/nas08-restore/nas08-backup-*/
# Read the manifest:
cat /tmp/nas08-restore/nas08-backup-*/MANIFEST.txt</pre>
<p>You should see: <code>omv-config/</code>&nbsp; <code>etc/</code>&nbsp; <code>docker-compose/</code>&nbsp; <code>app-data/</code>&nbsp; <code>cron/</code>&nbsp; <code>MANIFEST.txt</code></p>
</div>
<!-- PHASE 6 -->
<div class="phase-label">Phase 6 — Restore System Configuration</div>
<div class="step">
<div class="step-header"><span class="step-num">18</span> Restore /etc — NAS08</div>
<pre>sudo rsync -a /tmp/nas08-restore/nas08-backup-*/etc/ /etc/</pre>
<p class="note">Restores all system configuration: network settings, nginx, fstab, cron, and everything else under /etc.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">19</span> Restore OMV configuration — NAS08</div>
<pre># Copy saved OMV config back into place:
sudo cp /tmp/nas08-restore/nas08-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 (shares, users, plugins, schedules):
sudo omv-salt deploy run all</pre>
<p class="note">The last command takes several minutes. Do not interrupt it — let it complete fully.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">20</span> Reboot and verify OMV — NAS08 then browser</div>
<pre>sudo reboot</pre>
<p>After 2–3 minutes, SSH back in and check:</p>
<pre>ssh rufusking@192.168.150.35</pre>
<p>Then open a browser on your workstation:</p>
<pre>http://192.168.150.35</pre>
<p>Log in and verify: shares, users, and settings are present. Go to <strong>Storage → File Systems</strong> and confirm the ZFS pool is mounted and <code>/export/kingdezigns-all</code> is available.</p>
</div>
<!-- PHASE 7 -->
<div class="phase-label">Phase 7 — Restore Docker and Application Data</div>
<div class="step">
<div class="step-header"><span class="step-num">21</span> Verify Docker is installed — NAS08</div>
<pre>sudo docker ps</pre>
<p>If Docker is not found, install it:</p>
<pre>sudo apt-get install -y docker-compose-plugin</pre>
<p>If the OMV Compose plugin is missing, reinstall via OMV UI:</p>
<pre>OMV UI → System → Plugins → search "compose" → Install</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">22</span> Restore Docker Compose files — NAS08</div>
<pre>sudo rsync -a /tmp/nas08-restore/nas08-backup-*/docker-compose/ \
/export/kingdezigns-all/Docker/Compose/
# Verify files landed correctly:
ls /export/kingdezigns-all/Docker/Compose/</pre>
<p>Expected: <code>nextcloud/</code>&nbsp; <code>nginx-proxy-manager/</code>&nbsp; <code>pihole/</code>&nbsp; <code>plex/</code>&nbsp; <code>vaultwarden/</code>&nbsp; <code>global.env</code></p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">23</span> Restore Pi-hole data — NAS08</div>
<pre>sudo rsync -a /tmp/nas08-restore/nas08-backup-*/app-data/pihole/ \
/export/kingdezigns-all/Docker/pihole/</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">24</span> Restore Plex data — NAS08</div>
<pre>sudo rsync -a /tmp/nas08-restore/nas08-backup-*/app-data/plex/ \
/export/kingdezigns-all/Docker/plex/</pre>
<p class="note">This restores your music organization (Media/), library metadata (Metadata/), and watch history (Plug-in Support/). These are the folders that represent weeks of manual work and are the primary reason this backup exists.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">25</span> Restore Shared folder — NAS08</div>
<pre>sudo rsync -a /tmp/nas08-restore/nas08-backup-*/app-data/shared/ \
/export/kingdezigns-all/Docker/Shared/</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">26</span> Fix permissions on all Docker folders — NAS08</div>
<pre>sudo chown -R root:users /export/kingdezigns-all/Docker/
sudo chmod -R 775 /export/kingdezigns-all/Docker/</pre>
</div>
<!-- PHASE 8 -->
<div class="phase-label">Phase 8 — Bring Containers Back Up</div>
<div class="step">
<div class="step-header"><span class="step-num">27</span> Start each container one at a time — NAS08</div>
<pre>cd /export/kingdezigns-all/Docker/Compose/pihole && sudo docker compose up -d
cd /export/kingdezigns-all/Docker/Compose/nginx-proxy-manager && sudo docker compose up -d
cd /export/kingdezigns-all/Docker/Compose/vaultwarden && sudo docker compose up -d
cd /export/kingdezigns-all/Docker/Compose/nextcloud && sudo docker compose up -d
cd /export/kingdezigns-all/Docker/Compose/plex && sudo docker compose up -d</pre>
<p class="note">Start one at a time — not all at once — so errors from individual containers are not lost in combined output.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">28</span> Verify all containers are running — NAS08</div>
<pre>sudo docker ps</pre>
<p>All containers should show status <strong>Up</strong>. If any show <strong>Exited</strong>, check that container's logs:</p>
<pre>sudo docker logs pihole
sudo docker logs nginx-proxy-manager
sudo docker logs vaultwarden
sudo docker logs nextcloud
sudo docker logs plex</pre>
</div>
<!-- PHASE 9 -->
<div class="phase-label">Phase 9 — Final Steps &amp; Verification</div>
<div class="step">
<div class="step-header"><span class="step-num">29</span> Verify the backup script is in place — NAS08</div>
<pre>ls -lh /usr/scripts/omv/nas08-backup.sh</pre>
<p>If missing (it lives outside /etc so may not have restored automatically), copy it from your workstation:</p>
<pre># On your workstation:
scp nas08-backup.sh rufusking@192.168.150.35:/usr/scripts/omv/nas08-backup.sh
# On NAS08:
chmod +x /usr/scripts/omv/nas08-backup.sh</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">30</span> Restore the crontab — NAS08</div>
<pre>sudo crontab /tmp/nas08-restore/nas08-backup-*/cron/root-crontab.txt
# Verify it was applied:
sudo crontab -l</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">31</span> Reschedule the backup job in OMV UI</div>
<pre>OMV UI → System → Scheduled Jobs → Add
Enabled: Yes
Name: NAS08 Backup
Command: /usr/scripts/omv/nas08-backup.sh
Minute: 0
Hour: 2
Day of month: */3
Month: *
Day of week: *
→ Save</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">32</span> Clean up the restore working directory — NAS08</div>
<pre>sudo rm -rf /tmp/nas08-restore</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">33</span> Run a fresh backup immediately to create a new baseline</div>
<pre># Option A — OMV UI:
System → Scheduled Jobs → NAS08 Backup → Run
# Option B — SSH on NAS08:
sudo /usr/scripts/omv/nas08-backup.sh
# Verify it completed successfully:
ls -lh /export/kingdezigns-all/Backups/NAS08/
cat /export/kingdezigns-all/Backups/NAS08/backup.log</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">34</span> Run a ZFS scrub to verify data integrity — NAS08</div>
<pre>sudo zpool scrub kingdezignsnas
# Check results a few minutes later:
sudo zpool status</pre>
<p>A healthy result:</p>
<pre>scan: scrub repaired 0B in 00:xx:xx with 0 errors</pre>
</div>
<!-- ZFS TROUBLESHOOTING -->
<div class="phase-label">ZFS Troubleshooting</div>
<div class="step">
<div class="step-header"><span class="step-num">—</span> Pool shows DEGRADED — 1 drive failed</div>
<pre>sudo zpool status ← failed drive shows FAULTED or UNAVAIL</pre>
<p>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. Do not skip recovery steps.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">—</span> Pool shows DEGRADED — 2 drives failed</div>
<pre>sudo zpool status ← two drives show FAULTED or UNAVAIL</pre>
<p>Data is at risk but still accessible. Complete the restore immediately and replace both drives as fast as possible. Seek assistance before doing anything else if unsure.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">—</span> Pool cannot be imported — not found</div>
<pre># Scan all connected devices for importable pools:
sudo zpool import
# If kingdezignsnas appears in the list, force import:
sudo zpool import -f kingdezignsnas</pre>
<p class="note">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.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">—</span> Pool imported but /export/kingdezigns-all is missing</div>
<pre># Access backup files directly via the ZFS mount point:
ls /kingdezignsnas/Backups/NAS08/</pre>
<p class="note"><code>/export/kingdezigns-all/</code> is created by OMV when it mounts the filesystem. Use <code>/kingdezignsnas/</code> as the base path for all restore commands until OMV is fully restored.</p>
</div>
</div>
<!-- SECTION 6 — LESSONS LEARNED -->
<div class="section">
<div class="section-title" data-num="6">Lessons learned</div>
<table>
<thead>
<tr><th>Lesson</th><th>Detail</th></tr>
</thead>
<tbody>
<tr>
<td>PCIe must be enabled before ZFS can see the drives</td>
<td>The Raspberry Pi 5 Penta SATA HAT requires PCIe to be explicitly enabled in <code>/boot/firmware/config.txt</code>. On a fresh OS this is never set. Without it all 4 ZFS drives are invisible and the pool cannot be imported.</td>
</tr>
<tr>
<td>ZFS pool import must happen before any restore steps</td>
<td>Without importing the pool, the backup files are completely inaccessible. It is now Phase 4, immediately after enabling PCIe, before any restore work begins.</td>
</tr>
<tr>
<td>Plex Media/ and Metadata/ contain irreplaceable manually curated data</td>
<td>These folders hold music organization, artwork, and library structure that took weeks of manual work. They must always be included in backups even though they are large (~1.6GB combined).</td>
</tr>
<tr>
<td>Never run scripts that touch OMV without a tested recovery plan first</td>
<td>A prior script run by another AI tool broke OMV and wiped Plex music organization. This session was motivated by that incident. Backup first, change second.</td>
</tr>
<tr>
<td>Custom scripts belong in /usr/scripts/ not /usr/local/bin/</td>
<td>Writing to /usr/local/bin/ requires root SCP access. A dedicated /usr/scripts/ directory owned by rufusking avoids this and keeps custom scripts separated from system binaries.</td>
</tr>
<tr>
<td>Always create output directories before the first script run</td>
<td>The script failed on first run because /Backups/NAS08/ did not exist. The script now handles this automatically via mkdir -p, but always verify the path exists before the first run on a new system.</td>
</tr>
<tr>
<td>Vaultwarden icon_cache is large and completely disposable</td>
<td>The icon cache for website favicons was inflating the archive. It regenerates automatically and must always be excluded.</td>
</tr>
<tr>
<td>Recovery documentation must be stored off the device being recovered</td>
<td>A recovery plan stored only on NAS08 is useless when NAS08 is down. Keep copies on a workstation, USB drive, or in print.</td>
</tr>
</tbody>
</table>
</div>
<!-- SECTION 7 — NETWORK MAP UPDATES -->
<div class="section">
<div class="section-title" data-num="7">Network map — items to update</div>
<table>
<thead>
<tr><th>Item</th><th>Old value</th><th>New value</th></tr>
</thead>
<tbody>
<tr>
<td>NAS08 — Hardware detail</td>
<td><code>Raspberry Pi</code></td>
<td><code>Raspberry Pi 5 with Penta SATA HAT</code></td>
</tr>
<tr>
<td>NAS08 — Backup status</td>
<td><code>None</code></td>
<td><code>Automated — every 3 days — 30-day retention</code></td>
</tr>
<tr>
<td>NAS08 — Backup destination</td>
<td><code>None</code></td>
<td><code>/export/kingdezigns-all/Backups/NAS08/</code></td>
</tr>
<tr>
<td>NAS08 — Backup script</td>
<td><code>None</code></td>
<td><code>/usr/scripts/omv/nas08-backup.sh</code></td>
</tr>
<tr>
<td>NAS08 — ZFS pool name</td>
<td><code>not documented</code></td>
<td><code>kingdezignsnas (RAIDZ2, 4 × 1TB SSD)</code></td>
</tr>
<tr>
<td>NAS08 — ZFS mount point</td>
<td><code>not documented</code></td>
<td><code>/kingdezignsnas</code></td>
</tr>
<tr>
<td>NAS08 — PCIe requirement</td>
<td><code>not documented</code></td>
<td><code>dtparam=pciex1 + dtparam=pciex1_gen=3 required in /boot/firmware/config.txt on fresh OS</code></td>
</tr>
<tr>
<td>NAS08 — Recovery plan</td>
<td><code>None</code></td>
<td><code>NAS08-Backup-Summary.html — 34 steps across 9 phases + ZFS troubleshooting</code></td>
</tr>
</tbody>
</table>
</div>
<div class="footer">
<span>KingDezigns Home Network</span>
<span>Generated 2026-05-11</span>
</div>
</div>
</body>
</html>