nas16-scripts/nas/NAS08-to-NAS16-Sync-Summary.html

531 lines
29 KiB
HTML
Raw Permalink Normal View History

2026-07-26 21:21:03 -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 → NAS16 Sync 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); }
.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.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.red { background: var(--red-bg); border: 1px solid var(--red-border); }
.callout.red p { color: var(--red-text); }
.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; }
.clue-label.red { color: var(--red-text); }
.clue-label.green { color: var(--green-text); }
.script-box { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.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; }
.version-tag { font-family: var(--mono); font-size: 10px; background: var(--text-primary); color: var(--bg); padding: 2px 8px; border-radius: 3px; margin-left: 8px; vertical-align: middle; }
</style>
</head>
<body>
<div class="page">
<header>
<h1>KingDezigns — NAS08 → NAS16 Sync Setup Summary <span class="version-tag">v2.0</span></h1>
<div class="meta">
<span>📅 Updated May 18, 2026</span>
<span>🖥 NAS08 (192.168.150.35) → NAS16 (192.168.150.40)</span>
<span>⚙️ OpenMediaVault / Raspberry Pi OS</span>
<span>🔧 rsync + NFSv4 + HTML Email Report</span>
</div>
</header>
<!-- SECTION 1 — THE GOAL -->
<div class="section">
<div class="section-title" data-num="1">The goal</div>
<p>Mirror the <code>Public</code> folder from NAS08 to NAS16, copying only files that have changed. The sync must be lightweight enough for Raspberry Pi hardware, non-destructive (no deletes on NAS16), and scheduled via the OMV Task Scheduler. After every run, an HTML email report is sent summarizing what transferred, what folders were affected, and any errors.</p>
<div class="badge-row">
<span class="badge green">Source: NAS08 — 192.168.150.35</span>
<span class="badge green">Destination: NAS16 — 192.168.150.40</span>
<span class="badge amber">~225,000 files / ~983 GB</span>
<span class="badge">NFSv4 file share mount</span>
<span class="badge">HTML email report</span>
</div>
<p>NAS16 pulls from NAS08 (rather than NAS08 pushing) so the heavier rsync process runs on the machine with more RAM (16GB vs 8GB), leaving NAS08 as a passive file server during the sync.</p>
</div>
<!-- SECTION 2 — FOLDER PATHS -->
<div class="section">
<div class="section-title" data-num="2">Folder paths</div>
<div class="step">
<div class="step-header"><span class="step-num">S</span> Source — NAS08</div>
<pre>/mnt/kingdezigns08/Public/</pre>
<p class="result neutral">NFS share mounted on NAS16 via fstab at boot. Mount verified as non-empty before rsync runs.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">D</span> Destination — NAS16</div>
<pre>/export/kingdezignsnas-16/Public/</pre>
<p class="result neutral">Local path on NAS16. Script verifies directory exists before writing.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num"></span> NAS08-only items (copied on first run)</div>
<pre>16 - Documents/
Savings Card Forms.pdf
kingdezigns08.nas</pre>
<p class="result pass">All three copied successfully on first sync. kingdezigns08.nas included intentionally.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num"></span> Permanently excluded</div>
<pre>/mnt/kingdezigns08/Public/.Trash-1000/</pre>
<p class="why">System trash folder generated by NAS08's desktop environment. Never needed in backup. Excluded via <code>--exclude='.Trash-1000/'</code> in rsync flags.</p>
<p class="result pass">No longer appears in logs or emails.</p>
</div>
</div>
<!-- SECTION 3 — KEY DECISIONS -->
<div class="section">
<div class="section-title" data-num="3">Key decisions</div>
<div class="callout amber">
<div class="clue-label">Pull vs Push</div>
<p>NAS16 pulls from NAS08 via the mounted NFS share. rsync runs entirely on NAS16 to keep NAS08 load minimal — NAS08 is passive during the sync window.</p>
</div>
<div class="callout amber">
<div class="clue-label">NFSv4 File Share vs SSH</div>
<p>NFS share used instead of SSH. Drive already mounted via fstab on NAS16 — no SSH keys or remote execution needed. NFS maps users by UID. Both machines have <code>rufusking</code> as UID 1000 so permissions resolve correctly over the mount.</p>
</div>
<div class="callout amber">
<div class="clue-label">No --delete flag</div>
<p>Files on NAS16 that do not exist on NAS08 are left untouched. NAS16 is a backup, not a strict mirror. This protects NAS16-only files from accidental deletion.</p>
</div>
<div class="callout amber">
<div class="clue-label">--update flag (not --checksum)</div>
<p>rsync skips files where the NAS16 copy is <em>newer</em> than NAS08. This is lightweight (uses timestamps, not file hashing) and protects any edits made directly on NAS16.</p>
</div>
<div class="callout green">
<p><strong>Schedule:</strong> Every other day at 2:30 AM via OMV Task Scheduler. NAS08 runs its own <code>nas16-backup.sh</code> at 2:00 AM (finishes ~2:05 AM). The 25-minute buffer prevents overlap on heavy nights.</p>
</div>
</div>
<!-- SECTION 4 — SETUP STEPS -->
<div class="section">
<div class="section-title" data-num="4">Setup steps performed</div>
<div class="step">
<div class="step-header"><span class="step-num">1</span> Created script directory on NAS16</div>
<pre>sudo mkdir /usr/scripts/nas
sudo chown rufusking:users /usr/scripts/nas</pre>
<p class="why">/usr/scripts already existed. /nas subfolder created manually on NAS16. chown required after sudo mkdir — ownership defaults to root otherwise.</p>
<p class="result pass">Directory created and ownership set successfully.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">2</span> Copied script from Linux PC to NAS16</div>
<pre>scp /path/to/nas08_to_nas16_sync.sh rufusking@192.168.150.40:/usr/scripts/nas/</pre>
<p class="result pass">File transferred successfully.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">3</span> Set executable permission on NAS16</div>
<pre>sudo chmod +x /usr/scripts/nas/nas08_to_nas16_sync.sh</pre>
<p class="why">Run directly on NAS16 (not via remote SSH). Makes the script executable by the OMV scheduler.</p>
<p class="result pass">Permission set. Script ready to run.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">4</span> NFS export updated on NAS08 — subtree_check → no_subtree_check</div>
<pre># Changed in OMV UI → Services → NFS → Shares (all four shares)
# Then reloaded on NAS08:
sudo exportfs -ra
# Then remounted on NAS16 to pick up the new export options:
sudo umount /mnt/kingdezigns08
sudo mount /mnt/kingdezigns08</pre>
<p class="why">subtree_check was causing intermittent Permission Denied errors on 02 - Photos, 08 - Taxes, and 16 - Documents during scheduled overnight runs. no_subtree_check is the modern recommended default for private NFS setups.</p>
<p class="result pass">All three folders now accessible. Permission errors resolved.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">5</span> Fixed log directory ownership on NAS16</div>
<pre>sudo chown -R rufusking:users /var/log/nas-sync/</pre>
<p class="why">Log directory was created by root during the first automated OMV run. Script now self-corrects ownership at startup so this never needs to be done manually again.</p>
<p class="result pass">Log writing works cleanly. Self-healing ownership check added to script.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">6</span> OMV Scheduler entry added on NAS16</div>
<pre>Command : /usr/scripts/nas/nas08_to_nas16_sync.sh
Schedule: 30 2 */2 * * (2:30 AM every other day)</pre>
<p class="result pass">Scheduled and confirmed running.</p>
</div>
</div>
<!-- SECTION 5 — SCRIPT DETAILS -->
<div class="section">
<div class="section-title" data-num="5">Script — final state</div>
<div class="script-box">
<div class="script-row">
<div class="script-label">Location on NAS16</div>
<pre>/usr/scripts/nas/nas08_to_nas16_sync.sh</pre>
</div>
<div class="script-row">
<div class="script-label">Log output</div>
<pre>/var/log/nas-sync/nas08_to_nas16_YYYY-MM-DD.log</pre>
</div>
<div class="script-row">
<div class="script-label">Log rotation</div>
<pre>Logs older than 30 days deleted automatically</pre>
</div>
<div class="script-row">
<div class="script-label">rsync flags</div>
<pre>--archive Preserve permissions, timestamps, symlinks, owner/group
--update Skip files where NAS16 copy is newer (protects NAS16 edits)
--human-readable Sizes in KB/MB/GB
--itemize-changes One structured line per transferred file — used for folder activity parsing
--stats Summary totals at end of each run
--exclude Excludes .Trash-1000/ from all operations</pre>
</div>
<div class="script-row">
<div class="script-label">Safety features</div>
<pre>NFS mount check Waits up to 30s for NFS share to be fully responsive before starting
Source empty check Aborts if NAS08 share appears empty — prevents accidental wipe of destination
Dest check Confirms NAS16 folder exists before writing
Smart lock file Stores PID in lock file; auto-clears stale locks if process is no longer running
Log ownership fix Self-corrects /var/log/nas-sync/ ownership on every startup
Exit code Returns rsync exit code so OMV scheduler can detect failures</pre>
</div>
<div class="script-row">
<div class="script-label">Email report sections</div>
<pre>Header/banner SUCCESS / WARNING / FAILED status with color coding
Stats tiles Files scanned, transferred, new files, data moved, duration
Source/dest info IPs, paths, transfer rate, total source size
Folder Activity Collapsed by default — folders with changes show file count,
folders with errors show the error message, no-activity runs
show "all files up to date"
Full rsync log Collapsed by default — complete raw output available on demand</pre>
</div>
<div class="script-row">
<div class="script-label">Email recipient</div>
<pre>rufus.king@kingdezigns.com</pre>
</div>
</div>
</div>
<!-- SECTION 6 — TROUBLESHOOTING LOG -->
<div class="section">
<div class="section-title" data-num="6">Troubleshooting log</div>
<div class="step">
<div class="step-header"><span class="step-num">T1</span> Permission Denied on 02 - Photos, 08 - Taxes, 16 - Documents</div>
<div class="callout red" style="margin-top:8px;">
<div class="clue-label red">Error</div>
<p>rsync: [sender] opendir "/mnt/kingdezigns08/Public/02 - Photos" failed: Permission denied (13)</p>
</div>
<p><strong>Investigation:</strong> ACLs confirmed correct on NAS08 (<code>rufusking:rwx</code> present on all affected folders and subfolders). UIDs matched on both machines (UID 1000). Folders readable manually via NAS16 terminal. Error only appeared during scheduled overnight runs.</p>
<p><strong>Root cause:</strong> <code>subtree_check</code> in the NFS export config on NAS08 was causing intermittent access failures for folders with ACL-based permissions and mixed ownership (some owned by <code>www-data</code> via Nextcloud). subtree_check forces NFS to validate every file access against the export tree — this check fails intermittently on first access after an idle period, especially overnight.</p>
<p><strong>Fix:</strong> Changed all four NFS shares on NAS08 from <code>subtree_check</code> to <code>no_subtree_check</code> via OMV UI. Reloaded exports with <code>sudo exportfs -ra</code>. Remounted share on NAS16. All three folders accessible on next run.</p>
<p class="result pass">Resolved — no Permission Denied errors since fix applied.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">T2</span> tee: Permission Denied on log file</div>
<div class="callout red" style="margin-top:8px;">
<div class="clue-label red">Error</div>
<p>tee: /var/log/nas-sync/nas08_to_nas16_2026-05-17.log: Permission denied</p>
</div>
<p><strong>Root cause:</strong> /var/log/nas-sync/ was created by root during the first automated OMV run. Running the script manually as <code>rufusking</code> couldn't write to a root-owned directory.</p>
<p><strong>Fix:</strong> <code>sudo chown -R rufusking:users /var/log/nas-sync/</code>. Script updated to self-correct ownership on every startup — checks if the log directory owner matches the running user and auto-chowns if not.</p>
<p class="result pass">Resolved — script is now self-healing for this condition.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">T3</span> Stale lock file blocking manual runs</div>
<div class="callout red" style="margin-top:8px;">
<div class="clue-label red">Error</div>
<p>ERROR: Lock file exists at /tmp/nas08_to_nas16.lock. Another sync may still be running. Exiting.</p>
</div>
<p><strong>Root cause:</strong> Script was killed mid-run during testing, leaving the lock file behind. Original lock logic just checked for file existence with no way to distinguish a live run from a stale one.</p>
<p><strong>Fix:</strong> Lock file now stores the script's PID. On startup, if a lock file exists the script checks whether that PID is still running. If not, it removes the stale lock and continues with a warning in the log.</p>
<p class="result pass">Resolved — stale locks are now self-clearing.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">T4</span> Folder Activity section showing 0 updated despite files transferring</div>
<p style="margin-top:8px;"><strong>Root cause:</strong> Original folder parser relied on <code>xfr#</code> markers from rsync's <code>--progress</code> flag. When <code>--progress</code> was removed (to clean up captured output), those markers disappeared and the parser never incremented folder counts. Switching to <code>--verbose</code> didn't help because verbose output only shows directory names, not individual files.</p>
<p><strong>Fix:</strong> Replaced <code>--verbose</code> with <code>--itemize-changes</code>, which outputs a structured prefix line for every transferred file regardless of size (e.g. <code>&gt;f+++++++++ 02 - Photos/2020/12/photo.jpg</code>). Parser updated to detect lines starting with <code>&gt;f</code> and extract the top-level folder name.</p>
<p class="result pass">Resolved — folder activity now correctly shows file counts per folder.</p>
</div>
</div>
<!-- SECTION 7 — NFS EXPORT REFERENCE -->
<div class="section">
<div class="section-title" data-num="7">NAS08 NFS export reference</div>
<p>All four shares updated to <code>no_subtree_check</code> on May 18, 2026. The <code>/export</code> root entries are OMV auto-generated read-only entries — leave them as-is.</p>
<table>
<thead>
<tr><th>Share</th><th>Networks</th><th>Key Options</th></tr>
</thead>
<tbody>
<tr>
<td><code>/export/kingdezigns-all</code></td>
<td>.100 .110 .120 .150</td>
<td><code>rw, no_subtree_check, insecure, crossmnt</code></td>
</tr>
<tr>
<td><code>/export/kingdezigns08-secure</code></td>
<td>.100 .110 .120 .150</td>
<td><code>rw, no_subtree_check, insecure, crossmnt</code></td>
</tr>
<tr>
<td><code>/export/kingdezigns-public</code></td>
<td>.100 .110 .120 .150</td>
<td><code>rw, no_subtree_check, insecure, crossmnt</code></td>
</tr>
<tr>
<td><code>/export/HomeAssistantBackups</code></td>
<td>.150 only</td>
<td><code>rw, no_subtree_check, insecure, crossmnt</code></td>
</tr>
<tr>
<td><code>/export</code> (root)</td>
<td>.100 .110 .120 .150</td>
<td><code>ro, root_squash, subtree_check</code> — OMV auto-generated, do not edit</td>
</tr>
</tbody>
</table>
<p style="margin-top:0.75rem;font-size:12px;color:var(--text-muted);">Note: duplicate 192.168.100.0/24 entry for /export root exists in OMV config — pre-existing, harmless, clean up in OMV UI when convenient.</p>
</div>
<!-- SECTION 8 — NIGHTLY TASK TIMELINE -->
<div class="section">
<div class="section-title" data-num="8">NAS08 nightly task timeline</div>
<table>
<thead>
<tr><th>Time</th><th>Device</th><th>Script</th><th>Notes</th></tr>
</thead>
<tbody>
<tr>
<td>12:00 AM</td>
<td>NAS08</td>
<td><code>/usr/scripts/zfs/nas08_zfs_report.sh</code></td>
<td>Daily ZFS health report email.</td>
</tr>
<tr>
<td>2:00 AM</td>
<td>NAS08 &amp; NAS16</td>
<td><code>/usr/scripts/omv/nas16-backup.sh</code></td>
<td>Pre-existing backup script. NAS16 finishes ~1 min, NAS08 ~5 min. Runs every 3 days.</td>
</tr>
<tr>
<td>2:30 AM</td>
<td>NAS16</td>
<td><code>/usr/scripts/nas/nas08_to_nas16_sync.sh</code></td>
<td>NAS08 → NAS16 Public folder sync. 25-min buffer after NAS08 backup finishes.</td>
</tr>
<tr>
<td>3:00 AM (Sun)</td>
<td>NAS08</td>
<td><code>/usr/scripts/zfs/nas08_zfs_scrub.sh</code></td>
<td>Weekly ZFS scrub. Sundays only.</td>
</tr>
<tr>
<td>TBD</td>
<td>TBD</td>
<td>Future maintenance tasks</td>
<td>Drive health checks, log cleanups, etc. — to be added later.</td>
</tr>
</tbody>
</table>
</div>
<!-- SECTION 9 — LESSONS LEARNED -->
<div class="section">
<div class="section-title" data-num="9">Lessons learned</div>
<table>
<thead>
<tr><th>Lesson</th><th>Detail</th></tr>
</thead>
<tbody>
<tr>
<td>subtree_check causes intermittent NFS permission failures</td>
<td>On folders with ACL-based or mixed ownership, subtree_check can fail the export tree validation intermittently — especially after idle periods overnight. no_subtree_check is the safe modern default for private home networks.</td>
</tr>
<tr>
<td>NFS client cache must be cleared after export changes</td>
<td>Running exportfs -ra on the server isn't enough. The NFS client (NAS16) must unmount and remount to pick up the new export options. Without this, the old subtree_check behavior persists.</td>
</tr>
<tr>
<td>ACL permissions and NFS UIDs are separate concerns</td>
<td>Files can have correct ACLs (rufusking:rwx) but still be blocked over NFS if the UID mapping fails. Always verify UIDs match on both machines with id username before assuming ACL issues.</td>
</tr>
<tr>
<td>sudo operations reset directory ownership</td>
<td>Any sudo mkdir or sudo mount can leave directories owned by root. Scripts that write to those directories will fail with Permission Denied when run as a regular user. Always chown after sudo directory operations.</td>
</tr>
<tr>
<td>Lock files should store PIDs, not just exist</td>
<td>A bare touch lock file can't distinguish a live run from a stale one left by a killed process. Storing the PID and checking if it's still running makes lock files self-healing.</td>
</tr>
<tr>
<td>--itemize-changes is the right flag for parsing file transfers</td>
<td>--progress generates xfr# markers but is noisy. --verbose only lists directories. --itemize-changes gives one clean structured line per transferred file (&gt;f prefix) that's easy to parse reliably regardless of file size.</td>
</tr>
<tr>
<td>Pull is safer than push for backups</td>
<td>Running rsync on the destination keeps the source device (NAS08) passive and low-load during the sync window.</td>
</tr>
<tr>
<td>Schedule buffer matters</td>
<td>Running the sync immediately after another backup script risks overlap on heavy nights. A 25-30 min buffer between jobs keeps things clean.</td>
</tr>
<tr>
<td>File count is larger than expected when blocked folders open up</td>
<td>Initial estimate was ~16,000 files. Actual count after Photos/Taxes/Documents became accessible was ~225,000 files across ~983 GB. rsync handled this without issue.</td>
</tr>
</tbody>
</table>
</div>
<!-- SECTION 10 — NETWORK MAP -->
<div class="section">
<div class="section-title" data-num="10">Network map — items to update</div>
<table>
<thead>
<tr><th>Item</th><th>Detail</th></tr>
</thead>
<tbody>
<tr>
<td>New script on NAS16</td>
<td><code>/usr/scripts/nas/nas08_to_nas16_sync.sh</code> — document in NAS16 script inventory</td>
</tr>
<tr>
<td>New log location on NAS16</td>
<td><code>/var/log/nas-sync/</code> — add to log monitoring notes. 30-day auto-rotation.</td>
</tr>
<tr>
<td>OMV Scheduler — NAS16</td>
<td>Task added: <code>30 2 */2 * *</code> running the sync script</td>
</tr>
<tr>
<td>NFS exports changed on NAS08</td>
<td>All four shares updated to <code>no_subtree_check</code> in OMV. Document in NAS08 config notes.</td>
</tr>
<tr>
<td>NAS08 → NAS16 data flow</td>
<td>NAS08 Public folder now syncing to NAS16 Public every other day at 2:30 AM. 225,000 files / 983 GB in scope.</td>
</tr>
<tr>
<td>OMV duplicate export entry (cleanup pending)</td>
<td>192.168.100.0/24 appears twice for the /export root in NAS08's exports. Harmless but should be cleaned up in OMV UI when convenient.</td>
</tr>
</tbody>
</table>
</div>
<div class="footer">
<span>KingDezigns Home Network</span>
<span>v1.0 — May 13, 2026 &nbsp;|&nbsp; v2.0 — May 18, 2026</span>
</div>
</div>
</body>
</html>