system-config: back up nas_audiobooks mount fix and missing unit files
Adds the 4 permanent .mount units (family/books/owncloud/audiobooks) and audiobookshelf-mount-ready.service to the repo backup, which weren't tracked here yet, and updates the README to document the autofs->permanent mount fix applied to nas_audiobooks today so a host rebuild doesn't recreate the broken automount version.
This commit is contained in:
@@ -9,47 +9,64 @@ running behavior; you have to re-copy it to the host and reload systemd.
|
|||||||
## What this does
|
## What this does
|
||||||
|
|
||||||
Permanent NFS mounts (`mnt-nas_family.mount`, `mnt-nas_books.mount`,
|
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
|
`mnt-nas_owncloud.mount`, `mnt-nas_audiobooks.mount`) can go stale — the host
|
||||||
top-level `ls`, but file handles nested inside it return ESTALE
|
mount looks fine on a top-level `ls`, but file handles nested inside it
|
||||||
(errno -116) to processes that opened them earlier, including containers
|
return ESTALE (errno -116) to processes that opened them earlier, including
|
||||||
that bind-mount the path. A container restart is required to pick up a
|
containers that bind-mount the path. A container restart is required to pick
|
||||||
fresh handle even after the host-side mount is healthy again. See
|
up a fresh handle even after the host-side mount is healthy again. See
|
||||||
`../../NAS-CONNECTION-STRATEGIES.md` for the full mount inventory and
|
`../../NAS-CONNECTION-STRATEGIES.md` for the full mount inventory and
|
||||||
`../../immich/` / `../../calibre/MOUNT-HISTORY.md` for history on this
|
`../../immich/` / `../../calibre/MOUNT-HISTORY.md` for history on this
|
||||||
failure mode (first hit immich on 2026-08-25; calibre-import had the same
|
failure mode (first hit immich on 2026-08-25; calibre-import had the same
|
||||||
issue documented earlier but unresolved).
|
issue documented earlier but unresolved).
|
||||||
|
|
||||||
|
**All four `.mount` units must be *permanent* (enabled directly, no
|
||||||
|
`.automount` wrapper), not just present.** `mnt-nas_audiobooks.mount` was
|
||||||
|
mistakenly left on an `.automount` unit until 2026-09-17 and flapped ESTALE
|
||||||
|
for days as a result — autofs can cycle the underlying mount for reasons
|
||||||
|
other than idle timeout even with `TimeoutIdleSec=0`, which invalidates any
|
||||||
|
container's bind-mounted reference exactly like a stale handle. The self-heal
|
||||||
|
below papered over it (auto-remounting every ~5 min) but never fixed it;
|
||||||
|
switching to a permanent mount did. See NAS-CONNECTION-STRATEGIES.md's
|
||||||
|
"Docker bind mounts + automount = stale handles" entry.
|
||||||
|
|
||||||
Two pieces:
|
Two pieces:
|
||||||
|
|
||||||
1. **`<container>-mount-ready.service`** (one per affected container) —
|
1. **`<container>-mount-ready.service`** (one per affected container) —
|
||||||
`BindsTo=mnt-nas_*.mount`, so restarting the mount unit automatically
|
`BindsTo=mnt-nas_*.mount`, so restarting the mount unit automatically
|
||||||
restarts the bound container. Currently covers `immich_server`,
|
restarts the bound container. Currently covers `immich_server`,
|
||||||
`calibre`, `ocis`. (Older instances of this same pattern —
|
`calibre`, `ocis`, `audiobookshelf`. (Older instances of this same
|
||||||
`backrest`, `kiwix`, `pmtiles`, `audiobookshelf`, `romm` — already
|
pattern — `backrest`, `kiwix`, `pmtiles`, `romm` — already exist on
|
||||||
exist on the host but aren't backed up here yet.)
|
the host but aren't backed up here yet.)
|
||||||
2. **`nfs-mount-heal.timer`** → **`nfs-mount-heal.service`** →
|
2. **`nfs-mount-heal.timer`** → **`nfs-mount-heal.service`** →
|
||||||
**`nfs-mount-heal.sh`** — runs every 5 minutes, does a real nested
|
**`nfs-mount-heal.sh`** — runs every 5 minutes, does a real nested
|
||||||
read (not just `ls` the mount root) against `nas_family`, `nas_books`,
|
read (not just `ls` the mount root) against `nas_family`, `nas_books`,
|
||||||
and `nas_owncloud`. On failure it force-remounts the mount unit
|
`nas_owncloud`, and `nas_audiobooks`. On failure it force-remounts the
|
||||||
(`systemctl restart`), which cascades into the container restart via
|
mount unit (`systemctl restart`), which cascades into the container
|
||||||
the hooks above, then re-checks and sends a Telegram alert either way.
|
restart via the hooks above, then re-checks and sends a Telegram alert
|
||||||
|
either way. This is a safety net for genuine transient staleness, not a
|
||||||
|
fix for a mount that's structurally wrong (e.g. sitting on autofs).
|
||||||
|
|
||||||
## Reinstall after a host rebuild
|
## Reinstall after a host rebuild
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo cp *.service *.timer /etc/systemd/system/
|
sudo cp *.mount *.service *.timer /etc/systemd/system/
|
||||||
sudo cp nfs-mount-heal.sh /usr/local/bin/nfs-mount-heal.sh
|
sudo cp nfs-mount-heal.sh /usr/local/bin/nfs-mount-heal.sh
|
||||||
sudo chmod 755 /usr/local/bin/nfs-mount-heal.sh
|
sudo chmod 755 /usr/local/bin/nfs-mount-heal.sh
|
||||||
|
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now mnt-nas_family.mount
|
||||||
|
sudo systemctl enable --now mnt-nas_books.mount
|
||||||
|
sudo systemctl enable --now mnt-nas_owncloud.mount
|
||||||
|
sudo systemctl enable --now mnt-nas_audiobooks.mount
|
||||||
sudo systemctl enable --now immich-mount-ready.service
|
sudo systemctl enable --now immich-mount-ready.service
|
||||||
sudo systemctl enable --now calibre-mount-ready.service
|
sudo systemctl enable --now calibre-mount-ready.service
|
||||||
sudo systemctl enable --now ocis-mount-ready.service
|
sudo systemctl enable --now ocis-mount-ready.service
|
||||||
|
sudo systemctl enable --now audiobookshelf-mount-ready.service
|
||||||
sudo systemctl enable --now nfs-mount-heal.timer
|
sudo systemctl enable --now nfs-mount-heal.timer
|
||||||
```
|
```
|
||||||
|
|
||||||
Requires the `mnt-nas_family.mount`, `mnt-nas_books.mount`, and
|
**Do not** create `.automount` units for any of these — they must be
|
||||||
`mnt-nas_owncloud.mount` systemd units to already exist (see
|
enabled directly as permanent mounts (see the autofs warning above).
|
||||||
`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
|
Requires `.credentials` at the repo root to be present on the host (the
|
||||||
token/chat ID).
|
heal script sources it for the Telegram bot token/chat ID).
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Restart audiobookshelf after mnt-nas_audiobooks is ready
|
||||||
|
After=mnt-nas_audiobooks.mount
|
||||||
|
Requires=mnt-nas_audiobooks.mount
|
||||||
|
BindsTo=mnt-nas_audiobooks.mount
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/bin/docker restart audiobookshelf
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=mnt-nas_audiobooks.mount
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Mount unRAID audiobooks NFS share
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Mount]
|
||||||
|
What=192.168.1.192:/mnt/user/media/audiobooks
|
||||||
|
Where=/mnt/nas_audiobooks
|
||||||
|
Type=nfs
|
||||||
|
Options=nfsvers=3,hard,rw,noatime
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Mount unRAID books NFS share
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Mount]
|
||||||
|
What=192.168.1.192:/mnt/user/media/books
|
||||||
|
Where=/mnt/nas_books
|
||||||
|
Type=nfs
|
||||||
|
Options=nfsvers=3,hard,rw,noatime
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Mount unRAID family NFS share
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Mount]
|
||||||
|
What=192.168.1.192:/mnt/user/family
|
||||||
|
Where=/mnt/nas_family
|
||||||
|
Type=nfs
|
||||||
|
Options=nfsvers=3,hard,rw,noatime
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Mount unRAID owncloud NFS share
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Mount]
|
||||||
|
What=192.168.1.192:/mnt/user/owncloud
|
||||||
|
Where=/mnt/nas_owncloud
|
||||||
|
Type=nfs
|
||||||
|
Options=nfsvers=3,hard,nolock,rw,noatime
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Deep health check + self-heal for permanent NFS mounts backing
|
# Deep health check + self-heal for permanent NFS mounts backing
|
||||||
# immich, calibre, and ocis.
|
# immich, calibre, ocis, and audiobookshelf.
|
||||||
#
|
#
|
||||||
# A plain `ls` on a mount root can succeed even when nested file
|
# A plain `ls` on a mount root can succeed even when nested file
|
||||||
# handles inside it are stale (ESTALE / errno -116) -- that's the
|
# handles inside it are stale (ESTALE / errno -116) -- that's the
|
||||||
@@ -20,6 +20,7 @@ CHECKS=(
|
|||||||
"/mnt/nas_family:mnt-nas_family.mount:/mnt/nas_family/immich-library/thumbs:immich_server"
|
"/mnt/nas_family:mnt-nas_family.mount:/mnt/nas_family/immich-library/thumbs:immich_server"
|
||||||
"/mnt/nas_books:mnt-nas_books.mount:/mnt/nas_books/calibre-import:calibre"
|
"/mnt/nas_books:mnt-nas_books.mount:/mnt/nas_books/calibre-import:calibre"
|
||||||
"/mnt/nas_owncloud:mnt-nas_owncloud.mount:/mnt/nas_owncloud:ocis"
|
"/mnt/nas_owncloud:mnt-nas_owncloud.mount:/mnt/nas_owncloud:ocis"
|
||||||
|
"/mnt/nas_audiobooks:mnt-nas_audiobooks.mount:/mnt/nas_audiobooks:audiobookshelf"
|
||||||
)
|
)
|
||||||
|
|
||||||
alert() {
|
alert() {
|
||||||
|
|||||||
Reference in New Issue
Block a user