NAS reboot & NFS (nfsd) hang recovery¶
TerraMaster F4-423 (192.168.0.237), NFS server for VM 208's media stack.
Symptom: alert flood, media containers down, NAS high load¶
A flood of media_container_missing on 208 while 208 itself is healthy = the NAS's
nfsd is hung in D-state (uninterruptible sleep). NFS stops accepting connections →
NFS-dependent containers on 208 crash in cascade. No data risk (the RAID is fine).
Diagnose (on the NAS):
ps -eo stat,comm | grep nfsd | grep -c D # >0 = hung
ss -tln | grep 2049 # LISTEN with high Recv-Q = wedged
Healthy = nfsd_D=0, Recv-Q 0. Metrics signature: load1 pinned at ~10 (the D-state
threads inflate load) while disk I/O is flatlined = a kernel-level I/O stall, not overload.
Cure: reboot the NAS (only option)¶
A D-state hang can't be killed (not even kill -9). The only cure is a NAS reboot.
GOTCHA — SSH cannot reboot it. The "root" reachable over SSH on TerraMaster is
uid 9999 (a sandbox). reboot / systemctl reboot → polkit "Interactive
authentication required"; reboot -f → "Need to be root"; sysrq / nfsd thread bounce →
"Permission denied". The reboot must go through the TOS web UI (its backend runs as
real uid 0) — pick Restart, not Shutdown (a shutdown can leave it powered off).
Remote reboot without the panel: nas-reboot.sh¶
Lives in ~/scripts/nas-reboot/ on VM 208. TOS 6's login is a bunker (RSA with a
time-mangled public key + CSRF + X-Security-Code), so instead of re-implementing that
crypto the script drives a headless Chromium through the real login page, then reuses
the session cookie for PUT /v2/system/reboot.
cd ~/scripts/nas-reboot
./nas-reboot.sh # DRY RUN — verify login + authenticated call, NO reboot
./nas-reboot.sh --reboot # actually reboot the NAS
Credentials in nas-reboot.env (chmod 600). Node + puppeteer (Chromium) vendored in the
same dir. Robust to TOS crypto changes because it runs the panel's own JS.
After the NAS comes back¶
nfs-health-monitor.{sh,service,timer} on 208 auto-recovers the stack. Two gotchas:
- It gives up at attempt 30 (~12–13 min). If the NAS is slower than that, restart the
crashed containers by hand:
docker start $(docker ps -aq -f status=exited). - Stale bind mounts (fixed 2026-07-16). When the NFS remounts, containers that stayed
"Up" keep their bind pointing at the pre-remount (empty) dir → Sonarr reports "Importing
after download will exceed available disk space" even though the NAS has TB free
(
docker exec sonarr ls /datais empty while host/mnt/nfs_mediais full). The monitor now runsrebind_nfs_containers()on recovery —docker restarton every container binding/mnt/nfs_media(discovered dynamically). Manual trigger:~/scripts/nfs-health-monitor.sh rebind.
Verify recovery: alertmanager container up + Prometheus firing=0.
Long-term hardening (not yet done)¶
- Phase 2: wire
nfs-health-monitorto auto-triggernas-reboot.sh --rebootafter N min of confirmed D-state hang (rate-limited, Telegram notify) — start in "detect + alert" mode before promoting to auto. - Smart plug as a last-resort power-cycle for when even a graceful reboot wedges (BTRFS is CoW and survives a hard cut).