Skip to content

Proxmox ​

camera.ui läuft auf Proxmox VE in einem LXC-Container, der Docker beherbergt. Ein Befehl auf dem Proxmox-Host richtet alles ein: Container, Docker und camera.ui.

Warum ein LXC und keine VM?

Ein LXC kann die iGPU teilen: /dev/dri bleibt gleichzeitig für den Host und andere Container nutzbar, während eine VM mit PCIe-Passthrough die GPU monopolisiert, und ein LXC hat weniger Overhead. Für NVIDIA-Karten ist eine VM die bessere Wahl (siehe unten).

Schnellstart ​

Auf dem Proxmox-Host (als root) ausführen:

bash
curl -fsSLO https://raw.githubusercontent.com/cameraui/docker/main/proxmox/install-cameraui-lxc.sh
bash install-cameraui-lxc.sh

Das Script lädt das Ubuntu-24.04-LXC-Template, erstellt einen unprivilegierten Container mit Nesting (privilegierte Container können auf aktuellen Proxmox-Versionen Dockers AppArmor-Profil nicht mehr laden), installiert Docker darin, deployt camera.ui via Docker Compose und gibt die URL der Web-UI aus. Getestet mit Proxmox VE 9.

Umgebungsvariablen:

VariableDefaultBedeutung
CTIDnächste freie IDContainer-ID
CT_HOSTNAMEcamerauiContainer-Hostname
CORES / RAM_MB / DISK_GB4 / 4096 / 16Container-Ressourcen
BRIDGEvmbr0Netzwerk-Bridge (Container bekommt seine IP per DHCP)
STORAGEauto-detectrootfs-Storage (bevorzugt local-lvm, local-zfs, local, sonst den ersten aktiven Storage, der ein Container-rootfs aufnehmen kann)
TEMPLATE_STORAGElocalStorage, auf den das LXC-Template geladen wird (braucht Content-Typ „Container-Template“)
FLAVORcpucpu, intel oder amd (wählt den Image-Flavor); nvidia ist experimentell
GPU_PASSTHROUGH1 wenn Flavor ≠ cpureicht /dev/dri in den Container
TZZeitzone des HostsZeitzone im Container

Beispiel für eine Intel-Maschine: FLAVOR=intel bash install-cameraui-lxc.sh

Shell im Container öffnen ​

Das Script legt den Container ohne Root-Passwort an, über die Proxmox-Konsole oder SSH kommst du also nicht hinein. Von der Shell des Hosts:

bash
pct enter <CTID>

Einzelne Befehle:

bash
pct exec <CTID> -- docker logs cameraui

Konsole und SSH funktionieren, sobald du ein Passwort vergibst:

bash
pct exec <CTID> -- passwd

Hardware-Beschleunigung ​

  • Intel / AMD iGPU. FLAVOR=intel (oder amd) setzen. Das Script reicht den GPU-Render-Node durch den Container bis zu Docker, sonst ist nichts zu konfigurieren. Details: Hardware-Beschleunigung.
  • NVIDIA. Nutze eine VM mit PCIe-Passthrough statt eines LXC. Darin folgst du dem Standard-Docker-Setup mit dem nvidia-Flavor. Ein LXC müsste Host-Treiber und Userspace-Bibliotheken im Container dauerhaft versionsgleich halten. Die VM monopolisiert dafür die Karte. Brauchen andere Dienste auf dem Host dieselbe GPU (Ollama, Jellyfin), siehe NVIDIA im LXC unten.
  • KI-Beschleuniger (Coral, Hailo). Den Host-Treiber auf dem Proxmox-Host installieren, dann den Device-Node (/dev/apex_0, /dev/hailo0) in den Container reichen.

NVIDIA im LXC (experimentell) ​

