Files
docker-infrastructure/NAS-CONNECTION-STRATEGIES.md

7.0 KiB
Raw Permalink Blame History

NAS Connection Strategies

Summary of how each service connects to the unRAID NAS (192.168.1.192 / 192.168.1.4).


Strategy Overview

Strategy Services Reliability Notes
Docker NFS named volume Plex, qBittorrent, Audiobookshelf ⚠️ Fragile Soft mount; stale handles on drive spin-down
systemd permanent mount + bind Calibre (import), oCIS, Immich Solid Hard NFS; permanent; no idle cycling
systemd automount + bind Backrest, Filebrowser-Colleen-HD Solid CIFS; TimeoutIdleSec=0; never unmounts once triggered
Local SSD + lsyncd sync Calibre (library) Best SQLite never touches NFS; NAS copy is read-only replica

Per-Service Details

Plex

  • Strategy: Docker NFS named volume (nas_media, external)
  • NAS path: 192.168.1.192:/mnt/user/media
  • Mount options: nfsvers=4,soft,nolock,timeo=14,rsize=8192,wsize=8192
  • Container path: /data
  • Risk: soft + timeo=14 means EIO after 14 retries × 0.1s = ~1.4s timeout. If unRAID drives spin down, Plex gets I/O errors. Works in practice because Plex opens/closes file handles per-request rather than holding them open.

qBittorrent (all 3 instances: open, vpn, vpn2)

  • Strategy: Docker NFS named volume (nas_media, same as Plex)
  • NAS path: 192.168.1.192:/mnt/user/media
  • Container path: /data
  • Risk: Same as Plex. Active downloads write continuously — more exposure to spin-down EIO than Plex.

Calibre

  • Strategy (library): Local SSD + lsyncd one-way sync to NAS
    • Local: /srv/calibre/library → container /config/Calibre Library
    • lsyncd syncs to /mnt/nas_books/calibre/Calibre Library within ~15 seconds
    • SQLite (metadata.db, notes.db) never touches NFS — eliminates apsw.IOError
  • Strategy (import): systemd permanent NFS mount + Docker bind mount
    • Host: /mnt/nas_books/calibre-import (permanent NFS, no automount)
    • Container: /calibre-import
    • NAS path: 192.168.1.192:/mnt/user/media/books
  • Mount options: nfsvers=3,hard,rw,noatime
  • Why permanent (not automount): Docker bind mounts snapshot the mount reference at container start. If autofs cycles between restarts, the container gets a stale handle. Permanent mount avoids this entirely.
  • Manual book add (when auto-add fails):
    docker stop calibre
    docker run --rm \
      -v /srv/calibre/library:/config/Calibre\ Library \
      -v /mnt/nas_books/calibre-import:/calibre-import \
      lscr.io/linuxserver/calibre:latest \
      sh -c "cd /opt/calibre && LD_LIBRARY_PATH=/opt/calibre ./calibredb add \
        --library-path '/config/Calibre Library' '/calibre-import/<book>' 2>&1"
    docker start calibre
    

Filebrowser-Colleen-HD

  • Strategy: systemd CIFS automount + Docker bind mount
  • Host mount: /mnt/nas_backup (CIFS //192.168.1.192/backup)
  • Container path: /folder
  • Mount options: vers=3.0,uid=0,gid=0,noperm,noserverino,soft,TimeoutIdleSec=0
  • Why CIFS: Container runs as root; CIFS with uid=0,gid=0 maps all files to root
  • TimeoutIdleSec=0: Never auto-unmounts once triggered; safe for persistent container access

Backrest (backup service)

  • Strategy: systemd CIFS automount + Docker bind mount (same mount as Filebrowser)
  • Host mount: /mnt/nas_backup/nas-docker-data
  • Container path: /backup-export
  • Same CIFS mount as Filebrowser-Colleen-HD (mnt-nas_backup)

oCIS (ownCloud Infinite Scale)

  • Strategy: systemd permanent NFS mount + Docker bind mount
  • Host mount: /mnt/nas_owncloud (permanent NFS, no automount)
  • Container path: /var/lib/ocis/storage/users
  • NAS path: 192.168.1.192:/mnt/user/owncloud
  • Mount options: nfsvers=3,hard,rw,noatime
  • Local config/index: /srv/ocis/data and /srv/ocis/config stay on local SSD

Immich

  • Strategy: systemd permanent NFS mount + Docker bind mount
  • Host mount: /mnt/nas_family (NFS 192.168.1.192:/mnt/user/family)
  • Container path: /usr/src/app/upload/mnt/nas_family/immich-library
  • Mount options: nfsvers=3,hard,rw,noatime
  • Why permanent (not automount): Drive doesn't spin down; permanent mount avoids any autofs cycling risk
  • Database: PostgreSQL on local SSD (/var/lib/postgresql/data) — correct, not on NFS

Audiobookshelf

  • Strategy: Docker NFS named volume
  • NAS path: 192.168.1.192:/mnt/user/media/audiobooks
  • Container path: /audiobooks
  • Config/metadata: Local SSD (/srv/audiobookshelf/) — correct

systemd Mount Units

Unit Type Share Status
mnt-nas_books.mount NFS permanent :/mnt/user/media/books enabled, always up
mnt-nas_owncloud.mount NFS permanent :/mnt/user/owncloud enabled, always up
mnt-nas_family.mount NFS permanent :/mnt/user/family enabled, always up
mnt-nas_library.mount CIFS automount //192.168.1.192/library triggered on access, TimeoutIdleSec=0
mnt-nas_library.automount CIFS automount enabled
mnt-nas_backup.mount CIFS automount //192.168.1.192/backup triggered on access, TimeoutIdleSec=0
mnt-nas_backup.automount CIFS automount enabled

Known Issues & Gotchas

  • Docker NFS named volumes: The nas_media volume uses soft,nolock,timeo=14,nfsvers=4. This is fragile — short timeout means EIO on spin-up. Plex/qBittorrent survive because they open/close handles per request. If either starts having I/O errors, migrate to the systemd permanent mount pattern.
  • Docker bind mounts + automount = stale handles: Docker snapshots the mount reference at container start. If autofs cycles (unmount + remount) between container restarts, the container's bind mount goes stale while the host sees the path fine. Fix: use permanent .mount (no .automount) for any share that Docker containers bind-mount.
  • SQLite on NFS: Never store SQLite databases (calibre metadata.db/notes.db, any app DB) on NFS. Even with hard mounts and NLM locking, transient NFS errors cause SQLITE_IOERR. Keep SQLite on local SSD; sync non-SQLite files to NAS if sharing is needed.
  • CIFS vs NFS for file permissions: CIFS enforces server-side ACLs based on the SMB user. Files created via NFS by uid=99 with mode 600 are inaccessible via CIFS. Use NFS when container needs uid-mapped access to NFS-created files.
  • lsyncd for NAS sync: inotify-based, syncs within ~15 seconds of any write. Config at /etc/lsyncd/lsyncd.conf.lua. Log at /var/log/lsyncd.log.

Plex, qBittorrent, Immich, and Audiobookshelf all use the fragile Docker NFS named volume pattern. The safer pattern is systemd permanent mount + Docker bind mount (as used by calibre-import and oCIS). This would involve:

  1. Create /mnt/nas_media systemd permanent mount unit
  2. Update compose files to use bind mounts instead of the external nas_media volume
  3. docker volume rm nas_media after redeployment