nas08-scripts/Backup Scripts/NAS08-Backup-Summary.html
2026-07-26 21:34:22 -04:00

923 lines
39 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>