FLAVOR=nvidia teilt die Karte zwischen dem Container und anderen Diensten auf dem Host, was eine VM nicht kann. Der Haken ist eine harte Versionskopplung: Die NVIDIA-Userspace-Bibliotheken im Container müssen exakt zum Kernel-Treiber des Hosts passen, nach jedem Treiber-Update.

Voraussetzung ist ein funktionierender NVIDIA-Treiber auf dem Proxmox-Host (.run-Installer mit --dkms plus pve-headers; nvidia-smi auf dem Host muss funktionieren), und die installierte Treiberversion muss auf download.nvidia.com existieren. Dann:

bash
FLAVOR=nvidia bash install-cameraui-lxc.sh

Das Script reicht alle /dev/nvidia*-Device-Nodes in den Container, installiert den passenden Userspace-Treiber (--no-kernel-module) plus das NVIDIA Container Toolkit (mit no-cgroups=true, weil ein unprivilegierter Container keine Device-Cgroups verwalten kann) und registriert einen Sync-Service, der nach Host-Treiber-Updates beim Boot den passenden Userspace nachinstalliert. Verifizieren mit:

bash
pct exec <CTID> -- docker exec cameraui nvidia-smi

Experimentell

Dieser Weg hängt an NVIDIAs Installer-Archiv und daran, dass der Host-Treiber gesund bleibt; nach einem Host-Treiber-Update braucht der Container einen Reboot zum Nachsynchronisieren. Wenn es bricht, funktioniert der VM-Weg immer. Reports und Fixes sind im docker-Repo willkommen.

Aufnahmen auf einer dedizierten Platte oder einem NAS ​

Aufnahmen landen standardmäßig auf dem eigenen Volume des Containers. Für eine größere Platte, ein NAS-Share oder einen zusammengefassten Pool reichst du diesen Speicher in den Container und setzt den NVR-Speicherpfad darauf.

Unprivilegierte Container können NFS/CIFS-Shares nicht selbst mounten. Mounte das Share auf dem Proxmox-Host und reiche es als Mountpoint in den Container:

bash
pct set <CTID> -mp0 /mnt/nas/recordings,mp=/mnt/recordings

Setze dann den NVR-Speicherpfad auf /mnt/recordings (Einstellungen → Aufnahmen → Speicher), oder siehe den Speicher-Abschnitt der Docker-Seite.

FUSE-Mounts (mergerfs, rclone) brauchen Sonderbehandlung

Ein FUSE-Mount (etwa ein mergerfs-Pool, der mehrere Platten zusammenfasst) propagiert nicht wie ein normales Dateisystem in einen (unprivilegierten) Container. Ist der FUSE-Mount nicht vor dem Container-Start auf dem Host aktiv, sieht der Container den leeren Mountpoint auf der Root-Disk des Hosts statt den Pool. Aufnahmen landen dann auf der kleinen OS-Platte und werden innerhalb von Minuten wieder rotiert.

Mounte den Pool auf dem Host vor dem Container-Start (z.B. per fstab-Eintrag oder systemd-Unit mit Before=pve-container@<CTID>.service) und stelle sicher, dass der Mount in den Container geteilt wird. Danach immer aus dem Container heraus verifizieren.

Speichergröße verifizieren ​

Nach dem Setzen eines eigenen Speicherpfads prüfen, ob der Container das volle Volume sieht:

bash
pct exec <CTID> -- df -h /mnt/recordings

Die angezeigte Größe muss zu deiner echten Platte oder deinem Pool passen. Zeigt sie die kleine Container-Root-Größe, ist der Mount nicht propagiert. Der NVR loggt seinen aufgelösten Speicher samt Größe außerdem bei jedem Start und zeigt in Einstellungen → Aufnahmen eine Warnung, wenn das Volume unerwartet klein ist.

Verifizieren ​

Bei jedem Start loggt der Container, welche Devices tatsächlich angekommen sind. Siehe Aus dem Container verifizieren. Die camera.ui-UI ist unter https://<container-ip>:3443 erreichbar (das Script gibt die IP am Ende aus).