Proxmox VE LXC Deployment (iGPU passthrough)

Recommended path: PVE host → privileged LXC container → docker inside the container → SkyView image. Don't install docker directly on the PVE host (Proxmox officially advises against it; it clashes with PVE's iptables / apt). LXC is namespace-isolated with near-zero performance overhead, and /dev/dri passthrough feels almost identical to running docker on the host.

HardwareRecommended variantiGPU status
N100 / N305 / N355 mini PCopenvinoAlder Lake-N iGPU, /dev/renderD128 available
J4125 / J4105 old NUCopenvinoApollo Lake iGPU, /dev/renderD128 available
i3-i7 11th gen+ + Iris XeopenvinoBest value pick
NVIDIA GPU PVE hostcuda or trtRequires installing the NVIDIA driver on the PVE host + passing /dev/nvidia* to the LXC

2. Prerequisites (on the PVE host)

  1. 1

    Confirm the host has /dev/dri

    Run ls -la /dev/dri/ in the PVE shell; you should see card0/card1 + renderD128; otherwise the PVE kernel hasn't loaded i915, so run modprobe i915 first

  2. 2

    Download the Debian 12 template

    PVE Web UI → local → CT Templates → Templates button → find and download debian-12-standard (or pveam download local debian-12-standard_12.x_amd64.tar.zst)

  3. 3

    Find the render/video group GIDs

    Run getent group render and getent group video in the PVE shell and note the GIDs (default render=104, video=44); you'll need them for pct set later

3. Create the LXC container

bash
# In the PVE host shell: create a vmid=101 container, 4 cores, 4G RAM, 40G disk
pct create 101 local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst \
  --hostname yunkan \
  --cores 4 --memory 4096 --swap 1024 \
  --rootfs local-lvm:40 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp,firewall=0 \
  --unprivileged 0 \
  --features nesting=1,keyctl=1 \
  --onboot 1

pct start 101

Must be privileged + nesting=1 + keyctl=1

--unprivileged 0 = privileged LXC, the simplest choice for home use (running docker in an unprivileged container needs 90+ lines of lxc.conf tuning). nesting=1 lets you run docker inside the container, and keyctl=1 lets docker overlayfs work.

4. Pass the iGPU through to the LXC

bash
# On the PVE host: pass renderD128 and card1 through to vmid=101
pct set 101 -dev0 /dev/dri/renderD128,gid=104   # render group
pct set 101 -dev1 /dev/dri/card1,gid=44         # video group

# Reboot the container for the dev passthrough to take effect
pct reboot 101

# Verify: enter the container and check that /dev/dri exists
pct exec 101 -- ls -la /dev/dri/

5. Install docker inside the LXC + run SkyView

bash
# Enter the LXC
pct enter 101

# Install docker
curl -fsSL https://get.docker.com | sh

# Run the SkyView one-line script (auto-selects the openvino variant because it detects /dev/dri)
curl -fsSL https://cdn.yun-kan.com/yunkan-install.sh | bash

When the script finishes it gives an LXC IP + port (e.g. http://10.0.0.148:23406/). Open it from any machine on the same subnet to enter the Setup wizard.

6. Upgrading

Upgrades are done inside the LXC (pct enter 101), exactly like a regular Linux host — no LXC-specific steps. Prefer method A (one-click upgrade from the web console, no command line needed); use method B / C when you want to pin a specific version or prefer the command line.

Open Web Admin → Settings → System upgrade and click Upgrade. The system pulls the new image and recreates the main container automatically (a short-lived worker container appears during the switch and removes itself when done). If the new version fails to start, it automatically rolls back to the previous one — no command line involved. The docker socket works normally inside LXC, so this path is fully supported.

Option B: command-line upgrade

Use this when you want to control the timing yourself or pin a specific version. Enter the LXC and run in the deployment directory (default ~/skyview):

bash
pct enter 101
cd ~/skyview

# Upgrade to the latest image for the current tag (default latest) and rebuild
docker compose -p yunkan -f compose.yml up -d --pull always

To pin a specific version, change the image tag in the compose first, then rebuild (keep the variant unchanged — see the warning below):

bash
cd ~/skyview
# Replace 0.9.9 with your target version
sed -i 's|image: .*/yunkan-.*|image: registry.cn-hangzhou.aliyuncs.com/yunkan/yunkan-openvino:0.9.9|' compose.yml
docker compose -p yunkan -f compose.yml up -d --pull always --force-recreate

Don't switch variants by mistake during an upgrade

The variant in the image tag (openvino / cpu / cuda / trt) must match the original — an LXC + iGPU passthrough install uses openvino, and mistyping it as cpu loses hardware acceleration. If unsure, run docker ps to see whether the current image name contains -openvino or -cpu. The data/ and recordings/ volumes are cross-version compatible, DB migration runs automatically when the new container starts, and upgrading doesn't lose data.

Option C: re-run the install script

The one-line installer is idempotent: re-running it re-pulls the image, regenerates the compose file and recreates the container. Ideal for refreshing an older install to the latest standard layout (it also retires the legacy yunkan-updater helper container):

bash
pct enter 101
curl -fsSL https://cdn.yun-kan.com/yunkan-install.sh | bash

7. Backup / restore

  • LXC snapshot: before upgrading, pct snapshot 101 pre-upgrade-$(date +%Y%m%d); if something breaks, pct rollback 101 <snapshot-name> rolls the whole container back instantly
  • LXC backup: vzdump 101 --storage local backs up the entire container (including the docker volume) via PVE's standard backup; or Web UI → select 101 → Backup
  • Restore: pct restore <new-vmid> <backup-file> restores from a backup
  • ⚠️ Don't destroy + create to rebuild: rebuilding the LXC changes /etc/machine-id, so the license fingerprint drifts → it consumes a new slot in a loop. To reset, always use pct restore from a backup; never create a new container

8. FAQ

/dev/dri doesn't appear inside the LXC

Confirm the pct set commands are correct (mind the gid numbers per what you actually found on your host); reboot the container with pct reboot 101; if it still fails, pct config 101 | grep dev to see whether the config was written.

docker run reports a keyctl error

You forgot --features keyctl=1 when creating the container. Add it: pct set 101 --features nesting=1,keyctl=1, then pct reboot 101.

Manage all your LXCs centrally

PVE Web UI → Datacenter → select LXC 101 → visualize CPU/memory/disk/network; friendlier than logging into the host and running docker stats.
Proxmox VE LXC Deployment - SkyView Docs