# NFS exports from nixdesk (14900k) to r5500 (192.168.2.100), formerly nix-server (192.168.2.238): # - /mnt/deep/jellyfin → nix-server /mnt/nixdesk-jellyfin (Jellyfin bulk libraries) # # Jellyfin root on nixdesk uses owner olivier + group nfsmedia (990); dirs here are 2775 so # local writes and NFS all_squash (anonuid=olivier, anongid=990) get rwx via owner or group. # # Legacy trees may still need a one-time `chgrp -R nfsmedia` / `chmod -R g+rwX` on deep folders. { config, pkgs, ... }: let olivierUid = config.users.users.olivier.uid or 1000; in { # Avoid UID/GID mismatches across machines: map all NFS writes from nix-server to a single # local system user/group on this server. users.groups.nfsmedia = { gid = 990; }; users.users.nfsmedia = { isSystemUser = true; uid = 990; group = "nfsmedia"; }; # olivier: owner for local use; nfsmedia: group used by NFS all_squash (990). systemd.tmpfiles.settings."14900k-nfs-export-paths" = { "/mnt/deep/jellyfin"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; }; }; # After exports are up, ensure group nfsmedia can write throughout library roots (idempotent; # scoped to library folders only — not whole disks). Runs on each `nixos-rebuild switch`. system.activationScripts.nfs-export-group-write = { deps = [ "specialfs" ]; text = '' for d in /mnt/deep/jellyfin do [ -d "$d" ] || continue ${pkgs.acl}/bin/setfacl -R -m g:nfsmedia:rwx "$d" 2>/dev/null || true ${pkgs.acl}/bin/setfacl -R -d -m g:nfsmedia:rwx "$d" 2>/dev/null || true done ''; }; # Fixed ports so the firewall can allow NFS v3 helpers (see networking.firewall below). services.nfs.server = { enable = true; mountdPort = 4000; lockdPort = 4001; statdPort = 4002; # fsid= unique per export tree (avoids client ESTALE when multiple paths are exported). # Squash nix-server clients to olivier:nfsmedia so Jellyfin can write .nfo/posters into # existing olivier-owned library folders (990-only squash was "other" r-x on typical 755 trees). exports = '' /mnt/deep/jellyfin 192.168.2.100(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=1) /mnt/deep/jellyfin 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=2) ''; }; networking.firewall.allowedTCPPorts = [ 111 # portmapper 2049 4000 4001 4002 ]; networking.firewall.allowedUDPPorts = [ 111 2049 4000 4001 4002 ]; }