Files
oikos/archive/knowledge/containers/102-nfs-export.md
dtoro 6b75f7302d db as source of truth: wiki→seeds, archive old artifacts, knowledge ingestion
- Migrations 010 (content_hash) + 011 (search tsvector column)
- new: internal/knowledge/seed.go — knowledge seed ingest engine
- new: internal/httpapi/knowledge.go — SearchKnowledge + GetEntityKnowledge
- wire knowledge ingest into oikos seed pipeline
- convert all 36 wiki docs + 6 investigations + 12 runbooks → seeds/knowledge.yaml
- archive: knowledge/wiki/→archive/, oikos/cards/→archive/, .hermes/plans/→archive/
- delete: 9 superseded Python kernel files, ledger/, mcp/build_host_files.py
- remove empty knowledge/ directory tree
2026-07-07 20:22:30 +02:00

6.5 KiB
Raw Blame History

102 — nfs-export

Dedicated, single-purpose LXC that re-exports /mnt/library over NFSv4 to clients that can't use the host's PVE virtiofs path — currently only 100-zimaos, which ships a kernel without virtiofs support.

At a glance

  • Hostname: nfs-export
  • IP: 192.168.8.200 (static; LAN-only, no Caddy in front because NFS is L4)
  • LAN DNS: nfs-export.hubris.network192.168.8.200 (direct, no Caddy)
  • Privilege: privileged (unprivileged: 0) + lxc.apparmor.profile: unconfined — required for nfs-kernel-server
  • Resources: 1 core / 512 MiB RAM / 2 GiB rootfs / 256 MiB swap
  • Mounts: host /mnt/library ↔ container /mnt/library (same path on both sides — matches the bind-mount convention used by jellyfin, paperless, arriman, nextcloud, mule-images, apps)

What it does

/mnt/library (host ext4 on nvme1n1)
        │
        ├── bind-mounted into 7 other LXCs (jellyfin, paperless, …)
        └── bind-mounted into LXC 102
                    │
                    └── nfs-kernel-server exports /mnt/library
                          │
                          └── consumed by VM 100 (ZimaOS)

Same inodes, same page cache. The NFS server is just one more access path on top of a tree that 8 other consumers already share — see media permissions.

Export config

/etc/exports:

/mnt/library  192.168.8.0/24(rw,all_squash,anonuid=33,anongid=10000,no_subtree_check,sec=sys)

Initially started as ro; promoted to rw on 2026-05-14 after the Files-UI evaluation confirmed (a) the library renders correctly as a folder under /DATA, (b) thumbnails are generated, (c) the squash works — a write from ZimaOS appears on /mnt/library as www-data:media (uid 33, gid 10000), matching the existing tree convention used by Nextcloud and mule-images.

Guardrails (in order of importance)

  1. all_squash,anonuid=33,anongid=10000. Every write from ZimaOS records on disk as www-data:media (uid 33, gid 10000), the same identity Nextcloud and mule-images use. Keeps the existing tree convention from drifting. See project_media_perms.
  2. Subnet restriction 192.168.8.0/24. No public/mesh access; LAN only.
  3. no_subtree_check + sec=sys — standard performance/auth pair for a homelab.
  4. No crossmnt because /mnt/library is a single ext4 filesystem on the host (no nested mounts to traverse).

What we're not doing yet

  • No per-subdir export. ZimaOS sees the whole tree; access is controlled by filesystem permissions (drwxr-x--- private dirs like documents/, notes/, heaper/ aren't readable by media group, so ZimaOS-as-squashed-uid won't see them either).
  • No write-back. Until we promote to rw, ZimaOS can't write — eliminates the lock-domain split concern between NFS clients (NLM/v4) and local LXCs (POSIX flock).
  • No Authentik / forward-auth. NFS doesn't sit behind HTTP, so the standard caddy+authentik path doesn't apply. Subnet ACL is the only auth.

Why this LXC exists (vs serving from host)

We considered three options before building this:

Option Outcome
NFS on hubris bare-metal host Best performance, but adds long-lived NFS/RPC daemons to a host with a recent crash episode (hubris crash 2026-04-21/22). Rejected.
SMB on host Same host-blast-radius problem, plus 3050% lower throughput than NFS on Linux↔Linux. Rejected.
NFS in a dedicated LXC ← this Within ~2% of host performance (LXC is namespace isolation; IO path is unchanged), zero new daemons on hubris, matches the existing fleet pattern. Selected.

Rationale lives in the install plan /root/.claude/plans/i-wannt-you-to-nifty-muffin.md on hubris.

Operations

  • Reload exports after editing /etc/exports: pct exec 102 -- exportfs -ra
  • List active exports: pct exec 102 -- exportfs -v
  • Watch from outside: showmount -e 192.168.8.200
  • Service health: pct exec 102 -- systemctl is-active nfs-server rpcbind
  • Restart cleanly: pct restart 102 (ZimaOS will retry the mount via nofail)
  • Destroy + rebuild: pct stop 102 && pct destroy 102 --purge — reversible in seconds; only ZimaOS notices

Open items

  • Consider tightening the export to subdirs (e.g. movies, tv, music, audiobooks, books, images, podcasts, roms) if you don't want ZimaOS reachable into documents/, notes/, heaper/, etc. — though those private subdirs are already invisible to media-group perms.
  • ZimaOS architecture finding: the Drives panel only enumerates physical/block devices via GET /v2/local_storage/storages (read-only API, no POST). Network shares cannot appear as Drives — they show up as folders in Files. This is intentional in CasaOS's design; don't try to work around it. Library-as-folder is the supported model.
  • Consider adding Samba to this LXC if a future Mac/iOS client needs SMB on the same tree — same LXC, no host changes.
  • No PBS backup (no PBS configured on hubris); the container is fully described in this page + pct config 102, rebuild from scratch in <2 min if lost.

Changelog

2026-05-14 — Promoted to rw; squash behaviour verified

After ZimaOS Files UI evaluation passed (library renders as folder under /DATA, thumbnails work, ZimaOS Drives panel ignores NFS by design), flipped export to rw. Tested: writing /DATA/library/.zimaos-rw-test from ZimaOS appears on hubris's /mnt/library owned www-data:media (uid 33, gid 10000), confirming all_squash,anonuid=33,anongid=10000 works as designed. Also discovered the dead end: ZimaOS's GET /v2/local_storage/storages is the source of the Drives panel; it returns only physical storage and rejects POST/PUT — network shares cannot be promoted to Drives.

2026-05-14 — LXC built; NFS export live (read-only)

Privileged Debian 13 container created with bind-mount /mnt/library. nfs-kernel-server installed and enabled; export /mnt/library to 192.168.8.0/24 with ro,all_squash,anonuid=33,anongid=10000. Smoke-tested from hubris host (mounted, listed library tree, confirmed RO). nfs-export.hubris.network added to LXC 124 dnsmasq.