import type { Metadata } from "next" import { getTranslations, getMessages, setRequestLocale } from "next-intl/server" import { Link } from "@/i18n/navigation" import Image from "next/image" import { DocHeader } from "@/components/ui/doc-header" import { Callout } from "@/components/ui/callout" import { Prerequisites } from "@/components/ui/prerequisites" import { Steps } from "@/components/ui/steps" import CopyableCode from "@/components/CopyableCode" export async function generateMetadata({ params, }: { params: Promise<{ locale: string }> }): Promise { const { locale } = await params const t = await getTranslations({ locale, namespace: "docs.hardware.igpuAccelerationLxc.meta" }) return { title: t("title"), description: t("description"), } } type CompareRow = { feature: string; lxc: string; vm: string } type PreflightItem = string type DistroRow = { distro: string; intel: string; nvidia: string } type RelatedItem = { label: string; href: string; tail?: string } export default async function AddGpuToLxcPage({ params, }: { params: Promise<{ locale: string }> }) { const { locale } = await params setRequestLocale(locale) const t = await getTranslations({ locale, namespace: "docs.hardware.igpuAccelerationLxc" }) const messages = (await getMessages({ locale })) as unknown as { docs: { hardware: { igpuAccelerationLxc: { compare: { rows: CompareRow[] } walkthrough: { preflight: { items: PreflightItem[] } installDrivers: { rows: DistroRow[] } } related: { items: RelatedItem[] } } } } } const compareRows = messages.docs.hardware.igpuAccelerationLxc.compare.rows const preflightItems = messages.docs.hardware.igpuAccelerationLxc.walkthrough.preflight.items const distroRows = messages.docs.hardware.igpuAccelerationLxc.walkthrough.installDrivers.rows const relatedItems = messages.docs.hardware.igpuAccelerationLxc.related.items const code = (chunks: React.ReactNode) => {chunks} const strong = (chunks: React.ReactNode) => {chunks} const em = (chunks: React.ReactNode) => {chunks} const vmLink = (chunks: React.ReactNode) => ( {chunks} ) const switchLink = (chunks: React.ReactNode) => ( {chunks} ) const nvidiaLink = (chunks: React.ReactNode) => ( {chunks} ) return (
{t.rich("intro.body", { code })}

{t("compare.heading")}

{t.rich("compare.intro", { em, vmLink })}

{compareRows.map((row, idx) => ( ))}
{t("compare.headerFeature")} {t("compare.headerLxc")} {t("compare.headerVm")}
{row.feature} {row.lxc} {row.vm}
{t.rich("prereqs.gpu", { strong, code })}, check: t("prereqs.gpuCheck"), }, { label: <>{t.rich("prereqs.vfio", { strong, switchLink })}, }, { label: <>{t.rich("prereqs.nvidia", { strong, nvidiaLink })}, check: t("prereqs.nvidiaCheck"), }, { label: <>{t.rich("prereqs.container", { strong })}, }, ]} /> {t.rich("unpriv.body", { code })}

{t("running.heading")}

{t.rich("running.body", { strong })}

{t("running.imageAlt")}

{t("howRuns.heading")}

{t("howRuns.body")}

