Files
docker-infrastructure/system-config/nfs-self-heal
poprhythm 50a5a48ed4 Fix false-positive stale-mount detection in nfs-mount-heal.sh
find -maxdepth 3 couldn't reach immich's thumbs/<uuid>/XX/YY/file (4
levels deep), so it exhausted the 256x256 hash-bucket fan-out with no
match and timed out on every run -- 3 spurious remounts/restarts of
immich_server within 15 minutes of deploy, all falsely alerted as
staleness. Drop -maxdepth entirely; -quit already stops at the first
match via depth-first search, so it's fast regardless of tree depth.
2026-08-25 22:06:43 +00:00
..

NFS Self-Heal (host-level systemd units)

These files are not deployed by Docker/Portainer — they're systemd units and a script that live directly on the host at /etc/systemd/system/ and /usr/local/bin/. They're checked in here purely as a backup so they can be restored if the host is rebuilt. Editing a file here does not change running behavior; you have to re-copy it to the host and reload systemd.

What this does

Permanent NFS mounts (mnt-nas_family.mount, mnt-nas_books.mount, mnt-nas_owncloud.mount) can go stale — the host mount looks fine on a top-level ls, but file handles nested inside it return ESTALE (errno -116) to processes that opened them earlier, including containers that bind-mount the path. A container restart is required to pick up a fresh handle even after the host-side mount is healthy again. See ../../NAS-CONNECTION-STRATEGIES.md for the full mount inventory and ../../immich/ / ../../calibre/MOUNT-HISTORY.md for history on this failure mode (first hit immich on 2026-08-25; calibre-import had the same issue documented earlier but unresolved).

Two pieces:

  1. <container>-mount-ready.service (one per affected container) — BindsTo=mnt-nas_*.mount, so restarting the mount unit automatically restarts the bound container. Currently covers immich_server, calibre, ocis. (Older instances of this same pattern — backrest, kiwix, pmtiles, audiobookshelf, romm — already exist on the host but aren't backed up here yet.)
  2. nfs-mount-heal.timer → nfs-mount-heal.service → nfs-mount-heal.sh — runs every 5 minutes, does a real nested read (not just ls the mount root) against nas_family, nas_books, and nas_owncloud. On failure it force-remounts the mount unit (systemctl restart), which cascades into the container restart via the hooks above, then re-checks and sends a Telegram alert either way.

Reinstall after a host rebuild

sudo cp *.service *.timer /etc/systemd/system/
sudo cp nfs-mount-heal.sh /usr/local/bin/nfs-mount-heal.sh
sudo chmod 755 /usr/local/bin/nfs-mount-heal.sh

sudo systemctl daemon-reload
sudo systemctl enable --now immich-mount-ready.service
sudo systemctl enable --now calibre-mount-ready.service
sudo systemctl enable --now ocis-mount-ready.service
sudo systemctl enable --now nfs-mount-heal.timer

Requires the mnt-nas_family.mount, mnt-nas_books.mount, and mnt-nas_owncloud.mount systemd units to already exist (see NAS-CONNECTION-STRATEGIES.md) and .credentials at the repo root to be present on the host (the heal script sources it for the Telegram bot token/chat ID).