nuc: media over NFS from nas, on-demand role, i915 and input traps

nuc keeps only what needs its iGPU. blocky, privoxy and transmission-bt
moved to nas so the box can be powered off when not watching Jellyfin or
using the Spotify kiosk.

- /srv/media is now an NFSv4 mount from nas; jellyfin-server reads it
  with shift=false (idmapped mounts are unsupported on NFS, as the
  container doc already noted for CIFS) and readonly=true
- replication to nas is a systemd timer with Persistent=true, not cron —
  an on-demand host misses its 03:30 window and cron cannot catch up

Two failures documented in full, both diagnosed from the wrong layer
first:

- booting with the TV connected and powered on kills the i915 probe
  (drm_WARN_ON in intel_modeset_setup_hw_state), so /dev/dri never
  appears, snd_hda_intel deferred-probes forever holding the PCI device
  lock, and incusd blocks in sriov_numvfs_show — no container starts at
  all, including LAN DNS. Identical on 6.12.107 and 6.12.105.
- the kiosk input gid mismatch is real but was NOT the cause of the
  2026-08-30 outage (flat K400 batteries were); seatd opens input devices
  as root, so kiosk group membership is not on that path. Records the
  one-line raw capture that settles hardware-vs-software immediately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Julien Lutran
2026-08-30 23:53:30 +02:00
co-authored by Claude Opus 5
parent 66c7bca28f
commit 203728674f
4 changed files with 225 additions and 21 deletions
+32 -18
View File
@@ -1,31 +1,45 @@
# Homelab: nuc
Incus host on the LAN.
Incus host on the LAN**on-demand**: since 2026-08-30 it only needs to
run when watching Jellyfin or using the Spotify Connect kiosk. Everything
always-on (blocky/DNS, privoxy, transmission-bt) moved to
[`nas`](../nas/README.md), which is why nuc can now be powered off.
⚠️ Powering nuc off has backup consequences — its 03:30 replication to
nas only runs while it is up. See [nas-install.md](../nas/nas-install.md) §9.
- Debian 13, Intel Alder Lake-N (iGPU `i915`, shared by both Jellyfin containers) —
bare-metal reinstall: [nuc-install.md](nuc-install.md)
- Instances are bridged onto the LAN (192.168.0.0/24)
- USB 4 TB WD Red: ZFS pool `usb4t``usb4t/backup``/backup`
(incus exports, `nuc/` + `ks4/` subdatasets, 1 TB quota) and
`usb4t/media``/srv/media` (media library, shared into containers
via `shift=true` disk devices; works because ZFS ≥ 2.2 supports
idmapped mounts)
- ⚠️ The USB enclosure drops off the bus periodically and suspends the
pool, which silently breaks the nightly replication — symptoms,
recovery and fixes: [usb4t-dropouts.md](usb4t-dropouts.md)
- Backups: all local instances replicated to the USB pool
(`/root/scripts/incus-copy.sh -p backup -s nucbackup`; replicas
stopped, autostart off) — see
[nuc-install.md](nuc-install.md); ks4 replicas pulled into
pool `ks4backup` — see [ks4/incus-copy.md](../ks4/incus-copy.md)
- Storage: ZFS pool `data` on the SSD (all instance disks). The USB
4 TB and its pool **left nuc on 2026-08-30** — the enclosure's JMicron
bridge was suspending the pool ([usb4t-dropouts.md](usb4t-dropouts.md));
the disk now sits on direct SATA in [`nas`](../nas/nas-install.md) as
pool `tank`.
- Media library: `/srv/media` is now an **NFSv4 mount from nas**
(`192.168.0.4:/media`, read-only). `jellyfin-server` stays here for
the iGPU and reads it with `shift=false`
([jellyfin-server.md](jellyfin-server.md)).
- Backups: nuc and nas **cross-replicate** — nuc pushes all its
instances to `nas:nucbackup` at 03:30, nas pushes its own to
`nuc:nasbackup` at 04:00, so neither host's instances depend on that
host surviving ([nas/nas-install.md](../nas/nas-install.md) §9).
The ks4 pull leg moved to nas as well
([ks2/nas-seed.md](../ks2/nas-seed.md)), so nuc no longer runs a
WireGuard tunnel.
- ⚠️ **Never reboot nuc with the display powered on** — the i915 probe
dies and takes every container with it (including LAN DNS). Symptoms
and fix: [jellyfin-client.md](jellyfin-client.md#-never-boot-nuc-with-the-display-active-2026-08-30)
## Instances
| Name | IP | Doc | Features |
|---|---|---|---|
| [jellyfin-server](jellyfin-server.md) | 192.168.0.5 | ✅ | unprivileged, autostart; iGPU render node (`gpu` device, render gid) for QSV/VAAPI transcoding; `/srv/media` disk device (`shift=true`); proxy device → host :8096 |
| [jellyfin-server](jellyfin-server.md) | 192.168.0.5 | ✅ | unprivileged, autostart; iGPU render node (`gpu` device, render gid) for QSV/VAAPI transcoding; `/srv/media` disk device (NFS from nas, `shift=false`, read-only); proxy device → host :8096 |
| [jellyfin-client](jellyfin-client.md) | 192.168.0.6 | ✅ | **privileged**, autostart; full iGPU (`gpu` device, gid 44) → HDMI kiosk (cage + Jellyfin Media Player); custom `raw.lxc` (bind `/dev/snd`, `/dev/input`, host `/run/udev`); Pioneer USB audio as ALSA default; FR keymap; go-librespot Spotify Connect ("Pioneer A-70") |
| [transmission-bt](transmission-bt.md) | 192.168.0.7 | ✅ | unprivileged, autostart; always-on WireGuard full tunnel → ks4 (egress = 193.70.35.17, kill switch: no default route); `/srv/media` disk device (`shift=true`), downloads to `/media/downloads`; web UI :9091 (LAN only) |
| blocky | 192.168.0.254 | — | unprivileged, autostart; DNS ad-blocker |
| privoxy | 192.168.0.11 | — | unprivileged, autostart; filtering HTTP proxy |
| homeassistant | (stopped) | — | **virtual machine**, 50 GiB root disk on pool `data` |
Moved to [`nas`](../nas/README.md) on 2026-08-30: `transmission-bt`
(next to the media dataset it writes to), plus `blocky` and `privoxy`
so LAN DNS and the proxy survive nuc being shut down.