{`┌─────────────────────────────────────────────┐
│  PHASE 1 — Detect, select, validate         │
│  (nothing touched yet)                      │
└──────────────────┬──────────────────────────┘
                   ▼
  lspci detects Intel / AMD / NVIDIA GPU(s)
  (NVIDIA: also check nvidia module loaded +
   nvidia-smi, capture host driver version)
                   │
                   ▼
  User picks LXC container from the list
                   │
                   ▼
  User selects which GPU(s) to add
  (checklist; auto-selects if only one)
                   │
                   ▼
  Pre-flight checks
  ├─ Not in SR-IOV (VF / active PF) → block
  ├─ Bound to vfio-pci? → offer Switch Mode, exit
  └─ Already configured in this CT? → filter out
      (skip duplicates, warn if partial)
                   │
     ┌─────── Cancel   OR   Confirm ────┐
     ▼                                  ▼
 Exit, nothing       ┌──────────────────┴──────────────────┐
 was changed         │  PHASE 2 — Configure + install      │
                     └──────────────────┬──────────────────┘
                                        ▼
                       Stop container (if running)
                                        │
                                        ▼
                       Write LXC config (/etc/pve/lxc/.conf):
                       ├─ Intel / AMD iGPU:
                       │    dev: /dev/dri/card*   gid=video
                       │    dev: /dev/dri/renderD* gid=render
                       ├─ AMD with ROCm (if /dev/kfd):
                       │    dev: /dev/kfd  gid=render
                       └─ NVIDIA:
                            dev: /dev/nvidia0..N
                            dev: /dev/nvidiactl · nvidia-uvm*
                            dev: /dev/nvidia-modeset
                            dev: /dev/nvidia-caps/* (if exists)
                                        │
                                        ▼
                       Install GPU guard hookscript
                       (same one used by VM passthrough, if
                        available — prevents conflicts on start/stop)
                                        │
                                        ▼
                       Start container + wait for readiness
                       (pct exec — true, up to ~30 s)
                                        │
                                        ▼
                       Install userspace drivers inside CT
                       (distro auto-detected)
                       ├─ Intel  → apk/pacman/apt
                       │           (intel-media-driver,
                       │            libva-utils, opencl-icd)
                       ├─ AMD    → Mesa VA drivers
                       │           (mesa-va-drivers, libva)
                       └─ NVIDIA →
                          ├─ Alpine:  apk add nvidia-utils
                          ├─ Arch:    pacman -S nvidia-utils
                          └─ Debian/Ubuntu/others:
                             host .run is pre-extracted, packed,
                             pct push'd into the container, run
                             with --no-kernel-modules --no-dkms
                                        │
                                        ▼
                       Align GIDs in /etc/group inside CT
                       (video=44, render=104 to match host)
                                        │
                                        ▼
                       Restore container state
                       (stop if it was stopped before)
                                        │
                                        ▼
                       Show summary + nvidia-smi output
                       (if NVIDIA) + log path`}
      

{t("walkthrough.heading")}

{t.rich("walkthrough.detect.body", { code })}

{t.rich("walkthrough.detect.tipBody", { nvidiaLink })}

{t("walkthrough.pickCt.body")}

{t("walkthrough.pickCt.imageAlt")}

{t("walkthrough.selectGpu.body")}

{t("walkthrough.selectGpu.imageAlt")}
{t("walkthrough.preflight.imageAlt")}

{t("walkthrough.preflight.intro")}

    {preflightItems.map((_, idx) => (
  • {t.rich(`walkthrough.preflight.items.${idx}`, { strong, code, switchLink })}
  • ))}

{t.rich("walkthrough.applyConfig.body1", { code })}

{t("walkthrough.applyConfig.body2")}

.conf dev0: /dev/dri/card0,gid=44 dev1: /dev/dri/renderD128,gid=104 dev2: /dev/nvidia0,gid=44 dev3: /dev/nvidiactl,gid=44 dev4: /dev/nvidia-uvm,gid=44 dev5: /dev/nvidia-uvm-tools,gid=44 dev6: /dev/nvidia-modeset,gid=44`} className="my-4" />

{t.rich("walkthrough.installDrivers.body", { code })}

{distroRows.map((row, idx) => ( ))}
{t("walkthrough.installDrivers.headerDistro")} {t("walkthrough.installDrivers.headerInt")} {t("walkthrough.installDrivers.headerNvidia")}
{row.distro} {row.intel} {row.nvidia}
{t("walkthrough.installDrivers.debianDistro")} {t("walkthrough.installDrivers.debianIntel")} {t.rich("walkthrough.installDrivers.debianNvidia", { code })}
{t.rich("walkthrough.installDrivers.whyBody", { code, strong })}

{t.rich("walkthrough.alignGids.body1", { code })}

{t("walkthrough.alignGids.body2")}

{t("vendors.heading")}

{t("vendors.intelHeading")}

{t.rich("vendors.intelBody", { em, code })}

{t("vendors.amdHeading")}

{t.rich("vendors.amdBody", { code })}

{t("vendors.nvidiaHeading")}

{t.rich("vendors.nvidiaBody", { code, strong })}

{t.rich("vendors.updateBody", { code, nvidiaLink })}

{t("verification.heading")}

{t("verification.body")}

# Intel / AMD — check DRI nodes and VA-API ls -l /dev/dri/ vainfo # NVIDIA — check nvidia-smi matches the host version nvidia-smi nvidia-smi --query-gpu=driver_version --format=csv,noheader # Check group alignment getent group video render`} className="my-4" />

{t("troubleshoot.heading")}

{t.rich("troubleshoot.mismatchBody", { code })} {t.rich("troubleshoot.denyBody", { code })} {t.rich("troubleshoot.vainfoBody", { code })} {t.rich("troubleshoot.logBody", { code })}

{t("related.heading")}

    {relatedItems.map((item) => (
  • {item.label} {item.tail}
  • ))}
) }