mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-02 19:02:31 +00:00
docs: review GPU and Coral guides in all seven translations
This commit is contained in:
@@ -14,18 +14,18 @@
|
||||
},
|
||||
"whenUse": {
|
||||
"heading": "When to use this",
|
||||
"body": "Typical use case: running <frigateLink>Frigate</frigateLink>, Agent DVR, Blue Iris + CodeProject.AI, or any other object-detection app inside an LXC and wanting the Coral TPU to do the ML inference instead of the CPU. With Coral, inference latency drops from ~100 ms to ~5 ms per frame and CPU load stays near zero."
|
||||
"body": "Use this for <frigateLink>Frigate</frigateLink> or another compatible Linux detection app in LXC. Coral runs supported ML inference instead of the CPU. Performance depends on the model and hardware; video decoding and other application work still consume resources."
|
||||
},
|
||||
"prereqs": {
|
||||
"title": "Before you start",
|
||||
"drivers": "<strong>Coral drivers already installed on the host</strong>. This script does not install them; it only configures passthrough to the container. Run <hostLink>Install Coral TPU on the Host</hostLink> first if you haven't.",
|
||||
"drivers": "<strong>Prepare the Coral device on the host</strong>. M.2 / PCIe needs the host driver loaded; USB needs device access and suitable permissions. See <hostLink>Install Coral TPU on the Host</hostLink>. The app runtime must be available inside the container.",
|
||||
"driversCheck": "ls /dev/apex_* 2>/dev/null ; lsusb | grep -E '1a6e:089a|18d1:9302'",
|
||||
"container": "<strong>An existing LXC container</strong>, ideally running a <strong>Debian / Ubuntu</strong>-based distro — the in-container runtime install uses <code>apt-get</code>. <strong>Non-Debian containers</strong> (Alpine, Arch, RHEL, SUSE…) are still supported in <strong>passthrough-only mode</strong>: the script detects the distro and offers a prompt to skip the <code>libedgetpu</code> APT install while still writing the device passthrough config — useful for app containers that bundle the runtime themselves (e.g. the Frigate Docker image).",
|
||||
"downtime": "<strong>Be OK with a brief downtime</strong> of the container. The script stops it to apply config changes, then starts it back up to install drivers inside. No host reboot needed."
|
||||
},
|
||||
"hostPrep": {
|
||||
"title": "Host must be prepared first",
|
||||
"body": "If you run this script before installing Coral drivers on the host (the <code>gasket</code>/<code>apex</code> kernel module for M.2, the <code>libedgetpu</code> runtime for USB), the LXC config is still written but the container won't find the device at runtime. Order matters: <strong>host install → LXC passthrough → in-container app</strong>."
|
||||
"body": "M.2 / PCIe needs the host <code>gasket</code>/<code>apex</code> driver and a working device node. USB needs the connected device and permissions; it does not require the host to run the app. The <code>libedgetpu</code> runtime must be available where the app runs. Follow <strong>host preparation → LXC device access → app setup</strong>."
|
||||
},
|
||||
"running": {
|
||||
"heading": "Running the script",
|
||||
@@ -34,39 +34,39 @@
|
||||
},
|
||||
"howRuns": {
|
||||
"heading": "How the script runs",
|
||||
"body": "One decision upfront (which container?), then the script handles USB and PCIe paths independently based on what it finds on the host. If both are present, both get passed."
|
||||
"body": "Choose the target container. The script configures USB access even if no USB Coral is currently connected, then adds M.2 / PCIe access when the corresponding hardware is detected."
|
||||
},
|
||||
"walkthrough": {
|
||||
"heading": "Walking through the flow",
|
||||
"pick": {
|
||||
"title": "Pick the LXC container",
|
||||
"body": "A dialog shows every LXC on the host (from <code>pct list</code>). Pick the one that should get the Coral. Running or stopped, it doesn't matter — the script handles both (stops it briefly to write config, then starts it back up to install drivers)."
|
||||
"body": "The picker lists eligible containers from <code>pct list</code>; OCI-image containers are hidden and managed through OCI manager Apps. Choose the target, running or stopped. The script stops it if needed, writes configuration and starts it for runtime installation."
|
||||
},
|
||||
"gpuHint": {
|
||||
"title": "GPU passthrough suggestion (optional)",
|
||||
"body": "If the host has a GPU (Intel iGPU, AMD, NVIDIA) and the chosen container does NOT have GPU passthrough configured, the script shows a one-time dialog suggesting you run <lxcGpuLink>Add GPU to LXC</lxcGpuLink> first. Coral is most often paired with hardware video decode (Quick Sync, VA-API, NVENC) for apps like Frigate. You can say yes (exits, run the GPU script, then come back) or no (continues with TPU-only setup)."
|
||||
"body": "If a GPU is detected but not configured for this container, a dialog recommends <lxcGpuLink>Add GPU to LXC</lxcGpuLink> for hardware video decoding, such as Quick Sync, VA-API or NVDEC. It asks whether to continue with Coral only: Yes continues TPU setup; No exits so you can configure the GPU first."
|
||||
},
|
||||
"usb": {
|
||||
"title": "Write LXC config — USB path",
|
||||
"body": "If a USB Accelerator is present, the script does two things: (1) writes a udev rule on the host so the device gets a stable name <code>/dev/coral</code> whatever USB port it's in, and (2) bind-mounts the <strong>whole</strong> <code>/dev/bus/usb</code> tree into the container.",
|
||||
"body": "The script creates a host udev rule for the <code>/dev/coral</code> symlink and bind-mounts the <strong>whole</strong> <code>/dev/bus/usb</code> tree into the container. This USB configuration is written even when no Coral USB is currently connected; it exposes more than just that one device.",
|
||||
"whyTitle": "Why mount /dev/bus/usb instead of /dev/coral?",
|
||||
"whyBody": "The USB device node path (e.g. <code>/dev/bus/usb/001/005</code>) changes when you replug the accelerator into a different port. Earlier versions of the script bind-mounted the <code>/dev/coral</code> symlink, which pointed at an old path and broke. Mounting the whole USB tree means the container sees whatever the current path is, so a replug just works."
|
||||
"whyBody": "USB node paths such as <code>/dev/bus/usb/001/005</code> change on reconnect. Older versions bind-mounted the <code>/dev/coral</code> symlink and could retain a stale path. Mounting the whole USB tree makes the current device node visible; the app may still need to reopen it."
|
||||
},
|
||||
"pcie": {
|
||||
"title": "Write LXC config — M.2 / PCIe path",
|
||||
"body1": "If a M.2 / PCIe Coral is present on the host and <code>/dev/apex_0</code> exists (the apex kernel module is loaded), the script uses the modern Proxmox <code>dev</code> API which handles cgroup2 permissions automatically for both privileged and unprivileged containers:",
|
||||
"body2": "If the host hasn't booted yet with the apex module loaded (you just ran <hostLink>Install Coral on Host</hostLink> and haven't rebooted), <code>/dev/apex_0</code> doesn't exist yet. The script falls back to classic cgroup2 + bind mount with <code>create=file</code> so the entries are valid even when the device hasn't materialised:",
|
||||
"body2": "If <code>/dev/apex_0</code> is absent after <hostLink>Install Coral on Host</hostLink>, the script writes a classic cgroup2 configuration and optional bind mount with <code>create=file</code>. This does not itself create a working device:",
|
||||
"rebootTitle": "Reboot the host first if you just installed Coral drivers",
|
||||
"rebootBody": "The fallback cgroup2 + mount will be written, but the device only actually exists after a host reboot loads the <code>apex</code> module. If you haven't rebooted, reboot now before starting the container."
|
||||
"rebootBody": "The fallback mount does not load the host <code>apex</code> driver. Load the driver, or reboot after installation, and verify the host device exists. Re-run the script once the device is ready to apply the modern device entry, then restart the container."
|
||||
},
|
||||
"drivers": {
|
||||
"title": "Start the container + install Coral runtime inside",
|
||||
"body": "Config changes in Proxmox LXC take effect on the next start — so the script starts the container, waits up to 15 seconds for <code>pct exec</code> to respond, then drops a bash script inside that:",
|
||||
"body": "The script starts the container and waits up to 15 seconds for its running status, then uses <code>pct exec</code> to run the runtime installer inside. The installer:",
|
||||
"items": [
|
||||
"Runs <code>apt-get update</code>.",
|
||||
"Installs the Coral repository prerequisites: <code>gnupg</code>, <code>curl</code>, <code>ca-certificates</code>.",
|
||||
"Imports Google's Coral GPG key to <code>/etc/apt/keyrings/coral-edgetpu.gpg</code> (modern path, same as the host installer uses) and adds the <code>coral-edgetpu-stable</code> APT repository with <code>signed-by=</code>.",
|
||||
"Installs the latest <code>libedgetpu1-std</code> (default). If you have a M.2 Coral, you'll be prompted to pick between <code>libedgetpu1-std</code> (standard) and <code>libedgetpu1-max</code> (max performance, runs hotter)."
|
||||
"Installs <code>libedgetpu1-std</code> by default. When an M.2 Coral is detected, the script offers a choice of <code>libedgetpu1-std</code> or <code>libedgetpu1-max</code>. The choice of runtime package does not itself configure application detection settings."
|
||||
],
|
||||
"noIgpuTitle": "Why no iGPU drivers here?",
|
||||
"noIgpuBody": "Earlier versions of this script also installed Intel <code>va-driver-all</code>, <code>intel-opencl-icd</code> and friends so the same container could do Quick Sync video decode alongside Coral inference. That doubled-up responsibility caused confusing failures when the user only wanted Coral. The iGPU side is now the exclusive job of <lxcGpuLink>Add GPU to LXC</lxcGpuLink> — run it first if you also want hardware video decode in the container.",
|
||||
@@ -92,15 +92,15 @@
|
||||
"troubleshoot": {
|
||||
"heading": "Troubleshooting",
|
||||
"apexTitle": "Container started but /dev/apex_0 missing inside",
|
||||
"apexBody": "Host apex module isn't loaded. On the host: <code>lsmod | grep apex</code> — if empty, run <code>modprobe apex</code>, or reboot if you just installed Coral drivers. Once the host has <code>/dev/apex_0</code>, restart the container: <code>pct stop <ctid> && pct start <ctid></code>.",
|
||||
"apexBody": "Check the host driver first: <code>lsmod | grep apex</code>. If missing, try <code>modprobe apex</code> or reboot after driver installation. Once <code>/dev/apex_0</code> exists on the host, verify the LXC device entry and restart the container with <code>pct stop <ctid> && pct start <ctid></code>.",
|
||||
"replugTitle": "USB Coral disappears after replug in a different port",
|
||||
"replugBody": "This is exactly why the script mounts <code>/dev/bus/usb</code> instead of the <code>/dev/coral</code> symlink. If you're hitting this, check your LXC config has <code>lxc.mount.entry: /dev/bus/usb dev/bus/usb ...</code> and not a reference to <code>/dev/coral</code> directly. Old configs from earlier script versions may need updating — re-run the script on the same container and the config gets refreshed.",
|
||||
"alpineTitle": "Alpine / Arch / RHEL / SUSE container — runtime not installed",
|
||||
"alpineBody": "If you chose <em>passthrough-only mode</em> when the script prompted, the LXC config is written and the Coral device is visible inside the container, but the <code>libedgetpu</code> runtime is not installed. That's by design: Google's APT repo only ships for Debian/Ubuntu. Install the runtime manually with your distro's package manager (Alpine: <code>apk add</code>; Arch: AUR; RHEL/SUSE: build from source) following Google's official guide, or run an app container that bundles the runtime — the Frigate Docker image is the canonical example: just expose the device with <code>--device /dev/apex_0:/dev/apex_0</code> (M.2) or the USB bind mount the script already wrote (USB).",
|
||||
"alpineBody": "In <em>passthrough-only mode</em>, device configuration is written but <code>libedgetpu</code> is not installed. Use a compatible community package or build from source; check availability before using a package command such as Alpine <code>apk add</code>. An app image such as Frigate can bundle the runtime. With nested Docker, also forward the M.2 device using <code>--device /dev/apex_0:/dev/apex_0</code>, or mount the USB tree into that Docker container; the LXC mount alone does not forward it into Docker.",
|
||||
"frigateTitle": "Frigate says 'Coral EdgeTPU detected but not available'",
|
||||
"frigateBody": "Almost always a permissions issue inside the container. Frigate runs as root by default; check the root user is in the <code>plugdev</code> group inside the container (for USB), and that the process can read <code>/dev/apex_0</code> (for M.2). <code>ls -l /dev/apex_0</code> from inside the container should show group <code>apex</code> — if not, add the GID alignment to <code>/etc/group</code> or switch the container to privileged mode.",
|
||||
"frigateBody": "Check runtime availability, device visibility and read/write access for the actual app process. For USB, inspect permissions and any <code>plugdev</code> membership. For M.2, inspect <code>/dev/apex_0</code> with <code>ls -l /dev/apex_0</code>. A group name such as <code>apex</code> in <code>/etc/group</code> is not enough: numeric GIDs and LXC mappings must match. Also check whether another process already claims the TPU; do not switch to privileged mode as the first fix.",
|
||||
"logsTitle": "Check both host and container logs",
|
||||
"logsBody": "On the host: <code>journalctl -u pvedaemon | grep -i coral</code>. Inside the container: check the app logs (Frigate: <code>/config/logs/</code>, CodeProject.AI: its own log directory). The classic error pattern is \"Coral detected, runtime loaded, but inference engine can't claim it\" — that's permissions 9 out of 10 times."
|
||||
"logsBody": "On the host, inspect kernel device messages with <code>journalctl -k | grep -i -e apex -e gasket -e usb</code>. Inside the container, inspect the app logs; for nested Docker use <code>docker logs <container></code>. Permissions, missing runtime, USB connectivity or another process claiming the TPU can all cause failures."
|
||||
},
|
||||
"related": {
|
||||
"heading": "Related",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"intro": {
|
||||
"title": "What this does",
|
||||
"body": "Everything the <pveLink>official Proxmox PCI passthrough wiki</pveLink> walks you through manually — IOMMU enablement, VFIO modules, driver blacklisting, vendor ID discovery, <code>hostpci</code> setup, ROM dumps on AMD, KVM hiding on NVIDIA — done in one run with sanity checks at every step. The script is also aware of the <em>other</em> things on your host: if the same GPU is already assigned to an LXC or another VM, it offers to migrate cleanly instead of silently breaking the existing setup."
|
||||
"body": "Automates the relevant host and <code>hostpci</code> configuration steps described in the <pveLink>Proxmox PCI passthrough documentation</pveLink>. It checks assignments in <em>other</em> guests and offers conflict-handling choices. These checks do not guarantee support for every GPU, reset method or guest driver."
|
||||
},
|
||||
"who": {
|
||||
"heading": "Who is this for?",
|
||||
@@ -20,11 +20,11 @@
|
||||
"title": "Before you start",
|
||||
"gpu": "<strong>A supported GPU</strong> physically installed. The script detects Intel, AMD and NVIDIA via <code>lspci</code>.",
|
||||
"gpuCheck": "lspci | grep -iE 'VGA|3D|Display'",
|
||||
"iommu": "<strong>IOMMU virtualization</strong> available in BIOS/UEFI (Intel VT-d or AMD-Vi). If it's off at the firmware level, no amount of Linux config fixes it — you have to enable it in the BIOS first. The script detects this and offers to enable it on the OS side.",
|
||||
"q35": "The target VM uses <strong>q35</strong> machine type. Older <code>i440fx</code> does not reliably support PCIe passthrough and the script will refuse to proceed.",
|
||||
"q35Check": "qm config '<'vmid'>' | grep machine",
|
||||
"iommu": "<strong>IOMMU support</strong> must be available in hardware and enabled in firmware where required (Intel VT-d or AMD-Vi). The script checks the running system and can configure Linux boot parameters; it cannot change BIOS/UEFI settings or prove that every inactive IOMMU is disabled in firmware.",
|
||||
"q35": "This assistant requires the <strong>q35</strong> machine type and refuses <code>i440fx</code>. Machine type is separate from BIOS/UEFI firmware; changing an existing VM chipset requires planning and is not performed automatically.",
|
||||
"q35Check": "qm config VMID | grep machine",
|
||||
"moreGpus": "Preferably <strong>more than one GPU</strong> in the host, or console access on another output (IPMI, KVM-over-IP, serial). Once you pass the only GPU to a VM, the host console goes dark. With two NVIDIA GPUs you can pass one to a VM and keep the other on the host — the script handles this per-BDF (see <em>NVIDIA</em> in the vendor notes below).",
|
||||
"nvidiaInstalled": "If you're on a Proxmox that already installed the NVIDIA driver via <nvidiaLink>NVIDIA Drivers on the Host</nvidiaLink>: the GPU you pass to the VM gets unbound from the host <code>nvidia</code> driver and rebound to <code>vfio-pci</code>. The <code>nvidia</code> module stays loaded so any <strong>other</strong> NVIDIA GPU you have on the host keeps working with <code>nvidia-smi</code>."
|
||||
"nvidiaInstalled": "If you installed <nvidiaLink>NVIDIA Drivers on the Host</nvidiaLink>, selected functions are reserved for <code>vfio-pci</code> rather than <code>nvidia</code>. The <code>nvidia</code> module can remain available for <strong>other</strong> cards outside the affected IOMMU group; verify them with <code>nvidia-smi</code>."
|
||||
},
|
||||
"pickOne": {
|
||||
"title": "VM passthrough vs LXC sharing — pick one per GPU",
|
||||
@@ -39,34 +39,34 @@
|
||||
},
|
||||
"howRuns": {
|
||||
"heading": "How the script runs",
|
||||
"body": "The flow has three phases with clear separation between \"collecting information and decisions\" and \"actually applying changes\". Until the final confirmation, nothing on your host or VM has been touched."
|
||||
"body": "Detection and selection precede the main host/VM changes and a final summary confirms that plan. Enabling IOMMU has its own earlier confirmation and can already edit the boot configuration. Later associated-audio cleanup may also ask for a choice."
|
||||
},
|
||||
"walkthrough": {
|
||||
"heading": "Walking through the flow",
|
||||
"detect": {
|
||||
"title": "Detect GPUs and check IOMMU",
|
||||
"body": "The script lists every GPU it finds. If IOMMU isn't already enabled in the running kernel cmdline, you'll get a yes/no prompt to append <code>intel_iommu=on</code> (or <code>amd_iommu=on</code>) + <code>iommu=pt</code> to the right boot file. Selection is based on the bootloader: <code>/etc/kernel/cmdline</code> when the host boots via systemd-boot (detected by the presence of <code>root=ZFS=</code> in that file, the default on ProxmoxVE-installed ZFS-on-root systems), otherwise <code>/etc/default/grub</code>. If you accept and the kernel cmdline changes, the script flags that a reboot will be needed at the end.",
|
||||
"body": "Checks active IOMMU support, not just explicit kernel parameters. If inactive, a separately confirmed step can add <code>intel_iommu=on</code> or <code>amd_iommu=on</code> with <code>iommu=pt</code>. Its boot-file heuristic uses <code>/etc/kernel/cmdline</code> when a ZFS-root marker such as <code>root=ZFS=</code> exists there; otherwise it uses <code>/etc/default/grub</code>. That heuristic is not proof of the actual bootloader. Newly configured IOMMU takes effect after reboot; inspect the real groups afterwards.",
|
||||
"tipTitle": "Already ran post-install?",
|
||||
"tipBody": "If you previously enabled <postLink>VFIO IOMMU support</postLink> from the post-install scripts, IOMMU is already on and this step silently passes. Good.",
|
||||
"tipBody": "If <postLink>VFIO IOMMU support</postLink> was previously configured and is active in the running kernel, this check passes. A saved next-boot setting alone does not prove it is active.",
|
||||
"imageAlt": "List of detected GPUs with vendor and PCI address"
|
||||
},
|
||||
"preflight": {
|
||||
"title": "Pick a GPU and run pre-flight checks",
|
||||
"intro": "Once you pick the GPU, the script runs a series of checks that can each block further progress:",
|
||||
"items": [
|
||||
"<strong>Not in SR-IOV.</strong> If the device is a Virtual Function or a Physical Function with active VFs, passthrough would clash with SR-IOV usage. Blocked.",
|
||||
"<strong>SR-IOV guard.</strong> This assistant refuses VFs and PFs with active VFs because its full-device workflow is not an SR-IOV configuration flow. SR-IOV passthrough must be configured separately on supported hardware.",
|
||||
"<strong>Single-GPU warning.</strong> If this is the only GPU in the host, you get a scary dialog reminding you that after reboot the console goes dark — make sure you have SSH or web-UI access from another machine.",
|
||||
"<strong>AMD reset method.</strong> AMD GPUs have a long history of not resetting cleanly between VM stops and starts. The script checks <code>/sys/bus/pci/devices/<pci>/reset_method</code>: if the card is an APU without FLR it <em>blocks</em> (practically unusable); a dedicated AMD card without FLR is also blocked; anything with an unknown reset mode warns but lets you continue with explicit override.",
|
||||
"<strong>AMD reset policy.</strong> Reads <code>/sys/bus/pci/devices/<pci>/reset_method</code>. An APU or dedicated card without FLR is <em>blocked by this assistant’s policy</em>; an unknown subtype without FLR requires an explicit override. This does not establish universal hardware impossibility.",
|
||||
"<strong>Not in D3cold.</strong> Some AMD cards report <code>D3cold</code> power state while idle, which makes them invisible during VM startup. Blocked until you wake the GPU.",
|
||||
"<strong>IOMMU group analysis.</strong> Reads <code>/sys/kernel/iommu_groups/</code> to find every non-bridge device in the GPU's group. <em>All of them</em> will be passed to the VM together — if your motherboard groups the GPU with a network card, the network card goes too."
|
||||
"<strong>IOMMU group analysis.</strong> Reads <code>/sys/kernel/iommu_groups/</code> and includes <em>all non-bridge members</em> in the VM plan, possibly network or storage controllers. Inspect them before confirming. If IOMMU is pending reboot, real groups are unavailable and the plan initially contains only the selected GPU function; verify isolation after reboot."
|
||||
],
|
||||
"audioIntro": "<strong>Audio companion.</strong> Two paths, depending on where the audio lives:",
|
||||
"audioDgpu": "<strong>Discrete GPU (NVIDIA / AMD):</strong> HDMI audio sits on the same card as function <code>.1</code> of the GPU's PCI slot. Auto-included. This audio device was never used by the host, so no one loses anything.",
|
||||
"audioDgpu": "<strong>Discrete GPU:</strong> HDMI audio often occupies function <code>.1</code> of the same PCI slot and is automatically included when detected. If the host was using that audio device, it loses access when the device is reserved for the VM.",
|
||||
"audioIgpu": "<strong>Intel iGPU (or any GPU without a <code>.1</code> sibling):</strong> the HDMI / analog audio lives on the chipset at a different slot (<code>00:1f.3</code> typically). The script scans the host, lists every PCI audio controller with its current driver (<code>snd_hda_intel</code>, etc.), and asks you which one(s) to pass through. Default is <strong>none</strong> — you explicitly opt in."
|
||||
},
|
||||
"pickVm": {
|
||||
"title": "Pick the target VM",
|
||||
"body": "You're shown the list of VMs on the host and pick one. The script checks the VM is q35 — BIOS/i440fx machine types are refused because PCIe passthrough on them is unreliable. If you have a q35 VM with the GPU already assigned (partially or fully), the existing entry is reused instead of being duplicated.",
|
||||
"body": "Choose a VM from the list. The assistant requires q35 and reuses existing GPU entries where possible. BIOS/UEFI firmware is a separate setting, not a machine type; this check does not automatically change the installed guest’s chipset or boot mode.",
|
||||
"imageAlt": "VM list with name, ID and status shown as a picker"
|
||||
},
|
||||
"switchMode": {
|
||||
@@ -75,34 +75,34 @@
|
||||
"items": [
|
||||
"<strong>GPU is free.</strong> Nothing to do, continue.",
|
||||
"<strong>GPU is in a different VM.</strong> If the source VM is currently running, the script aborts — two VMs can't share an exclusive VFIO assignment, and the source VM has to be stopped first. If the source VM is stopped, you get two options: <em>Keep GPU in the source VM's config but disable Start on boot</em>, or <em>Remove the GPU lines from the source VM's config and keep Start on boot</em>. A fast-path also exists: if the GPU is already bound to <code>vfio-pci</code> and the source VM is a plain VM→VM swap, no host reconfiguration is done and no reboot is needed.",
|
||||
"<strong>GPU is in an LXC (shared mode).</strong> You get two options on a menu: <em>Keep GPU in the LXC config but disable Start on boot</em>, or <em>Remove the GPU lines from the LXC config (<code>lxc.cgroup2.devices.allow</code> / <code>lxc.mount.entry</code>) and keep Start on boot</em>. Either way the LXC won't see the GPU after the switch, and the VM will — this is the \"switch mode\" mechanic that gives this menu entry its secondary label."
|
||||
"<strong>GPU used by LXC.</strong> For ordinary containers, choose <em>keep the GPU configuration and disable Start on boot</em> or <em>remove GPU device configuration, including legacy <code>lxc.cgroup2.devices.allow</code>/<code>lxc.mount.entry</code> rules, and keep Start on boot</em>. OCI containers retain their configuration and are stopped with Start on boot disabled; remove their GPU through OCI manager Apps. Conflict detection is by GPU device family and may include other cards of that family."
|
||||
],
|
||||
"imageAlt": "Dialog offering to remove the GPU from an LXC before assigning it to the VM",
|
||||
"smartTitle": "Audio siblings are cleaned up smartly too",
|
||||
"smartBody": "If the source VM had extra audio devices attached alongside the GPU, the script removes <strong>only the ones that are now orphan</strong> — i.e. audio entries whose display sibling is also being removed. Audio tied to a different GPU that stays in the VM is kept untouched. This matters when you detach an Intel iGPU (which shares chipset audio) from a VM that also has a discrete NVIDIA / AMD card still passed through: the dGPU's HDMI audio (<code>02:00.1</code>) stays, the chipset audio (<code>00:1f.3</code>) leaves."
|
||||
"smartBody": "After removing GPU assignments from the source VM, the script can offer a checklist of <strong>potentially orphaned audio devices</strong>. Review it and uncheck anything the source still needs. For example, dedicated-card audio at <code>02:00.1</code> may remain while chipset audio at <code>00:1f.3</code> is offered for removal. The checklist, not a universal display/audio pairing guarantee, determines the extra removals."
|
||||
},
|
||||
"audioPick": {
|
||||
"title": "(If no .1 sibling) Pick which audio controllers to include",
|
||||
"body": "Only happens for Intel iGPU and similar split-audio setups. A checklist shows every PCI audio controller on the host (excluding any already in the GPU's IOMMU group), labelled with its current driver. Select the ones you want — or none, if the VM doesn't need audio from the host hardware.",
|
||||
"imageAlt": "Checklist dialog with every host PCI audio controller (BDF + driver) when the GPU has no .1 sibling audio",
|
||||
"warnTitle": "Don't tick audio the host relies on",
|
||||
"warnBody": "If the host currently uses an audio controller for anything — for example, the Proxmox shell beeping, or a VM you've already passed it to — ticking it here means the host (and any other VM sharing it) loses access after reboot. When in doubt, leave this empty and you can always re-run the script later to add audio if needed."
|
||||
"warnBody": "Assigning an audio controller to the VM can remove host access; it cannot simultaneously belong to another running VM. Leave optional audio unselected when unnecessary, and verify ownership before moving it. PCI audio is not necessarily the source of the host console beep."
|
||||
},
|
||||
"summary": {
|
||||
"title": "Review the confirmation summary",
|
||||
"body": "A final dialog shows exactly what's about to change on the host and in the VM. This is the last off ramp — if anything looks wrong (an extra device in the IOMMU group you didn't expect, the wrong GPU, the wrong VM), cancel here and nothing has been touched yet.",
|
||||
"body": "Review the final host and VM plan, especially every IOMMU-group member, and cancel if it is wrong. This stops the main changes; it does not undo an earlier separately confirmed IOMMU boot-configuration change.",
|
||||
"imageAlt": "Summary dialog listing host changes (VFIO/blacklist files) and VM config changes (hostpci lines) before applying"
|
||||
},
|
||||
"hostApply": {
|
||||
"title": "Host changes are applied",
|
||||
"intro": "Phase 2 runs non-interactively. Host-side the script can touch:",
|
||||
"intro": "The apply phase performs the host and VM changes. Associated-audio cleanup may still prompt for a selection. Host changes can include:",
|
||||
"items": [
|
||||
"<code>/etc/modules</code> — adds <code>vfio</code>, <code>vfio_iommu_type1</code>, <code>vfio_pci</code> (plus <code>vfio_virqfd</code> on kernels < 6.2).",
|
||||
"<code>/etc/modprobe.d/vfio.conf</code> — for AMD / Intel, sets <code>options vfio-pci ids=<vendor:device,...> disable_vga=1</code> so VFIO claims the GPU early at boot. For NVIDIA the file only adds <code>softdep nvidia pre: vfio-pci</code> (plus <code>_drm</code>/<code>_modeset</code>/<code>_uvm</code>) — actual binding is per-BDF via the udev rule below. On AMD, also adds <code>softdep</code> lines forcing <code>vfio-pci</code> to load before <code>radeon</code> / <code>amdgpu</code>.",
|
||||
"<code>/etc/modprobe.d/iommu_unsafe_interrupts.conf</code> and <code>kvm.conf</code> — sensible workarounds that most Windows / macOS VMs need (<code>allow_unsafe_interrupts=1</code>, <code>ignore_msrs=1</code>).",
|
||||
"<code>/etc/modprobe.d/blacklist.conf</code> — blacklists only the open-source drivers for the selected vendor (<code>nouveau</code>/<code>lbm-nouveau</code> for NVIDIA; <code>radeon</code>+<code>amdgpu</code> for AMD; <code>i915</code> for Intel), so drivers for other vendors on the same host stay loaded. The proprietary <code>nvidia</code> module is <strong>only</strong> blacklisted (via a separate <code>/etc/modprobe.d/proxmenux-nvidia-vfio-blacklist.conf</code>) once <em>every</em> NVIDIA GPU on the host has been switched to VFIO — until that point it stays loaded so any NVIDIA card you keep on the host keeps working.",
|
||||
"<code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> + <code>/etc/proxmenux/vfio-bind.bdfs</code> — <strong>NVIDIA only</strong>. Per-BDF binding state. The udev rule applies <code>ATTR'{'driver_override'}'=\"vfio-pci\"</code> at the PCI ADD event for each tracked Bus:Device.Function, so only the GPU(s) you've explicitly passed go to VFIO. This is what makes multi-GPU NVIDIA work — your other NVIDIA cards keep their <code>nvidia</code> driver and stay usable on the host.",
|
||||
"<strong>AMD only.</strong> Dumps the GPU ROM from sysfs (<code>/sys/bus/pci/.../rom</code>) or the ACPI VFCT table to <code>/usr/share/kvm/vbios_<card>.bin</code>. The VM references it via <code>romfile=</code> so cards that misreport their own VBIOS still initialise correctly.",
|
||||
"Writes <code>/etc/modprobe.d/iommu_unsafe_interrupts.conf</code> and <code>kvm.conf</code> with <code>allow_unsafe_interrupts=1</code> and <code>ignore_msrs=1</code>. These are compatibility settings applied by the script, not universal Windows/macOS requirements; unsafe interrupts relax interrupt-remapping protection.",
|
||||
"<code>/etc/modprobe.d/blacklist.conf</code>: NVIDIA — <code>nouveau</code>/<code>lbm-nouveau</code>; AMD — <code>radeon</code> + <code>amdgpu</code>; Intel — <code>i915</code>. These vendor-wide entries may affect other cards using the same driver. The proprietary <code>nvidia</code> module is blocked <strong>only</strong> through <code>/etc/modprobe.d/proxmenux-nvidia-vfio-blacklist.conf</code> when <em>all</em> host NVIDIA cards are tracked for VFIO.",
|
||||
"<code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> + <code>/etc/proxmenux/vfio-bind.bdfs</code> — <strong>NVIDIA only.</strong> The udev rule sets <code>ATTR'{'driver_override'}'=\"vfio-pci\"</code> at PCI ADD for tracked BDFs, including affected IOMMU-group functions. Cards outside those groups can retain the <code>nvidia</code> driver. Per-BDF policy does not split a hardware IOMMU group.",
|
||||
"<strong>AMD only.</strong> Attempts a ROM dump from <code>/sys/bus/pci/.../rom</code> or ACPI VFCT into <code>/usr/share/kvm/vbios_<card>.bin</code>. If successful, the VM uses <code>romfile=</code>. A valid dump does not guarantee successful GPU initialization.",
|
||||
"<strong>NVIDIA only.</strong> Host NVIDIA services (<code>nvidia-persistenced</code>, <code>nvidia-powerd</code>, <code>nvidia-fabricmanager</code>) are stopped and disabled only when every NVIDIA GPU is assigned to VFIO. With a mixed host they remain active, together with the <code>nvidia</code> module, for the GPU(s) that stay native.",
|
||||
"<code>update-initramfs -u -k all</code> — only runs if any of the above actually changed."
|
||||
]
|
||||
@@ -110,25 +110,25 @@
|
||||
"vmApply": {
|
||||
"title": "VM config is applied via qm set",
|
||||
"body": "The VM config at <code>/etc/pve/qemu-server/<vmid>.conf</code> is updated via <code>qm set</code> (never by direct <code>sed</code>):",
|
||||
"after1": "A <code>x-vga=1</code> flag is added for every vendor <strong>except</strong> Intel iGPU — Intel integrated GPUs don't have dedicated VRAM for a pre-boot console, so that flag causes hangs.",
|
||||
"after1": "The script adds <code>x-vga=1</code> for AMD and NVIDIA, <strong>not</strong> Intel. This describes its configuration policy; it does not establish that every Intel iGPU lacks firmware or that the flag universally causes hangs.",
|
||||
"after2": "Additional <code>hostpciN</code> lines are appended if the GPU's IOMMU group contains other devices you need to pass together."
|
||||
},
|
||||
"reboot": {
|
||||
"title": "Reboot if host config was touched",
|
||||
"body": "If Phase 2 changed anything at the kernel-module / cmdline / blacklist level, you'll be prompted to reboot. Reboot is mandatory before starting the VM — otherwise the GPU is still held by the host driver and VFIO can't claim it.",
|
||||
"body": "Follow the reboot prompt when host boot or driver settings change, and verify the GPU’s active binding before starting the VM. Saved configuration does not prove it is active. A VM-to-VM reassignment with the correct VFIO state can avoid a host reboot.",
|
||||
"imageAlt": "Summary screen showing what was changed, followed by a reboot prompt"
|
||||
}
|
||||
},
|
||||
"vendors": {
|
||||
"heading": "Vendor-specific notes",
|
||||
"nvidiaHeading": "NVIDIA",
|
||||
"nvidiaBody": "NVIDIA consumer drivers detect that they're running in a VM and refuse to initialise with the infamous <em>\"Code 43\"</em> error. ProxMenux's workaround: hide KVM from the guest (<code>hidden=1</code>), set a spoofed hypervisor vendor ID <code>NV43FIX</code> in the <code>args</code> line, and pass <code>kvm=off</code>. This has worked reliably on GeForce drivers for years. On datacenter / Tesla / Quadro cards this isn't needed — those drivers are licensed for virtualisation.",
|
||||
"nvidiaBody": "The script retains a legacy <em>Code 43</em> workaround: <code>hidden=1</code>, vendor ID <code>NV43FIX</code> in <code>args</code>, and <code>kvm=off</code>. It is not a universal requirement for current GeForce drivers: NVIDIA enabled Windows-VM passthrough support in R465. Code 43 can have other causes; verify the actual GPU and driver combination.",
|
||||
"nvidiaMultiHeading": "Multi-GPU NVIDIA support",
|
||||
"nvidiaMultiBody": "Hosts with two or more NVIDIA GPUs are first-class. You can pass one card to a VM and keep the other(s) on the host for <code>nvidia-smi</code>, LXC GPU sharing, or any host-side workload. ProxMenux binds VFIO <strong>per-BDF</strong> (Bus:Device.Function) via a udev rule rather than globally blacklisting the <code>nvidia</code> module — so each card's destination is independent of the others, even when both GPUs are the same model and share the same <code>vendor:device</code> ID. The host nvidia driver stays loaded; only the specific BDFs you select get redirected to <code>vfio-pci</code>.",
|
||||
"nvidiaMultiBody": "Mixed NVIDIA use is supported <strong>per BDF</strong>. Functions assigned to <code>vfio-pci</code> are tracked by PCI address, not merely a shared <code>vendor:device</code> ID. Cards outside the affected IOMMU groups can keep <code>nvidia</code> and be checked with <code>nvidia-smi</code>. Two cards in the same group are not independently isolated by this policy.",
|
||||
"amdHeading": "AMD",
|
||||
"amdBody": "The \"AMD reset bug\" means some cards crash when the VM stops and can't re-initialise without a host reboot. ProxMenux pre-screens for this by reading the PCI reset method, but cannot fix it after the fact. If you hit it, the community fix is the <vendorResetLink>vendor-reset</vendorResetLink> kernel module. The script doesn't install it automatically — the module is a DKMS build you add yourself if you see reset failures. Also on Windows guests, the <em>RadeonResetBugFix</em> service is the common userspace workaround.",
|
||||
"amdBody": "Some AMD GPUs fail to reset after a VM stops. The assistant checks reported capabilities, not every real restart cycle. <vendorResetLink>vendor-reset</vendorResetLink> supports a limited device list and requires compatible kernel support and early loading; the script does not install it. The Windows <em>RadeonResetBugFix</em> project is another hardware-dependent workaround, not a guaranteed fix for all AMD GPUs.",
|
||||
"intelHeading": "Intel iGPU",
|
||||
"intelBody": "Intel iGPU passthrough is flaky but possible on UHD 630+ generations with <sriovLink>i915-sriov-dkms</sriovLink> for SR-IOV. For a single \"give the iGPU to one VM\" case, the script binds it exactly like a dedicated GPU, but skips <code>x-vga=1</code> (iGPUs don't carry a pre-boot VBIOS). You'll lose host console output — plan accordingly."
|
||||
"intelBody": "Full Intel iGPU passthrough and SR-IOV are separate workflows. This assistant reserves the full device for one VM and omits <code>x-vga=1</code>. <sriovLink>i915-sriov-dkms</sriovLink> applies only to supported SR-IOV hardware/kernel combinations; a “UHD 630+” label is not a compatibility rule. Plan alternate host-console access."
|
||||
},
|
||||
"verification": {
|
||||
"heading": "Verification"
|
||||
@@ -136,19 +136,19 @@
|
||||
"troubleshoot": {
|
||||
"heading": "Troubleshooting",
|
||||
"code43Title": "Code 43 in Windows (NVIDIA)",
|
||||
"code43Body": "The KVM hiding args didn't apply. Check <code>qm config <vmid> | grep -E \"cpu|args\"</code> — you should see <code>hidden=1</code> and <code>hv_vendor_id=NV43FIX</code>. If missing, re-run the script and re-select the same VM.",
|
||||
"code43Body": "Code 43 is not proof of failed KVM hiding. Inspect <code>qm config VMID | grep -E \"cpu|args\"</code> (replace VMID) for the script’s <code>hidden=1</code> and <code>hv_vendor_id=NV43FIX</code> settings, but also check the guest driver, GPU firmware and assignment. Re-running may exit early if the GPU is already assigned.",
|
||||
"amdResetTitle": "AMD GPU works once, fails on VM restart",
|
||||
"amdResetBody": "The AMD reset bug. Solutions (in order): (1) reboot the host — GPU will be usable again for one more VM cycle; (2) install the <code>vendor-reset</code> DKMS module and add <code>softdep amdgpu pre: vendor-reset</code>; (3) inside Windows, install the <em>RadeonResetBugFix</em> service.",
|
||||
"amdResetBody": "A reset failure is one possible cause. A host reboot or power cycle may restore the device temporarily. Check whether <code>vendor-reset</code> supports this exact GPU and kernel and load it early as its documentation requires; <code>softdep amdgpu pre: vendor-reset</code> alone does not guarantee early loading before VFIO. The Windows <em>RadeonResetBugFix</em> workaround also requires a compatible GPU.",
|
||||
"stuckBootTitle": "VM stuck booting / GPU not detected",
|
||||
"stuckBootBody": "Confirm VFIO actually holds the GPU on boot: <code>lspci -nnk -d vendor:device</code> must show <code>Kernel driver in use: vfio-pci</code>. If it still shows the vendor driver, the blacklist didn't take effect — check <code>/etc/modprobe.d/blacklist.conf</code> and <code>dmesg | grep vfio</code>, and regenerate initramfs: <code>update-initramfs -u -k all</code> then reboot.",
|
||||
"stuckBootBody": "Inspect the selected PCI address with <code>lspci -nnk -s PCI_ADDRESS</code>; expect <code>Kernel driver in use: vfio-pci</code>. Replace PCI_ADDRESS with the real BDF. If the native driver remains, inspect the appropriate binding policy, not only <code>/etc/modprobe.d/blacklist.conf</code>; NVIDIA also uses per-BDF state. Read <code>dmesg | grep vfio</code>. After correcting persistent configuration, rebuild with <code>update-initramfs -u -k all</code> and follow the reboot plan.",
|
||||
"darkTitle": "Host console goes dark after reboot and I can't SSH in",
|
||||
"darkBody": "You passed the primary GPU through before having alternate access. Boot into a recovery shell (rescue ISO, IPMI), remove the lines from the VM config (<code>/etc/pve/qemu-server/<vmid>.conf</code>), and remove the vfio options:",
|
||||
"darkBody": "A dark display does not prove the host is down. If SSH also fails, check network connectivity and whether a network/storage controller was included in the IOMMU group. Recover through IPMI, serial or a recovery environment; inspect the VM config <code>/etc/pve/qemu-server/<vmid>.conf</code> and only revert the relevant assignments and host binding rules. Do not delete unrelated blacklist or VFIO configuration.",
|
||||
"logTitle": "Check the install log",
|
||||
"logBody": "Every run writes to <code>/tmp/add_gpu_vm.log</code>. Attach it when asking for help on GitHub."
|
||||
},
|
||||
"revert": {
|
||||
"heading": "Reverting manually",
|
||||
"intro": "There isn't a dedicated \"remove GPU from VM\" shortcut in ProxMenux today. To detach cleanly:"
|
||||
"intro": "Stop the VM and remove only its relevant PCI assignments in Proxmox Hardware, or with the explicit index shown below. Detaching from the VM does not return the device to a native host driver. Use Switch GPU Mode for that separate transition and inspect the affected guests before confirming."
|
||||
},
|
||||
"related": {
|
||||
"heading": "Related",
|
||||
@@ -156,7 +156,7 @@
|
||||
{
|
||||
"label": "Install NVIDIA Drivers (Host)",
|
||||
"href": "/docs/hardware/nvidia-host",
|
||||
"tail": " — install drivers on the host first if you also want the GPU usable from there."
|
||||
"tail": " — prepare host-driver access for cards kept native; a card bound to VFIO cannot be used by the host driver simultaneously."
|
||||
},
|
||||
{
|
||||
"label": "Add GPU to LXC",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"intro": {
|
||||
"title": "What this does",
|
||||
"body": "Adds <code>dev<N></code> entries to the LXC config (<code>/etc/pve/lxc/<ctid>.conf</code>) so the container sees <code>/dev/dri/*</code>, <code>/dev/kfd</code> or <code>/dev/nvidia*</code> — whichever applies to your GPU. Then it boots the container, detects the distro inside, and installs the matching userspace drivers (Mesa, intel-media-driver, NVIDIA runtime…) so apps like Plex, Jellyfin or Frigate actually use the GPU for transcoding. GIDs (<code>video</code>, <code>render</code>) are aligned between host and container so permissions match."
|
||||
"body": "Adds <code>dev<N></code> entries to <code>/etc/pve/lxc/<ctid>.conf</code> for applicable <code>/dev/dri/*</code>, <code>/dev/kfd</code> or <code>/dev/nvidia*</code> nodes. It starts the container and installs userspace packages for its distribution, aligning <code>video</code> and <code>render</code> groups. Application acceleration still requires compatible hardware, libraries and app configuration."
|
||||
},
|
||||
"compare": {
|
||||
"heading": "LXC sharing vs VM passthrough",
|
||||
@@ -37,12 +37,12 @@
|
||||
{
|
||||
"feature": "Reboot required?",
|
||||
"lxc": "Usually no (just restart the CT)",
|
||||
"vm": "Yes, always"
|
||||
"vm": "When host driver or IOMMU setup changes; not for every VM assignment"
|
||||
},
|
||||
{
|
||||
"feature": "Supports running any OS?",
|
||||
"feature": "Guest operating systems",
|
||||
"lxc": "Only Linux (LXC is Linux-only)",
|
||||
"vm": "Windows, macOS, any Linux"
|
||||
"vm": "Supported guest OS with a compatible GPU driver"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -53,7 +53,7 @@
|
||||
"vfio": "<strong>The GPU is NOT bound to vfio-pci.</strong> If the GPU is currently assigned to a VM via passthrough, it's invisible to the host kernel driver and the LXC can't use it. The script detects this and offers to run <switchLink>Switch GPU Mode</switchLink> for you.",
|
||||
"nvidia": "<strong>For NVIDIA only:</strong> the NVIDIA host driver must already be installed — ProxMenux needs to match the container's userspace libs to the host version. If you haven't done it yet, run <nvidiaLink>Install NVIDIA Drivers on the Host</nvidiaLink> first.",
|
||||
"nvidiaCheck": "nvidia-smi",
|
||||
"container": "<strong>An existing LXC container.</strong> The script operates on a container you already created — it doesn't create one. The container should ideally be <strong>privileged</strong> (unprivileged works but needs UID/GID mapping which the script does not configure)."
|
||||
"container": "<strong>An existing LXC container.</strong> The script does not create one. Both privilege modes are supported; a <strong>privileged</strong> container is not universally required. Device entries and the application’s numeric group permissions still need to match."
|
||||
},
|
||||
"unpriv": {
|
||||
"title": "Works on both privileged and unprivileged containers",
|
||||
@@ -66,7 +66,7 @@
|
||||
},
|
||||
"howRuns": {
|
||||
"heading": "How the script runs",
|
||||
"body": "Two phases: all the decisions upfront, then all the changes in one go. Nothing on your container is touched until you confirm."
|
||||
"body": "Select the container and GPU families, then pass the checks. Processing then stops the container and changes its configuration; there is no additional final confirmation. Optional VFIO cleanup has its own confirmation and can change the host earlier."
|
||||
},
|
||||
"walkthrough": {
|
||||
"heading": "Walking through the flow",
|
||||
@@ -78,12 +78,12 @@
|
||||
},
|
||||
"pickCt": {
|
||||
"title": "Pick an LXC container",
|
||||
"body": "You'll see a list of every LXC on the host with its ID and name. Pick the one that should get the GPU. The container can be running or stopped — the script handles both (stops it briefly during config, restarts it, and leaves it in its original state at the end).",
|
||||
"body": "Lists eligible LXC containers by ID and name; OCI containers are excluded and use OCI manager Apps for devices. A running container is stopped for configuration, started for driver installation and normally returned to its original running/stopped state.",
|
||||
"imageAlt": "Dialog listing existing LXC containers to choose from"
|
||||
},
|
||||
"selectGpu": {
|
||||
"title": "Select the GPU(s) to add",
|
||||
"body": "If more than one GPU is present, you get a checklist. You can add multiple to the same container (e.g. an Intel iGPU for Quick Sync + an AMD dGPU for ROCm). If only one GPU is detected, it's auto-selected.",
|
||||
"body": "The checklist selects detected vendor families, not an isolated PCI device. Intel/AMD add the visible DRI nodes used by the script; NVIDIA adds its available device nodes, potentially covering multiple cards. One detected family is selected automatically. Verify the resulting device list, particularly on multi-GPU hosts.",
|
||||
"imageAlt": "Checklist showing detected GPUs (Intel / AMD / NVIDIA) with vendor and PCI address"
|
||||
},
|
||||
"preflight": {
|
||||
@@ -91,14 +91,14 @@
|
||||
"imageAlt": "Dialog offering to run Switch GPU Mode when the selected GPU is still bound to vfio-pci for VM passthrough",
|
||||
"intro": "Three checks, any of which can block or redirect you:",
|
||||
"items": [
|
||||
"<strong>SR-IOV.</strong> If the selected GPU is a Virtual Function (VF) or a Physical Function with active VFs, LXC passthrough doesn't apply — the device is managed by the SR-IOV driver. Blocked.",
|
||||
"<strong>SR-IOV guard.</strong> This assistant blocks a selected VF or PF with active VFs. That is a limitation of its broad device selection, not a universal prohibition on SR-IOV with LXC; configure those devices separately.",
|
||||
"<strong>Bound to vfio-pci.</strong> If the GPU is currently held by VFIO for VM passthrough, the host kernel can't create <code>/dev/dri/*</code> or <code>/dev/nvidia*</code> nodes for it. The script offers to run <switchLink>Switch GPU Mode</switchLink> which undoes the VFIO binding; you'll likely need a reboot before re-running Add GPU to LXC.",
|
||||
"<strong>Already configured.</strong> If the container already has every dev node for the selected GPU, the script says so and exits cleanly. If it's partially configured, it continues with only the missing pieces."
|
||||
]
|
||||
},
|
||||
"applyConfig": {
|
||||
"title": "Apply the LXC config changes",
|
||||
"body1": "The script stops the container, edits <code>/etc/pve/lxc/<ctid>.conf</code>, and adds <code>dev<N></code> entries with the right GIDs for the selected GPUs. Using <code>dev:</code> entries (over the older <code>lxc.mount.entry</code> lines) is the modern Proxmox way — group permissions are set at config parse time instead of at mount time.",
|
||||
"body1": "Stops the container if running and edits <code>/etc/pve/lxc/<ctid>.conf</code>. Numbered <code>dev<N></code> entries carry the chosen group IDs. The <code>dev:</code> device mechanism replaces manual <code>lxc.mount.entry</code> rules in this assistant; inspect the resulting configuration and permissions.",
|
||||
"body2": "Example after Intel + NVIDIA on the same container:"
|
||||
},
|
||||
"installDrivers": {
|
||||
@@ -123,24 +123,24 @@
|
||||
"debianIntel": "apt-get install va-driver-all intel-opencl-icd vainfo",
|
||||
"debianNvidia": "extract host <code>.run</code> → <code>pct push</code> → run with <code>--no-kernel-modules --no-dkms</code>",
|
||||
"whyTitle": "Why the NVIDIA .run dance on Debian",
|
||||
"whyBody": "Debian / Ubuntu don't ship NVIDIA packages with a version granular enough to match the host driver byte-for-byte. The userspace libs inside the container <strong>must match the kernel module version</strong> loaded on the host, or <code>nvidia-smi</code> fails with a version mismatch. ProxMenux solves this by using the exact same <code>.run</code> installer that was used for the host — extracted, tarred, pushed into the container with <code>pct push</code>, and run with <code>--no-kernel-modules --no-dkms</code> so only the userspace is touched."
|
||||
"whyBody": "Repository packages may not match the host driver. Container libraries <strong>must match the loaded host module</strong> for NVML tools such as <code>nvidia-smi</code>. The Debian/glibc path uses the cached host-version <code>.run</code> installer, extracts and packs it on the host, transfers it with <code>pct push</code> and installs with <code>--no-kernel-modules --no-dkms</code>. Alpine and Arch use repository packages, whose versions still need checking."
|
||||
},
|
||||
"alignGids": {
|
||||
"title": "Align GIDs and restore state",
|
||||
"body1": "Device files on the host are owned by group <code>video</code> (GID 44) or <code>render</code> (GID 104). The container's distro may ship different GID numbers for those groups, which would make the GPU nodes unreachable from inside. The script rewrites <code>/etc/group</code> in the container so <code>video:44</code> and <code>render:104</code> match exactly.",
|
||||
"body2": "Finally, it restores the container to its original state — if it was stopped when you started, it gets stopped again. If it was running, it stays running."
|
||||
"body1": "Reads the host GIDs for <code>video</code> and <code>render</code>, using 44/104 only as fallbacks, then edits <code>/etc/group</code> inside the container to match. Entries such as <code>video:44</code> and <code>render:104</code> are examples, not universal IDs. Verify app membership and effective device permissions.",
|
||||
"body2": "On the normal completion path, a container that was initially stopped is stopped again; one that was running stays running. If startup or installation fails, verify its final state and the log."
|
||||
}
|
||||
},
|
||||
"vendors": {
|
||||
"heading": "Vendor-specific notes",
|
||||
"intelHeading": "Intel iGPU",
|
||||
"intelBody": "Most common path — great for Plex / Jellyfin / Frigate hardware transcoding via <em>Quick Sync</em>. The container gets <code>/dev/dri/card0</code> (legacy) and <code>/dev/dri/renderD128</code> (modern render-only node — what apps actually use). No host-side changes needed; the <code>i915</code> driver on the host already created the nodes.",
|
||||
"intelBody": "Intel media acceleration, including <em>Quick Sync</em>, depends on GPU generation, codecs and app configuration. The script shares existing nodes such as <code>/dev/dri/card0</code> and <code>/dev/dri/renderD128</code>; numbering can differ. The host must already provide them through its native driver, for example <code>i915</code>.",
|
||||
"amdHeading": "AMD",
|
||||
"amdBody": "Same DRI nodes as Intel for graphics / VA-API. If <code>/dev/kfd</code> exists on the host (AMD compute / ROCm kernel support), the script also adds it so containers can do OpenCL / ROCm workloads. Mesa VA drivers cover the video decode side.",
|
||||
"amdBody": "AMD uses DRI nodes for Mesa/VA-API. If the host exposes <code>/dev/kfd</code>, the script also shares it. ROCm/OpenCL workloads still require supported hardware and compatible userspace packages; sharing the device does not install a complete ROCm stack.",
|
||||
"nvidiaHeading": "NVIDIA",
|
||||
"nvidiaBody": "Adds every <code>/dev/nvidia*</code> node the host exposes. The critical piece is <strong>driver-version matching</strong>: host module version and container userspace lib version must be identical, otherwise <code>nvidia-smi</code> inside the container fails. ProxMenux captures the host version at detection time and uses the same <code>.run</code> file to install the container userspace. For Debian containers the install bumps container memory to 2 GB temporarily (installer needs ~1.5 GB free to extract) and restores it afterwards.",
|
||||
"updateTitle": "After you update the host NVIDIA driver, re-run this script",
|
||||
"updateBody": "When you upgrade the NVIDIA driver on the host, the container's userspace libs stay on the old version and <code>nvidia-smi</code> inside the container breaks. ProxMenux's <nvidiaLink>NVIDIA host installer</nvidiaLink> detects containers with NVIDIA passthrough and offers to update them automatically — but if you skipped that prompt, just run Add GPU to LXC again on the same container and it'll refresh the userspace."
|
||||
"nvidiaBody": "Shares available <code>/dev/nvidia*</code> nodes. <strong>Driver-version matching</strong> remains essential for <code>nvidia-smi</code>. Debian/glibc uses the cached host-version <code>.run</code>; Alpine/Arch use repository packages. If the Debian path finds less than 2048 MiB configured RAM, it offers a temporary increase and later restores it; it also requires at least 1500 MiB of free disk space.",
|
||||
"updateTitle": "After a host NVIDIA update, check container library versions",
|
||||
"updateBody": "Old container libraries can make <code>nvidia-smi</code> report a mismatch. The <nvidiaLink>NVIDIA host installer</nvidiaLink> offers container updates. Re-running Add GPU to LXC may exit when its device entries already exist, so it is not a guaranteed library-refresh command. Check the installed versions and update the appropriate container packages or userspace installer."
|
||||
},
|
||||
"verification": {
|
||||
"heading": "Verification",
|
||||
@@ -149,11 +149,11 @@
|
||||
"troubleshoot": {
|
||||
"heading": "Troubleshooting",
|
||||
"mismatchTitle": "nvidia-smi: Failed to initialize NVML: Driver/library version mismatch",
|
||||
"mismatchBody": "Container userspace version ≠ host module version. Run Add GPU to LXC again on that container — the script extracts the current host <code>.run</code> and re-installs userspace matching.",
|
||||
"mismatchBody": "Container libraries do not match the loaded host module. Inspect versions and update the container userspace appropriately. The cached <code>.run</code> supports the Debian/glibc path, but Add GPU to LXC can exit early when all device entries already exist.",
|
||||
"denyTitle": "Permission denied on /dev/dri/renderD128 inside the container",
|
||||
"denyBody": "Usually one of: (1) container is unprivileged without UID/GID mapping to host <code>render</code> group; (2) the user inside the container isn't in the <code>render</code> group. Fix: add the user to <code>render</code> inside the container (<code>usermod -aG render <user></code>), or switch to privileged mode if the workload is trusted.",
|
||||
"denyBody": "Check the device entry and numeric <code>render</code> group permissions, then whether the app user belongs to <code>render</code>. Where available, add that user to <code>render</code> with <code>usermod -aG render <user></code>, replacing the placeholder with the actual account. Restart the application session to apply membership; changing privilege mode is not a general permissions fix.",
|
||||
"vainfoTitle": "vainfo says: VA-API version 1.xx; failed to initialize",
|
||||
"vainfoBody": "The VA-API runtime is there but no suitable driver was installed. On Intel, install <code>intel-media-driver</code> (newer gens) or <code>i965-va-driver</code> (older gens). On AMD, <code>mesa-va-drivers</code>. Re-run the script if in doubt.",
|
||||
"vainfoBody": "Check device access and the selected VA-API driver. Package names vary by distribution: examples include <code>intel-media-driver</code> for supported newer Intel GPUs, <code>i965-va-driver</code> for supported older ones, and <code>mesa-va-drivers</code> for AMD. The message alone does not prove a missing package.",
|
||||
"logTitle": "Install log",
|
||||
"logBody": "Every run writes to <code>/tmp/add_gpu_lxc.log</code> on the host. Include it when asking for help on GitHub."
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"intro": {
|
||||
"title": "What this does",
|
||||
"body": "The Coral installer is <strong>unified and hardware-aware</strong>: you run one menu option and it figures out what you actually have. M.2 / Mini-PCIe cards need kernel modules (<code>gasket</code> + <code>apex</code>) built with DKMS so they survive kernel upgrades. USB Accelerators just need the Google Edge TPU runtime (<code>libedgetpu1-std</code>) from Google's own APT repository. Both types plugged in? Both paths run in sequence."
|
||||
"body": "A <strong>single hardware-aware installer</strong> selects the detected device paths. PCIe uses <code>gasket</code> and <code>apex</code> modules with DKMS; future rebuilds still need compatible driver sources and kernel headers. USB uses the <code>libedgetpu1-std</code> userspace runtime. If both types are detected, both paths run. USB runtime must be available where the app runs; a host runtime is not inherently required for an app running only inside LXC."
|
||||
},
|
||||
"which": {
|
||||
"heading": "Which Coral do I have?",
|
||||
@@ -20,7 +20,7 @@
|
||||
"headerInstall": "Install type",
|
||||
"headerReboot": "Reboot?",
|
||||
"pcieForm": "M.2 / Mini-PCIe",
|
||||
"pcieFormSub": "(dual-edge TPU on an M.2 card)",
|
||||
"pcieFormSub": "(M.2 cards include single- and dual-Edge-TPU variants)",
|
||||
"pcieDetect": "PCI vendor <code>1ac1</code>",
|
||||
"pcieInstall": "Kernel module (gasket + apex) via DKMS",
|
||||
"pcieReboot": "Yes",
|
||||
@@ -32,15 +32,15 @@
|
||||
},
|
||||
"prereqs": {
|
||||
"title": "Before you start",
|
||||
"coral": "<strong>A Coral TPU plugged into the host</strong> (M.2, Mini-PCIe or USB). No Coral means no install — the script just tells you nothing was detected and exits.",
|
||||
"coral": "<strong>A connected Coral TPU</strong> (M.2, Mini-PCIe or USB) is required for installation. Without detected hardware, the script can still offer cleanup or removal of an existing installation; it will not install a new hardware path.",
|
||||
"coralCheck": "lspci -d 1ac1: ; lsusb | grep -E '1a6e:089a|18d1:9302'",
|
||||
"internet": "<strong>Internet access</strong> on the host — for PCIe the DKMS path clones a GitHub repo, for USB it adds a Google APT repo and downloads the <code>libedgetpu1-std</code> package.",
|
||||
"headers": "<strong>Kernel headers available via APT</strong>. On Proxmox this means <code>proxmox-headers-$(uname -r)</code> must be installable — needed only for the PCIe/M.2 path, but the script fetches it automatically so you don't have to.",
|
||||
"reboot": "<strong>Be OK with a reboot</strong> if you have PCIe hardware. The kernel module is built and loaded at the end, but a fresh boot is the clean way to confirm it comes up on its own."
|
||||
"reboot": "<strong>Plan a reboot</strong> for PCIe hardware. The script attempts to load the built modules; a planned restart also verifies that they load automatically."
|
||||
},
|
||||
"hostPrepTip": {
|
||||
"title": "This only prepares the host",
|
||||
"body": "Installing Coral here makes the host <em>ready</em> — the TPU is visible to the host kernel and can be handed to an LXC. To actually <em>use</em> it from a container (Frigate, DeepStack, etc.), the next step is <lxcLink>Add Coral TPU to an LXC</lxcLink>."
|
||||
"body": "This prepares the host for <em>device access</em>; it does not configure or test an application. To <em>use</em> Coral in a compatible container application such as Frigate, continue with <lxcLink>Add Coral TPU to an LXC</lxcLink>."
|
||||
},
|
||||
"running": {
|
||||
"heading": "Running the installer",
|
||||
@@ -60,28 +60,28 @@
|
||||
"<code>1a6e:089a</code> — Global Unichip, <em>unprogrammed</em> state (before the Edge TPU runtime talks to it the first time).",
|
||||
"<code>18d1:9302</code> — Google, <em>programmed</em> state (after the runtime loads firmware onto it)."
|
||||
],
|
||||
"outro": "If neither is found, you get an informative dialog and the script exits cleanly — no partial changes on the host."
|
||||
"outro": "If no Coral is detected and no installation exists, the script exits with an explanatory dialog. Existing components can still trigger the cleanup or removal menu."
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Pre-install prompt",
|
||||
"body": "Before touching anything, a single dialog summarises what was detected and what will be installed. You can cancel here without any side effects.",
|
||||
"body": "Before the installation steps, a dialog lists detected devices and the planned components. Cancel to skip installation. Optional legacy cleanup has its own earlier confirmation.",
|
||||
"imageAlt": "Pre-install dialog showing detected Coral hardware (M.2/PCIe count + USB count) and the list of steps the installer will run"
|
||||
},
|
||||
"pcie": {
|
||||
"title": "PCIe path — gasket + apex kernel modules via DKMS",
|
||||
"body": "Only runs if the script found a PCIe / M.2 Coral. It's the heavier of the two paths because it's compiling a kernel module for your exact running kernel.",
|
||||
"items": [
|
||||
"<strong>Cleanup.</strong> If a previous <code>gasket-dkms</code> install left dpkg in a broken state (typical after a PVE 9 kernel upgrade where DKMS autoinstall failed silently), force-purge it.",
|
||||
"<strong>Cleanup.</strong> If a previous <code>gasket-dkms</code> installation left a broken package state, the script attempts to purge it before rebuilding.",
|
||||
"<strong>Install build deps:</strong> <code>git</code>, <code>dkms</code>, <code>build-essential</code>, <code>proxmox-headers-$(uname -r)</code>."
|
||||
],
|
||||
"cloneIntro": "<strong>Clone the driver source.</strong> Prefers the <feranickLink>feranick/gasket-driver</feranickLink> community fork (actively maintained, kernel 6.12+ ready). Falls back to <googleLink>google/gasket-driver</googleLink> if feranick is unreachable, applying kernel-specific patches:",
|
||||
"cloneIntro": "<strong>Clone the driver source.</strong> Prefers <feranickLink>feranick/gasket-driver</feranickLink>, falling back to <googleLink>google/gasket-driver</googleLink> if unavailable. A successful build still depends on kernel compatibility. The Google fallback receives these version-dependent patches:",
|
||||
"kernelPatches": [
|
||||
"Kernel 6.5+ : <code>no_llseek</code> removed upstream → <code>noop_llseek</code> substitution",
|
||||
"For kernel 6.5+, the fallback patch replaces <code>no_llseek</code> with <code>noop_llseek</code>.",
|
||||
"Kernel 6.13+ : <code>MODULE_IMPORT_NS(DMA_BUF)</code> requires string literal"
|
||||
],
|
||||
"afterItems": [
|
||||
"<strong>Stage sources under <code>/usr/src/gasket-1.0/</code>,</strong> generate <code>dkms.conf</code>, register with <code>dkms add</code>.",
|
||||
"<strong>Build + install:</strong> <code>dkms build</code> then <code>dkms install</code>. If anything fails, the last 50 lines of <code>make.log</code> print to the terminal so you see the real error — no hunting in log files.",
|
||||
"<strong>Build and install:</strong> <code>dkms build</code> followed by <code>dkms install</code>. On failure, the script displays the last 50 lines of <code>make.log</code> if that file is available.",
|
||||
"<strong>Create the <code>apex</code> group + udev rules</strong> (<code>/etc/udev/rules.d/99-coral-apex.rules</code>) so <code>/dev/apex_*</code> nodes get the right group on the next boot.",
|
||||
"<strong>Load the modules:</strong> <code>modprobe gasket</code> + <code>modprobe apex</code>."
|
||||
],
|
||||
@@ -92,16 +92,16 @@
|
||||
"body": "Only runs if a USB Accelerator was detected. Much simpler:",
|
||||
"items": [
|
||||
"<strong>Add Google's GPG key</strong> to <code>/etc/apt/keyrings/coral-edgetpu.gpg</code>.",
|
||||
"<strong>Add the APT repository</strong> to <code>/etc/apt/sources.list.d/coral-edgetpu.list</code> with <code>signed-by=</code> pointing at the keyring (modern, non-deprecated format).",
|
||||
"<strong>Add the APT repository</strong> in <code>/etc/apt/sources.list.d/coral-edgetpu.list</code>, with <code>signed-by=</code> restricting verification to its keyring. This is one-line .list syntax, not deb822 .sources syntax.",
|
||||
"<strong>Install <code>libedgetpu1-std</code></strong> — the standard-performance Edge TPU runtime.",
|
||||
"<strong>Reload udev</strong> so the rules shipped with the package apply to the USB device without having to unplug/replug."
|
||||
],
|
||||
"stdTitle": "Why libedgetpu1-std and not libedgetpu1-max?",
|
||||
"stdBody": "The <code>max</code> variant overclocks the Coral and runs hotter. Fine for desktop use with airflow; not recommended inside small NUC / Mini-PC builds or passively cooled Proxmox hosts. If you really want it, install by hand afterwards: <code>apt install libedgetpu1-max</code>."
|
||||
"stdBody": "The <code>max</code> package enables the maximum supported clock frequency, increasing performance, power use and heat compared with the standard runtime. Check the accelerator’s cooling and operating conditions before switching. The packages are mutually exclusive; install the alternative with <code>apt install libedgetpu1-max</code>."
|
||||
},
|
||||
"reboot": {
|
||||
"title": "Reboot prompt (only if PCIe ran)",
|
||||
"body": "If the PCIe path ran, the script offers a reboot. The modules were <code>modprobe</code>'d already so in theory you can skip the reboot — but a clean boot is the right way to verify the module comes up on its own and <code>/dev/apex_0</code> appears with group <code>apex</code>. For USB-only installs, no reboot is suggested (the runtime and udev rules are active immediately).",
|
||||
"body": "After the PCIe path, the script offers a reboot. It has attempted <code>modprobe</code>, but verify that the modules load and <code>/dev/apex_0</code> appears with group <code>apex</code>. A planned reboot also checks automatic loading. USB-only installation does not prompt for a host reboot.",
|
||||
"imageAlt": "Final summary + reboot prompt after a PCIe install"
|
||||
}
|
||||
},
|
||||
@@ -125,18 +125,18 @@
|
||||
"reinstallHeading": "Reinstall / update",
|
||||
"reinstallBody": "Continues with the normal install flow — useful after a kernel upgrade if the DKMS rebuild didn't happen automatically, or to lift the runtime to a newer <code>libedgetpu1-*</code> from the Google Coral apt repo. The previous DKMS state is cleaned up first so a half-installed package from a failed earlier attempt doesn't block the new build.",
|
||||
"uninstallHeading": "Uninstall — what gets removed",
|
||||
"uninstallIntro": "Confirms with a yes/no dialog before doing anything (LXC containers with apex passthrough will lose access to <code>/dev/apex_*</code> after the next reboot — the warning makes that clear). Then it performs a full, idempotent rollback:",
|
||||
"uninstallIntro": "Requires confirmation before removal. LXC applications using <code>/dev/apex_*</code> may lose access during removal or after the next reboot. The removal sequence is:",
|
||||
"uninstallItems": [
|
||||
"Unloads the <code>apex</code> and <code>gasket</code> kernel modules.",
|
||||
"Attempts to unload <code>apex</code> and <code>gasket</code>; active users can prevent module removal.",
|
||||
"Removes every DKMS-registered <code>gasket/<version></code> entry so the modules don't come back on the next kernel install.",
|
||||
"Purges the <code>gasket-dkms</code>, <code>libedgetpu1-std</code> and <code>libedgetpu1-max</code> apt packages, then runs <code>apt-get autoremove --purge</code>.",
|
||||
"Deletes the udev rule <code>/etc/udev/rules.d/99-coral-apex.rules</code> ProxMenux wrote; restores the upstream <code>60-gasket-dkms.rules</code> group to its default if it's still present.",
|
||||
"Removes the <code>apex</code> system group <strong>only if no users still belong to it</strong> — if you mapped a custom user into <code>apex</code> for an LXC passthrough, the group is left in place and a warning prints the current members.",
|
||||
"Cleans the Google Coral apt repository entry and keyring (<code>/etc/apt/sources.list.d/coral-edgetpu.list</code> + <code>coral-edgetpu-archive-keyring.gpg</code>).",
|
||||
"Checks the supplementary member list of <code>apex</code>. <strong>If that list is empty</strong>, it attempts group removal; otherwise it retains <code>apex</code> and lists its members. This is not a complete check of primary-group users.",
|
||||
"Removes legacy repository entries including <code>/etc/apt/sources.list.d/coral-edgetpu.list</code> and old keyrings named <code>coral-edgetpu-archive-keyring.gpg</code>. The current keyring at /etc/apt/keyrings/coral-edgetpu.gpg is not removed by this sequence.",
|
||||
"Prompts for a reboot at the end <strong>only if the PCIe path was installed</strong> — the cleanest way to flush the kernel modules. USB-only uninstalls don't need one."
|
||||
],
|
||||
"lxcWarnTitle": "LXC containers with apex passthrough",
|
||||
"lxcWarnBody": "Uninstalling on the host invalidates the device path mapped into any LXC container configured for apex passthrough. Plan the operation during a maintenance window if Frigate / DeepStack / similar workloads depend on it."
|
||||
"lxcWarnBody": "Removing the host components can break LXC device access. Schedule maintenance if compatible applications such as Frigate depend on this Coral."
|
||||
},
|
||||
"updates": {
|
||||
"heading": "Update notifications",
|
||||
@@ -145,7 +145,7 @@
|
||||
"headerTracked": "Tracked version",
|
||||
"headerUpstream": "Upstream source",
|
||||
"pcieVariant": "PCIe / M.2",
|
||||
"pcieTracked": "<code>gasket-dkms</code> Debian version (or the DKMS-registered version if the package was force-removed)",
|
||||
"pcieTracked": "Recorded release tag from the successful installation, then a healthy <code>gasket-dkms</code> package version, with the DKMS module version as fallback. The bare DKMS version does not identify the fork’s patch level.",
|
||||
"pcieUpstream": "Latest tag of <code>feranick/gasket-driver</code> on GitHub (7-day cache, build-number comparison)",
|
||||
"usbVariant": "USB",
|
||||
"usbTracked": "<code>libedgetpu1-std</code> or <code>libedgetpu1-max</code> apt version",
|
||||
@@ -153,8 +153,8 @@
|
||||
"outro": "When a newer version is detected the Monitor fires a <code>coral_driver_update_available</code> notification on every enabled channel (Telegram, Discord, Gotify, ntfy, email, webhook). The notification points back at the same installer entry — pick <strong>Reinstall / update</strong> from the action menu above to apply it.",
|
||||
"antiTitle": "Anti-cascade by design",
|
||||
"antiBody": "One notification per variant, only when the upstream version actually changes — never on every 24h scan. If you ignore an update it doesn't re-ping you until a newer release lands.",
|
||||
"rebootTitle": "Reboot is only needed for the PCIe path",
|
||||
"rebootBody": "The gasket DKMS rebuild loads new kernel modules — that needs a reboot to be active. The USB runtime upgrade is a user-space library swap, no reboot required."
|
||||
"rebootTitle": "PCIe updates: plan a reboot",
|
||||
"rebootBody": "A rebuilt PCIe module must be loaded before it takes effect; a planned reboot also verifies automatic loading. A USB userspace-library upgrade needs no host reboot, but applications using the old library may need a restart."
|
||||
},
|
||||
"manual": {
|
||||
"heading": "Manual equivalent",
|
||||
@@ -170,13 +170,13 @@
|
||||
"troubleshoot": {
|
||||
"heading": "Troubleshooting",
|
||||
"dkmsFailTitle": "DKMS build fails after a kernel upgrade",
|
||||
"dkmsFailBody": "Most common cause on PVE 9: the running kernel bumped but <code>proxmox-headers-$(uname -r)</code> isn't installed for it yet. Check with <code>dpkg -l proxmox-headers-$(uname -r)</code>. Install the missing headers and re-run the script — ProxMenux's <code>cleanup_broken_gasket_dkms</code> step handles any leftover half-configured package state.",
|
||||
"dkmsFailBody": "Missing headers are one possible cause. Verify <code>proxmox-headers-$(uname -r)</code> with <code>dpkg -l proxmox-headers-$(uname -r)</code>. Install them if missing, then inspect the build log for source/kernel incompatibility. Re-running invokes <code>cleanup_broken_gasket_dkms</code>, but cleanup cannot guarantee compatibility with every kernel.",
|
||||
"apexMissTitle": "/dev/apex_0 missing after reboot",
|
||||
"apexMissBody": "The module isn't loaded. Try <code>modprobe apex</code> by hand. If that errors, check <code>dmesg | grep -iE \"apex|gasket\"</code> for the real failure — common culprits are kernel version mismatch (DKMS was built for a different kernel than the one you booted) or a firmware upgrade that disabled the PCIe slot the Coral is in.",
|
||||
"apexMissBody": "Check whether the PCIe device is detected and the module matches the running kernel. Try <code>modprobe apex</code> and inspect <code>dmesg | grep -iE \"apex|gasket\"</code>. Build failures, module loading or slot/firmware configuration can prevent device creation.",
|
||||
"lxcMissTitle": "Can see /dev/apex_0 but LXC can't",
|
||||
"lxcMissBody": "Host is fine. Problem is passthrough config — see <lxcLink>Add Coral TPU to an LXC</lxcLink>.",
|
||||
"lxcMissBody": "A visible host node alone does not prove the device works. Verify host access, then the LXC mount, cgroup rules and numeric user/group permissions. See <lxcLink>Add Coral TPU to an LXC</lxcLink>.",
|
||||
"usbUnreachTitle": "USB Accelerator detected but Frigate / TFLite can't reach it",
|
||||
"usbUnreachBody": "Check the udev rules shipped with <code>libedgetpu1-std</code> took effect: <code>ls -l /dev/bus/usb/*/*</code>. The device should NOT be owned by root:root with mode 0600 — if it is, run <code>udevadm control --reload-rules && udevadm trigger</code> on the host, unplug the USB Coral, wait 3 seconds and plug it back in.",
|
||||
"usbUnreachBody": "Check the rules supplied by <code>libedgetpu1-std</code> and inspect permissions with <code>ls -l /dev/bus/usb/*/*</code>. The application’s mapped user/group needs read/write access; root ownership alone is not an error. After changing rules, run <code>udevadm control --reload-rules && udevadm trigger</code> and reconnect the device if needed.",
|
||||
"logTitle": "Install log",
|
||||
"logBody": "Every run writes to <code>/tmp/coral_install.log</code> on the host. If the DKMS build dies, the script also appends the last 50 lines of <code>/var/lib/dkms/gasket/1.0/build/make.log</code> to that log — attach it when asking for help on GitHub."
|
||||
},
|
||||
@@ -196,7 +196,7 @@
|
||||
{
|
||||
"label": "ProxMenux Monitor — Hardware tab",
|
||||
"href": "/docs/monitor/dashboard/hardware",
|
||||
"tail": " — the Coral modal that surfaces driver, modules, device nodes, runtime status and live temperature once the host install is done."
|
||||
"tail": " — the Coral panel shows driver, modules, device nodes and runtime status, plus temperature when a supported sensor exposes it."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
},
|
||||
"intro": {
|
||||
"title": "What this does",
|
||||
"body": "ProxMenux automates the whole NVIDIA driver lifecycle on the host: detects your GPU, offers maintained NVIDIA branches that list its PCI Device ID, blacklists <code>nouveau</code>, downloads and runs the official NVIDIA <code>.run</code> installer with DKMS, installs the <code>nvidia-persistenced</code> service and udev rules, and offers to apply the optional NVENC patch. The DKMS build is the final compatibility check against the running kernel. If you already have LXC containers with NVIDIA passthrough, it can update their userspace libraries to match the host."
|
||||
"body": "ProxMenux detects the GPU and offers maintained NVIDIA branches listing its PCI ID. It blacklists <code>nouveau</code>, downloads the official <code>.run</code> installer, uses DKMS, installs <code>nvidia-persistenced</code> and udev rules, and offers an optional NVENC patch. Build checks assess the running kernel; successful compilation does not guarantee every app works. Existing NVIDIA LXCs can receive matching userspace libraries."
|
||||
},
|
||||
"who": {
|
||||
"heading": "Who is this for?",
|
||||
"body": "If you have an NVIDIA GPU and you want to use it for hardware-accelerated transcoding in Plex, Jellyfin, Frigate, Immich, Stable Diffusion or any other app running <strong>inside an LXC container</strong>, you need to install the driver on the Proxmox <em>host</em> first. This page covers that host-side install. Passing the GPU to a <strong>virtual machine (VM)</strong> uses a different flow (VFIO passthrough) and is documented separately."
|
||||
"body": "For GPU-accelerated video or compute apps such as Plex, Jellyfin, Frigate, Immich or Stable Diffusion <strong>inside LXC</strong>, install the supported NVIDIA driver on the Proxmox <em>host</em> first. Assigning a GPU directly to a <strong>VM</strong> uses the separate VFIO workflow."
|
||||
},
|
||||
"prereqs": {
|
||||
"title": "Before you start",
|
||||
@@ -22,11 +22,11 @@
|
||||
"gpuCheck": "lspci | grep -i nvidia",
|
||||
"notVm": "The GPU <strong>is not currently assigned to a VM via VFIO passthrough</strong>. If it is, the script will refuse to install the host driver to avoid breaking the passthrough config.",
|
||||
"internet": "Internet access on the host. The installer downloads the driver from <code>download.nvidia.com</code> and, optionally, clones <code>nvidia-persistenced</code> and <code>nvidia-patch</code> from GitHub.",
|
||||
"space": "Some free space in <code>/opt/nvidia</code> for the <code>.run</code> installer plus the RAM used during the build. When propagating to LXCs on non-Arch distros, each container needs at least 1.5 GB free; ProxMenux temporarily raises container RAM to 2 GB and restores it after. A reboot is required at the end of the host install."
|
||||
"space": "Allow disk space in <code>/opt/nvidia</code> for the <code>.run</code> installer and RAM for compilation. The non-Arch LXC update path checks for 1500 MiB free and can request a temporary increase to 2048 MiB RAM if lower, restoring the prior limit afterwards. Plan for the host reboot prompt."
|
||||
},
|
||||
"vmWarn": {
|
||||
"title": "GPU assigned to a VM? Stop here",
|
||||
"body": "If the GPU is currently bound to <code>vfio-pci</code> (i.e. it is being passed through to a VM), installing the host driver can break the passthrough and destabilise the system. ProxMenux detects this and aborts. Remove the GPU from the VM passthrough configuration and reboot before running this script."
|
||||
"body": "If any NVIDIA device is bound to <code>vfio-pci</code>, this installer aborts, including when the VM is stopped. A reserved device is not necessarily in active use by a VM. Plan the return to host-driver mode and remove obsolete VM and VFIO assignments before rebooting and installing."
|
||||
},
|
||||
"running": {
|
||||
"heading": "Running the installer",
|
||||
@@ -35,30 +35,30 @@
|
||||
},
|
||||
"howRuns": {
|
||||
"heading": "How the script runs",
|
||||
"body": "The installer goes through three phases with clear separation between \"collecting information and validating\" and \"actually touching the host\". Until the final confirmation, nothing has been changed."
|
||||
"body": "The workflow detects devices, selects a release and performs installation. A separately confirmed stale-VFIO cleanup can occur before the overview. Repository/header preparation and downloading also precede replacement of the existing driver, so there is no single final confirmation after which all changes begin."
|
||||
},
|
||||
"walkthrough": {
|
||||
"detect": {
|
||||
"title": "GPU detection and overview",
|
||||
"body1": "The script scans the PCI bus and shows every NVIDIA video controller it finds, the current driver status (or <em>\"No NVIDIA driver installed\"</em>), and any LXC container that already has NVIDIA passthrough configured (driver version inside each one).",
|
||||
"body2": "Review the overview carefully. If the detected GPU is not what you expect, or if a container's version already matches the host, you can cancel here without side effects.",
|
||||
"body2": "Review the detected GPU and host/container versions before proceeding. Cancel at the overview if the selection is unexpected; any separately confirmed earlier VFIO cleanup has already taken place.",
|
||||
"imageAlt": "Pre-install overview showing detected GPUs, current driver status and LXC containers with NVIDIA passthrough"
|
||||
},
|
||||
"version": {
|
||||
"title": "Choose the driver version",
|
||||
"body1": "ProxMenux fetches the list of available drivers from NVIDIA and narrows the picker to versions that <strong>list your GPU's PCI Device ID in the supported chips table</strong> of the corresponding branch on <code>nvidia.com</code>. Additional heuristics discard developer / beta CDN drops that would otherwise appear at the top. The first entry is labelled <em><version> — Recommended</em>: it prefers the head of the branch of the driver already installed on the host (bugfix in place), otherwise the head of the current Production Branch, otherwise the highest supported numeric.",
|
||||
"body2": "If the currently installed driver was patched via keylase (NVENC), the picker auto-narrows to versions still covered by the patch table, so applying <em>Reinstall / update</em> without losing the patch is one click.",
|
||||
"body2": "When the installed driver is tracked as NVENC-patched through keylase, the picker narrows to versions listed in the patch table. The <em>Reinstall / update</em> workflow still includes confirmation and patch prompts; check the final patch result.",
|
||||
"whyTitle": "How kernel compatibility is validated",
|
||||
"whyBody": "The version list is filtered by NVIDIA branch maintenance and GPU PCI support, not by a hard-coded kernel/driver matrix. After selection, DKMS builds the module against the running kernel. A failed build stops the installation from being treated as valid; choose another maintained branch if NVIDIA has not adapted that release to your kernel.",
|
||||
"whyBody": "The list uses maintained branches and GPU PCI support, rather than a fixed kernel/driver matrix. A pre-build check tests the selected release against the running kernel. A confirmed build failure returns to selection; an unavailable pre-check can produce a warning and continue. Final installation and runtime checks still matter.",
|
||||
"imageAlt": "Driver version selector with GPU-supported NVIDIA branches and the Recommended entry on top"
|
||||
},
|
||||
"uninstall": {
|
||||
"title": "Clean uninstall (only if reinstalling)",
|
||||
"body": "If a driver is already present and you picked a different version, ProxMenux stops the NVIDIA services, unloads the kernel modules, removes DKMS entries and purges <code>nvidia-*</code> / <code>libnvidia-*</code> / <code>cuda-*</code> packages before touching the new installer. This avoids the classic mixed-version mess."
|
||||
"body": "After downloading and checking the selected installer, an existing driver is removed before replacement. ProxMenux stops NVIDIA services, unloads modules, removes DKMS entries and purges <code>nvidia-*</code> / <code>libnvidia-*</code> / <code>cuda-*</code> packages. This also applies to a confirmed reinstall of the same version."
|
||||
},
|
||||
"prepare": {
|
||||
"title": "Prepare the system",
|
||||
"body": "Behind a single confirmation, the script:",
|
||||
"body": "During preparation, the script:",
|
||||
"items": [
|
||||
"Checks the repositories of the host before anything is removed or installed: a host with no active subscription and only the Enterprise repository is asked before switching to no-subscription, and the installation stops when the switch is declined.",
|
||||
"Installs <code>pve-headers-$(uname -r)</code> (or <code>proxmox-headers-$(uname -r)</code>), <code>build-essential</code> and <code>dkms</code>.",
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"download": {
|
||||
"title": "Download and run the NVIDIA installer",
|
||||
"body": "The installer downloads the <code>NVIDIA-Linux-x86_64-<version>.run</code> file into <code>/opt/nvidia</code>, validates it (size + executable signature, not just HTTP 200), then runs it with DKMS so the kernel module rebuilds automatically across kernel upgrades.",
|
||||
"body": "Downloads <code>NVIDIA-Linux-x86_64-<version>.run</code> into <code>/opt/nvidia</code>, checking file size and executable type. These are file-format checks, not cryptographic signature verification. The installer registers DKMS for rebuilds on kernel changes; source and kernel compatibility are still required.",
|
||||
"imageAlt": "Download progress followed by the NVIDIA installer running its DKMS build"
|
||||
},
|
||||
"persist": {
|
||||
@@ -77,39 +77,39 @@
|
||||
},
|
||||
"nvenc": {
|
||||
"title": "Optional: apply the NVENC patch",
|
||||
"body": "Consumer NVIDIA GPUs (GeForce line) limit the number of simultaneous NVENC encoding sessions. The community <patchLink>keylase/nvidia-patch</patchLink> removes that restriction. If you plan to use the GPU for Plex / Jellyfin / Frigate with many concurrent streams, answer <strong>Yes</strong> when prompted.",
|
||||
"body": "NVENC session limits depend on GPU and driver. The community <patchLink>keylase/nvidia-patch</patchLink> can remove the driver session limit for supported versions. Choose <strong>Yes</strong> only if you need that encoding change and your version is supported. This does not accelerate decoding or remove hardware capacity limits.",
|
||||
"supportTitle": "Check patch support for your driver",
|
||||
"supportBody": "The patch does not cover every driver version. Before relying on it in production, verify your version is listed in the <patchTableLink>patch table</patchTableLink>. If it isn't supported yet, pick a nearby older driver that is."
|
||||
"supportBody": "Check your exact release in the <patchTableLink>patch table</patchTableLink>. If it is missing, keep an unpatched driver or select another maintained release that supports your GPU and kernel as well as the patch; do not choose an older release solely because it is nearby in the list."
|
||||
},
|
||||
"propagate": {
|
||||
"title": "Optional: propagate the driver to LXC containers",
|
||||
"body1": "If the overview screen listed containers with NVIDIA passthrough, ProxMenux now offers to update the userspace libraries inside each one to match the host. Host kernel module and container userspace <strong>must be the exact same version</strong> — otherwise <code>nvidia-smi</code> inside the container will fail with a \"version mismatch\" error.",
|
||||
"body2": "The update is distro-aware. For Debian / Ubuntu and other glibc distros, the same <code>.run</code> installer (with <code>--no-kernel-modules --no-dkms --no-install-compat32-libs</code>) is pushed into the container and executed; container RAM is temporarily raised to 2 GB if lower and restored after. For <strong>Arch, Manjaro and EndeavourOS</strong> the update is a <code>pacman -Syu nvidia-utils</code> pinned to the host's driver branch. <strong>Alpine</strong> uses a different path — the <code>.run</code> is extracted on the host, only the userspace libraries are packaged as a tarball and pushed with <code>pct push</code>, then <code>gcompat</code> + <code>binutils</code> shims are installed via <code>apk</code> and SONAME symlinks are recreated with <code>readelf</code> so the glibc-linked libraries load correctly on musl.",
|
||||
"body2": "Debian / Ubuntu and other glibc containers receive the extracted <code>.run</code> installer with <code>--no-kernel-modules --no-dkms --no-install-compat32-libs</code>; RAM can temporarily increase to 2 GiB and is restored afterwards. <strong>Arch, Manjaro and EndeavourOS</strong> use <code>pacman -Syu nvidia-utils</code> from configured repositories, without pinning to the host version: verify the result. <strong>Alpine</strong> receives the extracted <code>.run</code> payload through <code>pct push</code>, installs <code>gcompat</code> and <code>binutils</code> with <code>apk</code>, and builds SONAME links using <code>readelf</code>. Check runtime functionality; compatibility shims do not guarantee every driver library works on musl.",
|
||||
"imageAlt": "Prompt listing LXCs with NVIDIA passthrough and current driver version, with Yes/No to update them all"
|
||||
},
|
||||
"reboot": {
|
||||
"title": "Reboot",
|
||||
"body": "Finally, the script rebuilds <code>initramfs</code> for all kernels and offers to reboot. A reboot <strong>is required</strong>: the nouveau blacklist and the new kernel module only take effect after restart."
|
||||
"body": "Finally, the script rebuilds <code>initramfs</code> for all kernels and offers a reboot. <strong>Plan that restart</strong> to verify the persistent module and nouveau configuration on a fresh boot, even when the new driver already responds before reboot."
|
||||
}
|
||||
},
|
||||
"reinstallUninstall": {
|
||||
"heading": "Reinstall or uninstall",
|
||||
"intro": "When the installer detects that the <code>nvidia</code> kernel module is currently loaded and <code>nvidia-smi</code> returns a version, it doesn't silently re-install on top. Instead it shows an action menu so you can choose what to do. (Binaries present on disk but the module not loaded do not count as installed — the module has to be live.)",
|
||||
"intro": "If <code>nvidia</code> is loaded and <code>nvidia-smi</code> returns a version, an action menu appears. This identifies an active driver for the menu; driver files can still be installed even when the module is not loaded.",
|
||||
"imageAlt": "NVIDIA action menu offered when a driver is already installed — two choices: Reinstall / update driver, or Uninstall the NVIDIA driver completely",
|
||||
"imageCaption": "The action menu only appears when an NVIDIA driver is currently active on the host.",
|
||||
"reinstallHeading": "Reinstall / update",
|
||||
"reinstallBody": "Continues with the normal install flow but, before downloading anything, runs a clean removal of the current driver (apt purge + DKMS entries dropped + leftover modules unloaded). This is the safe path to apply a newer same-branch version, choose another maintained branch when needed, or recover from a half-broken state. The LXC propagation and NVENC patch prompts re-run at the end.",
|
||||
"reinstallBody": "Continues through release selection, repository/header preparation, download and pre-build checking before removing the old driver and installing the new one. It can update within a maintained branch or select another supported branch. LXC library and NVENC patch prompts appear again afterwards.",
|
||||
"uninstallHeading": "Uninstall — what gets removed",
|
||||
"uninstallIntro": "Confirms with a yes/no dialog first. Then performs a full, idempotent rollback:",
|
||||
"uninstallIntro": "After a yes/no confirmation, the uninstall removes the following driver components:",
|
||||
"uninstallItems": [
|
||||
"Runs <code>nvidia-uninstall --silent</code> first (the counterpart to the <code>.run</code> installer), then stops and disables <code>nvidia-persistenced</code> and <code>nvidia-powerd</code>, and unloads the kernel modules (<code>nvidia_uvm</code>, <code>nvidia_drm</code>, <code>nvidia_modeset</code>, <code>nvidia</code>) — any LXC container with NVIDIA passthrough will be cleanly cut off.",
|
||||
"First runs <code>nvidia-uninstall --silent</code> for the <code>.run</code> installation, then stops and disables <code>nvidia-persistenced</code> and <code>nvidia-powerd</code>. It attempts to unload <code>nvidia_uvm</code>, <code>nvidia_drm</code>, <code>nvidia_modeset</code> and <code>nvidia</code>. NVIDIA-dependent LXC workloads are affected; active clients can prevent unloading.",
|
||||
"Runs <code>apt purge</code> on <code>nvidia-*</code>, <code>libnvidia-*</code>, <code>cuda-*</code> and <code>libcudnn*</code>, removes the DKMS source tree and the <code>/opt/nvidia</code> .run installer cache.",
|
||||
"Removes the modules-load config (<code>/etc/modules-load.d/nvidia-vfio.conf</code>) and the nouveau blacklist entries owned by ProxMenux. Legacy two-line ProxMenux blacklist files are migrated and removed too; modified or unrelated administrator files are preserved.",
|
||||
"Removes the udev rules (<code>/etc/udev/rules.d/70-nvidia.rules</code>) and clears the NVENC patch state (a field in the ProxMenux managed-installs registry, set to <em>removed</em> — no separate file to delete).",
|
||||
"Rebuilds <code>initramfs</code> for all kernels, runs <code>proxmox-boot-tool refresh</code> on systemd-boot hosts, and prompts for a reboot to finalise."
|
||||
],
|
||||
"lxcWarnTitle": "LXC containers with NVIDIA passthrough",
|
||||
"lxcWarnBody": "Removing the host driver invalidates the device paths and CUDA libraries mapped into any LXC with NVIDIA passthrough. Plan the operation during a maintenance window if Frigate / Plex / Jellyfin / Ollama (or anything else) depends on it."
|
||||
"lxcWarnBody": "Removing the host driver interrupts NVIDIA-dependent LXC workloads, even when their userspace libraries remain installed. Schedule maintenance for Frigate, Plex, Jellyfin, Ollama or other apps that use the GPU."
|
||||
},
|
||||
"updates": {
|
||||
"heading": "Update notifications",
|
||||
@@ -121,26 +121,26 @@
|
||||
"antiTitle": "Anti-cascade by design",
|
||||
"antiBody": "One notification per distinct upstream version, never on every 24h scan. If no newer release exists in the installed branch, the tracker stays quiet.",
|
||||
"applyTitle": "Applying the update",
|
||||
"applyBody": "The Monitor doesn't auto-apply driver updates — reinstalling the NVIDIA driver always needs a reboot. Open the same installer entry described above, pick <strong>Reinstall / update</strong>, and the new version is downloaded, the DKMS module rebuilt against the running kernel, and the reboot prompted at the end."
|
||||
"applyBody": "Monitor reports updates without installing them automatically. Open the installer and choose <strong>Reinstall / update</strong>, select a supported version, and complete its build and installation steps. The workflow ends with a reboot prompt; plan the restart and verify the host and LXC libraries afterwards."
|
||||
},
|
||||
"verify": {
|
||||
"heading": "Verifying the install",
|
||||
"intro": "Once the host is back up, log in over SSH or the Proxmox shell and run:",
|
||||
"after": "You should see your GPU listed, the driver version on the top border, and no processes yet (nothing is using the GPU at this point). Then check the persistence service:",
|
||||
"after": "Check that your GPU and the expected driver version appear. Processes may already be listed if host services or autostarted containers use the GPU. Then check the persistence service:",
|
||||
"imageAlt": "Output of nvidia-smi on the host showing the detected GPU and installed driver version"
|
||||
},
|
||||
"troubleshoot": {
|
||||
"heading": "Troubleshooting",
|
||||
"smiFailTitle": "`nvidia-smi` says 'NVIDIA-SMI has failed'",
|
||||
"smiFailBody": "Almost always a <strong>nouveau</strong> still loaded or a <strong>kernel header mismatch</strong>. After reboot, run <code>lsmod | grep nouveau</code> — if it returns anything, check <code>/etc/modprobe.d/proxmenux-nouveau-blacklist.conf</code>, rebuild initramfs with <code>update-initramfs -u -k all</code>, and reboot. If nouveau is gone, check <code>dmesg | grep -i nvidia</code> — DKMS build errors usually mean the headers do not match the running kernel.",
|
||||
"smiFailBody": "Possible causes include <strong>nouveau</strong> claiming the GPU, <strong>missing or mismatched kernel headers</strong>, incompatible driver sources or other module-load errors. Inspect <code>lsmod | grep nouveau</code> and <code>dmesg | grep -i nvidia</code>, plus the installer/DKMS logs. If nouveau policy needs fixing, check <code>/etc/modprobe.d/proxmenux-nouveau-blacklist.conf</code> before rebuilding with <code>update-initramfs -u -k all</code> and rebooting. Do not assume every build error is a header mismatch.",
|
||||
"lxcMissTitle": "LXC container can't see the GPU after host update",
|
||||
"lxcMissBody": "The container's userspace libraries are stuck at the previous driver version. Either re-run the NVIDIA installer and accept the LXC propagation prompt, or install the same driver version manually inside the container with <code>--no-kernel-modules</code>.",
|
||||
"lxcMissBody": "Check host device nodes, LXC permissions and the driver-library version before reinstalling. A version mismatch can require the matching userspace driver inside the LXC, using the supported distro path; on glibc systems the installer uses <code>--no-kernel-modules</code>. Reinstalling libraries will not repair missing device mounts or permissions.",
|
||||
"logTitle": "Check the install log",
|
||||
"logBody": "Every install writes to <code>/tmp/nvidia_install.log</code>. If something fails silently, that file has the full output (downloads, DKMS build, service installs). Attach it when reporting issues on GitHub."
|
||||
},
|
||||
"manualSteps": {
|
||||
"heading": "Looking for the manual steps?",
|
||||
"body": "The original community guide — installing everything by hand with <code>wget</code> and <code>./NVIDIA-Linux-...run</code> — is still available as a reference under <guideLink>Guides → NVIDIA</guideLink>. It's useful if you want to understand every command the ProxMenux installer runs, or if you're troubleshooting an unusual setup. For day-to-day installs, use ProxMenux — it's the path that keeps receiving fixes (kernel compatibility, LXC propagation, VFIO safety checks)."
|
||||
"body": "See <guideLink>Guides → NVIDIA</guideLink> for manual background, including <code>wget</code> and <code>./NVIDIA-Linux-...run</code>. It explains the components but is not an exact transcript of the automated installer. Use the maintained ProxMenux workflow for its GPU filtering, build checks, LXC updates and VFIO checks."
|
||||
},
|
||||
"related": {
|
||||
"heading": "Related",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
},
|
||||
"header": {
|
||||
"title": "Switch GPU Mode (VM ↔ LXC)",
|
||||
"description": "Reassign a GPU that's already in use — flip it from VM passthrough to LXC sharing or the other way round. ProxMenux handles all the host-side binding changes (vfio.conf, driver blacklist, modules, initramfs) and offers a clean policy for every VM or LXC currently using the GPU, so the switch doesn't leave broken config behind.",
|
||||
"description": "Move an assigned GPU between VM passthrough and LXC sharing. ProxMenux manages the host driver binding, VFIO configuration, module settings and initramfs, and asks how to handle affected guests. Review those choices and verify the resulting configuration after reboot.",
|
||||
"section": "Hardware: GPUs and Coral-TPU"
|
||||
},
|
||||
"intro": {
|
||||
@@ -42,21 +42,21 @@
|
||||
},
|
||||
{
|
||||
"situation": "I just want to completely unbind a GPU from everything.",
|
||||
"use": "Yes — pick the LXC-mode target and then detach manually."
|
||||
"use": "LXC mode restores host-driver ownership; removing guest assignments still needs the relevant conflict-policy choices. This does not leave the GPU unbound from every driver."
|
||||
}
|
||||
]
|
||||
},
|
||||
"prereqs": {
|
||||
"title": "Before you start",
|
||||
"assigned": "<strong>A GPU already assigned</strong> — either in a VM via VFIO or attached to at least one LXC. If you haven't assigned it yet, start from Add GPU to VM / LXC instead.",
|
||||
"iommu": "<strong>IOMMU enabled on the host</strong> — only strictly required when switching <em>to</em> VM mode, but worth having on either way. If the kernel param is missing the script auto-adds <code>intel_iommu=on iommu=pt</code> or <code>amd_iommu=on</code> to the boot command line (via <code>proxmox-boot-tool refresh</code> on systemd-boot or <code>update-grub</code> on GRUB) and includes it in the reboot prompt at the end.",
|
||||
"iommu": "<strong>IOMMU must be active on the host</strong> when switching <em>to</em> VM mode. Firmware settings and kernel support both matter; explicit arguments are not always necessary. If needed, the script attempts <code>intel_iommu=on iommu=pt</code> or <code>amd_iommu=on</code> using the active boot setup, with <code>proxmox-boot-tool refresh</code> or <code>update-grub</code>. Check any warnings and reboot when prompted.",
|
||||
"iommuCheck": "dmesg | grep -i 'IOMMU enabled' | head -1",
|
||||
"reboot": "<strong>Be OK with a reboot.</strong> Switching GPU bindings at the kernel level means the host regenerates initramfs and you reboot to apply. The script prompts at the end.",
|
||||
"reboot": "<strong>Plan for a reboot.</strong> Persistent driver and boot changes may require rebuilding initramfs and rebooting. The script presents a reboot prompt at the end.",
|
||||
"knowList": "<strong>Know which VMs / LXCs are using the GPU.</strong> The script will find them and ask what to do with each, but it's faster if you already know the list."
|
||||
},
|
||||
"blocklist": {
|
||||
"title": "Not all GPUs are safe to pass to a VM",
|
||||
"body": "A small blocklist of GPU IDs is refused for VM mode due to known passthrough instability (e.g. Intel Arc A770 <code>8086:5a84</code> / <code>8086:5a85</code>). If the selected GPU matches, the script explains why and exits. Switching <em>to</em> LXC mode is always allowed."
|
||||
"body": "The script blocks VM mode for certain device IDs, including <code>8086:5a84</code> and <code>8086:5a85</code>, under its compatibility policy. If a selected GPU matches, it displays a warning. This blocklist does not prevent switching <em>to</em> LXC mode; other checks can still apply."
|
||||
},
|
||||
"running": {
|
||||
"heading": "Running the script",
|
||||
@@ -65,7 +65,7 @@
|
||||
},
|
||||
"howRuns": {
|
||||
"heading": "How the script runs",
|
||||
"body": "Two phases as usual: everything is collected and validated first, nothing is applied until you confirm at the end."
|
||||
"body": "GPU selection and direction are reviewed before the main switch. A separate stale-VFIO cleanup can ask for confirmation earlier, and affected guests have their own conflict prompts. Read each confirmation: there is not one final confirmation covering every possible change."
|
||||
},
|
||||
"walkthrough": {
|
||||
"heading": "Walking through the flow",
|
||||
@@ -85,27 +85,27 @@
|
||||
"intro": "Based on the current mode, the script proposes the opposite as target:",
|
||||
"items": [
|
||||
"<strong>VM → LXC:</strong> unbind from <code>vfio-pci</code>, let the native driver (<code>nvidia</code>, <code>amdgpu</code>, <code>i915</code>) reclaim the card so LXCs can share it. On NVIDIA, the per-BDF entry is removed from <code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> so the nvidia module reclaims the GPU after reboot.",
|
||||
"<strong>LXC → VM:</strong> bind to <code>vfio-pci</code> so the card is free for VFIO passthrough to a single VM. On AMD / Intel this means blacklisting the native driver and setting <code>options vfio-pci ids=…</code>. On NVIDIA the <code>nvidia</code> module is <strong>not</strong> blacklisted — instead a per-BDF udev rule applies <code>driver_override=vfio-pci</code> only to the GPUs you select, so other NVIDIA GPUs on the host keep their <code>nvidia</code> driver."
|
||||
"<strong>LXC → VM:</strong> prepares <code>vfio-pci</code> ownership. AMD / Intel use native-driver blacklisting and <code>options vfio-pci ids=…</code>. For NVIDIA, <code>nvidia</code> is <strong>not</strong> globally blacklisted: per-BDF rules set <code>driver_override=vfio-pci</code> for the affected IOMMU-group devices. NVIDIA GPUs outside those groups can retain <code>nvidia</code>. Review every group member before switching."
|
||||
],
|
||||
"outro": "Confirm the direction or cancel."
|
||||
},
|
||||
"conflict": {
|
||||
"title": "Conflict policy per affected workload",
|
||||
"body": "The script scans every <code>/etc/pve/lxc/*.conf</code> and <code>/etc/pve/qemu-server/*.conf</code> looking for references to the GPU's PCI slot. For each affected workload you pick a policy:",
|
||||
"body": "The script checks <code>/etc/pve/lxc/*.conf</code> for GPU-device references by driver family, and <code>/etc/pve/qemu-server/*.conf</code> for PCI assignments. LXC detection is not a precise per-card BDF match. Review the detected guests and choose how to handle each:",
|
||||
"headerPolicy": "Policy",
|
||||
"headerEffect": "Effect",
|
||||
"headerWhen": "When to pick",
|
||||
"keepPolicy": "Keep config, disable onboot",
|
||||
"keepEffect": "<code>pct set -onboot 0</code> (or <code>qm set</code>). GPU lines stay in the config.",
|
||||
"keepEffect": "<code>pct set CTID -onboot 0</code> (or <code>qm set VMID -onboot 0</code>). GPU entries stay in the configuration.",
|
||||
"keepWhen": "You plan to come back to this VM/LXC once the GPU is back in its original mode. Safe default.",
|
||||
"removePolicy": "Remove GPU from config",
|
||||
"removeEffect": "<code>hostpci</code> / <code>dev</code> lines for this GPU's slot are sed'd out.",
|
||||
"removeWhen": "The VM/LXC will keep running without the GPU (CPU-only transcoding, etc.). Clean workflow.",
|
||||
"removeEffect": "Removes identified <code>hostpci</code> / <code>dev</code> entries and supported legacy device references.",
|
||||
"removeWhen": "Choose this if the guest should operate without the GPU. Check its application settings first: CPU fallback is application-dependent, and removing the device does not automatically reconfigure the app.",
|
||||
"imageAlt": "Dialog asking per-VM / per-LXC conflict policy when switching a GPU that's currently assigned"
|
||||
},
|
||||
"audio": {
|
||||
"title": "Orphan audio cleanup (only when leaving VM mode)",
|
||||
"body1": "dGPUs (NVIDIA / AMD) ship with an HDMI audio function at <code>.1</code> of the same slot, and sometimes extra audio controllers are attached alongside the GPU. When the GPU leaves the VM, those audio lines become orphans — the VM has <code>hostpci</code> entries pointing to audio devices that aren't going with the GPU.",
|
||||
"body1": "Many dedicated NVIDIA / AMD GPUs expose HDMI audio at function <code>.1</code> of the same slot; additional audio devices may also have been assigned. Removing the GPU can leave obsolete <code>hostpci</code> audio entries in the VM. Review which devices should remain assigned.",
|
||||
"body2": "The script discovers them (precise BDF match, no substring false-positives) and shows a checklist so you can remove them cleanly. It also cleans their vendor:device IDs from <code>/etc/modprobe.d/vfio.conf</code> — but only if no other VM still uses those audio IDs."
|
||||
},
|
||||
"apply": {
|
||||
@@ -119,9 +119,9 @@
|
||||
}
|
||||
},
|
||||
"manual": {
|
||||
"heading": "Manual equivalent",
|
||||
"intro": "If you want to understand exactly what the script does (or troubleshoot one of the steps by hand), these are the raw operations for <strong>VM → LXC</strong> on an NVIDIA card with vendor:device <code>10de:2204</code>:",
|
||||
"lxcToVm": "And for <strong>LXC → VM</strong>:",
|
||||
"heading": "Manual inspection",
|
||||
"intro": "Before a <strong>VM → LXC</strong> switch, inspect the driver and existing per-BDF policy. This NVIDIA example uses vendor:device <code>10de:2204</code>; adapt it to your card. These commands inspect state; the script also manages affected guests and IOMMU-group members.",
|
||||
"lxcToVm": "Before <strong>LXC → VM</strong>, inspect the selected PCI address and its IOMMU group. Replace the example address with yours and review all group members before assigning devices.",
|
||||
"oneVmTitle": "Only one VM can use a given vfio-pci GPU at a time",
|
||||
"oneVmBody": "Putting multiple <code>hostpci</code> entries with the same PCI slot in two VMs is valid config but only one of the VMs can start with the GPU — the second one will fail. The ProxMenux conflict policy step is exactly about avoiding this trap."
|
||||
},
|
||||
@@ -131,11 +131,11 @@
|
||||
"troubleshoot": {
|
||||
"heading": "Troubleshooting",
|
||||
"stillVfioTitle": "GPU still shows vfio-pci after switching to LXC mode",
|
||||
"stillVfioBody": "<code>update-initramfs</code> didn't run (or the reboot didn't actually happen). Check <code>lsmod | grep vfio</code> — if vfio-pci is loaded, rerun <code>update-initramfs -u -k all</code> and reboot. For AMD/Intel: verify <code>vfio.conf</code> no longer contains the GPU's vendor:device ID. For NVIDIA: verify the BDF is no longer in <code>/etc/proxmenux/vfio-bind.bdfs</code> and that <code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> doesn't list it.",
|
||||
"stillVfioBody": "A loaded VFIO module does not prove which driver owns this GPU. Check the card binding and whether <code>update-initramfs</code> and the reboot completed. <code>lsmod | grep vfio</code> only lists modules. For AMD / Intel inspect <code>vfio.conf</code>; for NVIDIA inspect <code>/etc/proxmenux/vfio-bind.bdfs</code> and <code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code>. Correct stale policy before running <code>update-initramfs -u -k all</code> and rebooting.",
|
||||
"vmFailTitle": "A VM won't start after switching a GPU to LXC mode",
|
||||
"vmFailBody": "The VM still has <code>hostpci</code> entries pointing to a GPU it can't claim. Run the script again and pick the <em>Remove GPU from config</em> policy, or clean the config by hand:",
|
||||
"vmFailBody": "Check whether the VM still has obsolete <code>hostpci</code> references. The <em>Remove GPU from config</em> policy can remove them during the intended switch; inspect the proposed direction before rerunning the script so you do not reverse the mode unintentionally. Alternatively, remove the obsolete assignment in Proxmox with the VM stopped.",
|
||||
"smiFailTitle": "nvidia-smi fails with 'Driver/library version mismatch' after going back to LXC",
|
||||
"smiFailBody": "Host NVIDIA modules didn't reload cleanly. <code>modprobe -r nvidia</code> then <code>modprobe nvidia</code>. If that fails, reboot — a full reboot always clears residual state from the vfio binding.",
|
||||
"smiFailBody": "Compare the loaded host NVIDIA module with the installed userspace libraries, including those in LXCs. Align versions first; a reboot loads the installed module but cannot repair mismatched library packages. Reloading with <code>modprobe -r nvidia</code> and <code>modprobe nvidia</code> requires stopped GPU clients and may fail while dependent modules are in use.",
|
||||
"logTitle": "Install log",
|
||||
"logBody": "Every run writes to <code>/tmp/proxmenux_gpu_switch_mode.log</code> on the host. Attach it when asking for help on GitHub."
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user