Self-HostingZFS mirror, replica cross-node ogni 15 minuti, 5 job vzdump stratificati. Pensavo di essere protetto. Poi ho controllato davvero: il mirror non era un mirror, i backup stavano sulla root, e l'offsite era vuoto.
Self-HostingVM vs LXC Proxmox: 40 MB vs 600 MB di RAM idle, boot 2s vs 30s, 8x densità. Quando usare LXC, quando serve davvero la VM, senza ideologia.

24 giugno 2026 · 11 min lettura
Ogni settimana mi arriva la stessa domanda: "Antonio, qual è il miglior backup per Proxmox?". È la domanda sbagliata. È come chiedere "qual è il miglior attrezzo" senza dire se devi piantare un chiodo o stringere un bullone.
Iscriviti alla newsletter per ricevere i migliori articoli direttamente nella tua inbox.
Su un nodo Proxmox con una RTX 2070 Super e i driver NVIDIA già installati sull'host, voicebox si installa in un container LXC con il bind dei device `/dev/nvidia*` — niente VM, niente VFIO, niente IOMMU, niente reboot — in meno di un'ora. Le due trappole che costano tempo sono il mismatch dello userspace NVIDIA (la distro del container deve combaciare con quella dell'host) e Python 3.13. Ecco il percorso reale, gotcha inclusi e con i benchmark VRAM misurati sul campo.
Il nodo pve gira Proxmox VE 9.2.3, kernel 7.0.6-2-pve. La RTX 2070 Super (8192 MiB) è già installata e i driver NVIDIA 610.43.02 sono sull'host da prima: nvidia-smi risponde senza problemi. I device presenti sotto /dev/:
/dev/nvidia0
/dev/nvidiactl
/dev/nvidia-modeset
/dev/nvidia-uvm
/dev/nvidia-uvm-tools
/dev/nvidia-caps/nvidia-cap1
/dev/nvidia-caps/nvidia-cap2voicebox gira interamente headless: backend FastAPI su porta 17493, web UI servita dalla stessa porta. Non ha bisogno di un display, di accesso diretto alla GPU di sistema né di esclusività sul device. Questo cambia completamente l'approccio all'infrastruttura.
La prima domanda è architetturale: VM con VFIO oppure LXC con bind dei device?
VFIO significa esclusività. La GPU viene strappata all'host, richiede IOMMU abilitato nel kernel (intel_iommu=on o amd_iommu=on nei parametri di boot) e impone un reboot. Sul nodo in questione /proc/cmdline non contiene né intel_iommu né amd_iommu: IOMMU è off. Abilitarlo richiederebbe un reboot di un nodo di produzione con container già in esecuzione, per dare alla VM un accesso esclusivo che non serve.
Il bind LXC, invece, è condiviso e leggero. Il kernel module NVIDIA gira sull'host, il container vede i device come se fossero suoi, e host e container possono usare la GPU contemporaneamente. Nessun IOMMU richiesto, nessun reboot. Per un'applicazione headless come voicebox è la scelta giusta in modo non ambiguo. Sul perché, tra una VM e un container, quasi sempre vince l'LXC, ho scritto un pezzo a parte: VM vs LXC su Proxmox, quando scegliere cosa. La verifica qui è stata rapida — device disponibili, IOMMU off, decisione in due minuti.
Ho creato CT 201 voicebox come container privileged (nesting attivo, 8 core, 12 GB di RAM, 60 GB su local-lvm). I major number reali dei device NVIDIA su questo host sono 195 (nvidia0/nvidiactl/nvidia-modeset), 511 (nvidia-uvm e nvidia-uvm-tools) e 236 (nvidia-caps). Il file /etc/pve/lxc/201.conf riceve queste righe:
# GPU passthrough — LXC bind
lxc.cgroup2.devices.allow: c 195:* rwm
lxc.cgroup2.devices.allow: c 511:* rwm
lxc.cgroup2.devices.allow: c 236:* rwm
lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-modeset dev/nvidia-modeset none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-caps/nvidia-cap1 dev/nvidia-caps/nvidia-cap1 none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-caps/nvidia-cap2 dev/nvidia-caps/nvidia-cap2 none bind,optional,create=fileI major number non sono universali: vanno letti dall'host con ls -la /dev/nvidia* prima di scrivere la config, perché su hardware diverso cambiano. Dopo il restart del container, pct exec 201 -- ls -la /dev/nvidia* mostra i device dentro il CT. Ma avere i device non basta: serve il corretto userspace NVIDIA. Lo stesso bind, con un carico diverso, l'ho usato per far girare un agente Hermes con Ollama sulla 2070 in passthrough LXC — la tecnica è identica, cambia solo cosa ci metti sopra.
È il punto dove si perde più tempo se non si conosce la trappola.
Il primo tentativo su Ubuntu 24.04 è fallito. La logica sembrava sensata: usare ubuntu2404 come repo CUDA per le librerie userspace. Il problema è che il repo CUDA di Ubuntu espone cuda-drivers 610 come metapacchetto, ma non include le librerie userspace 610 reali: libcuda1 e libnvidia-ml1 sono pacchetti virtuali forniti dall'archivio Ubuntu canonico, fermo alla versione 595. Il risultato è un mismatch — kernel module 610.43.02 sull'host, librerie userspace 595.x nel container. NVML non carica, CUDA non funziona.
La soluzione è concettualmente semplice una volta vista: usare la stessa distro e lo stesso repo dell'host. L'host gira Debian 13 con il repo CUDA debian13. Stessa distro, stesso repo, stessa versione: libcuda1 e libnvidia-ml1 sono alla 610.43.02-1, identiche al modulo kernel. Zero mismatch. Il container diventa quindi Debian 13 (trixie), e l'install dello userspace NVIDIA nel CT è:
# Aggiungere il repo CUDA Debian 13 (stessa procedura dell'host)
apt-get install -y libcuda1 libnvidia-ml1 \
libnvidia-gpucomp libnvidia-ptxjitcompiler1 libnvidia-pkcs11-openssl3 \
--no-install-recommendsPrima dell'install vero conviene un --dry-run, per verificare che le versioni siano 610.43.02-1 e che non vengano tirate dipendenze con DKMS o kernel headers: nel container non servono moduli kernel, serve solo lo userspace.
Un dettaglio che spiazza: nel repo Debian il pacchetto nvidia-smi è un transitional vuoto, non contiene il binario della CLI. Per leggere VRAM e stato GPU dal container si usa NVML direttamente, tramite ctypes o pynvml — che è esattamente quello che il backend di voicebox fa internamente. La verifica finale con NVML dal container:
device count: 1
name: NVIDIA GeForce RTX 2070 SUPER
driver: 610.43.02
VRAM total: 8192 MiB / free: 7777 MiBGPU operativa nel container. Si può procedere con l'install di voicebox.
Nel CT servono uv, bun, just e alcuni pacchetti di sistema (git, build-essential, ffmpeg). voicebox v0.5.0 viene clonato in /opt/voicebox. Le variabili d'ambiente da impostare prima dell'install:
export VOICEBOX_MODELS_DIR=/opt/voicebox-models
export HF_HOME=/opt/voicebox-modelsIl gotcha Python: Debian 13 installa Python 3.13 come default, ma numba 0.60 non ha wheel per 3.13 e l'installazione si interrompe con un errore di build. La soluzione è uv, che gestisce versioni Python indipendenti da quella di sistema:
uv python install 3.12
uv venv --python 3.12 --seed backend/venvVa fatto prima di just setup-python: la recipe cerca il venv già pronto in backend/venv e installa dentro quello, senza tirare la 3.13 di sistema. Il venv finale usa Python 3.12.13 e numba 0.60.0 si installa senza problemi. Poi:
cd /opt/voicebox
just setupIl setup scarica dipendenze Python e JavaScript: circa 6-12 minuti la prima volta (incluso il download dei wheel PyTorch), per un venv finale da 6.7 GB. Un dettaglio su PyTorch: su Linux il wheel di default da PyPI è già CUDA, la recipe setup-python unix non forza un index CUDA separato, e il risultato è torch 2.12.1+cu130, CUDA runtime 13.0, device capability (7,5). Avvio headless:
nohup backend/venv/bin/python -m uvicorn backend.main:app \
--host 0.0.0.0 --port 17493 \
> /root/vbx-backend.log 2>&1 &Dopo circa 6 secondi, il check di salute conferma tutto:
{
"gpu_available": true,
"gpu_type": "CUDA (NVIDIA GeForce RTX 2070 SUPER)",
"backend_variant": "cuda",
"version": "0.5.0"
}gpu_available: true, backend_variant: "cuda", MCP montato su /mcp. La prima voce sintetizzata con Kokoro (preset af_heart, una frase inglese da 7 parole): 6,58 secondi di audio generati in 2,0 secondi, con un picco VRAM di 1341 MiB.
Dopo il primo test ho fatto un benchmark sistematico di tutti gli engine disponibili, con frasi inglesi e italiane standardizzate, VRAM misurata via NVML, backend riavviato e isolato per ogni engine. La regola di lettura è semplice: RTF sotto 1 vuol dire più veloce del realtime, RTF sopra 1 più lento del realtime. Engine per engine:
Kokoro-82M è il più veloce e leggero in assoluto. In inglese (preset) genera 6,38 s di audio in 0,51 s — RTF 0,08, oltre dodici volte più veloce del realtime — con appena 1357 MiB di VRAM di picco. In italiano sale a RTF 0,40 (2,02 s per 5,03 s di audio), stessa VRAM.
LuxTTS/ZipVoice sta sotto i 2,3 GB di picco. In cloning inglese fa RTF 1,01 (3,86 s per 3,81 s di audio); in italiano vola a RTF 0,13 (0,51 s per 3,96 s), con VRAM di picco 2265 MiB.
Qwen3-TTS 0.6B è più pesante e più lento, ma con qualità multilingua superiore. In inglese preset RTF 2,06 (14,48 s per 7,04 s), in inglese cloning RTF 2,25 (13,49 s per 6,00 s) con VRAM di picco 4245 MiB, in italiano RTF 1,45 (7,55 s per 5,20 s).
Chatterbox Multilingual in cloning inglese fa RTF 2,25 (12,40 s per 5,52 s) con VRAM di picco 5113 MiB, in italiano scende a RTF 0,61 (3,02 s per 4,98 s). Qui c'è la sorpresa: vari benchmark online lo davano a 8-16 GB, e sul campo ha girato a 5113 MiB di picco. La ricerca era pessimista, l'hardware reale la smentisce.
Chatterbox Turbo in cloning inglese fa RTF 1,95 (11,61 s per 5,96 s) ed è il più affamato del lotto: 6741 MiB di picco, il massimo registrato. Ci si riesce, anche se con poco margine sugli 8 GB.
HumeAI TADA è l'unico vero scarto su questa GPU. La variante 1B si carica in VRAM (circa 3963 MiB) senza errori, ma la generazione stalla: GPU utilization a 0%, nessun output dopo lungo tempo. Non è un OOM, è un blocco funzionale — dipendenze mancanti o un bug per questa combinazione driver/CUDA. La 3B-ml non l'ho testata: su 8 GB sarebbe OOM.
Il risultato più controintuitivo è che tutti e sei gli engine pratici entrano negli 8 GB, con il picco massimo a 6741 MiB. Il vero discriminante sulla 2070 non è la VRAM ma la velocità: Kokoro in inglese a RTF 0,08 e LuxTTS in italiano a RTF 0,13 sono adatti al realtime, mentre Qwen3-TTS e Chatterbox in inglese stanno sopra il realtime (RTF circa 2) — usabili per batch e automazioni, meno per l'interazione diretta. E se la GPU non ce l'hai affatto, vale lo stesso principio dell'inference testuale: Ollama gira in LXC anche CPU-only, e qui Kokoro resta l'engine garantito.
Il mismatch userspace Ubuntu/Debian è la trappola principale. La causa è strutturale: i repo CUDA di Ubuntu e Debian sono separati, e Ubuntu non garantisce le versioni userspace recenti nello stesso ciclo dei driver. Se l'host gira Debian, il container deve girare Debian; se l'host girasse Ubuntu, si userebbe Ubuntu con il repo CUDA corrispondente.
Python 3.13 contro numba è il secondo gotcha: è un limite di numba, non di voicebox, e uv lo risolve in modo pulito senza toccare il Python di sistema. Da ricordare per qualsiasi progetto Python su Debian 13, uscito con la 3.13, ancora troppo nuova per alcune librerie ML.
Il pacchetto nvidia-smi transitional non è un errore: nel repo Debian è un metapacchetto vuoto. Per leggere VRAM e stato GPU dal container si va di NVML (pynvml o ctypes più libnvidia-ml.so).
TADA 1B, infine, si carica ma stalla: su questa configurazione è da escludere a priori.
No. IOMMU e VFIO servono solo per assegnare la GPU in modo esclusivo a una VM. Con un container LXC basta il bind dei device /dev/nvidia*: nessun IOMMU, nessun reboot, e host e container condividono la stessa scheda.
In questo setup ho usato un container privileged con nesting per semplicità. Il passthrough via bind funziona anche su unprivileged, ma richiede la mappatura corretta degli ID e dei permessi sui device: con privileged si evitano diversi attriti, a fronte di una superficie di sicurezza maggiore.
Tutti gli engine pratici stanno negli 8 GB: il picco massimo misurato è 6741 MiB su Chatterbox Turbo. Il limite reale non è la memoria ma la velocità di generazione, che su alcuni engine supera il realtime.
Perché l'host è Debian 13. Le librerie userspace NVIDIA del container devono combaciare con il kernel module dell'host (610.43.02), e solo il repo CUDA della stessa distro dell'host le fornisce a quella versione esatta. Su un host Ubuntu si userebbe un container Ubuntu.
Una guida in quattro parti per installare, configurare e usare voicebox in un homelab con Proxmox.
Parte 1 — voicebox: lo studio vocale AI che gira tutto in locale: cos'è, architettura, confronto onesto con ElevenLabs e Wispr Flow, panoramica engine.
Parte 2 — Installare voicebox su Proxmox con GPU passthrough (RTX 2070 Super) (questo post): LXC bind, il gotcha Debian vs Ubuntu, Python 3.13 con uv, benchmark VRAM reali.
Parte 3 — voicebox in pratica: voice cloning, TTS multilingua e dettatura: cloning reale, quale engine per quale lingua, la pipeline edge-tts→RVC, dettatura con Whisper.
Parte 4 — Dare voce ai tuoi agenti AI: voicebox + MCP con Claude Code: setup MCP, i quattro tool, voci per-agente, verdetto finale.
Nella Parte 3 i numeri di questa tabella diventano campioni audio ascoltabili: come funziona il voice cloning della mia voce reale, le differenze di qualità tra engine in inglese e in italiano, e la pipeline che mi ha portato fuori da voicebox per clonare la voce davvero.