SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-21

Container di sistema Incus su VPS: guida pratica

Configura Incus su un VPS con init, utenti e servizi separati: verifica virtualizzazione, pool di storage e rete, evitando i problemi che Docker non copre.

Che cos'è un container di sistema Incus

I container di sistema Incus su un VPS forniscono una macchina completa con un proprio sistema init e account utente distinti, non un singolo processo con un filesystem associato. Il container viene avviato, esegue init come PID 1 e risponde a systemctl. Condivide il kernel dell'host, quindi non è una macchina virtuale. Tutto ciò che si trova sopra il kernel si comporta come un sistema autonomo.

Incus è il fork gestito dalla community di LXD, mantenuto nell'ambito del progetto Linux Containers. Il comando client è incus. Incus esegue anche vere macchine virtuali tramite QEMU quando si specifica --vm, ma il container di sistema è il motivo per cui la maggior parte degli utenti lo installa ed è l'argomento trattato nel resto di questa guida.

Perché i confronti con Docker possono trarre in inganno

Docker impacchetta un processo. Incus impacchetta un sistema operativo. La documentazione di Incus descrive direttamente questa distinzione: "I container applicativi (forniti, ad esempio, da Docker) impacchettano un singolo processo o un'applicazione. I container di sistema, invece, simulano un sistema operativo completo, simile a quello che si eseguirebbe su un host o in una macchina virtuale."

Questa differenza cambia il modo in cui si utilizza il container ogni giorno.

  • Un'immagine Docker non include un sistema init, quindi systemctl al suo interno non funziona. Un container Incus esegue un sistema init, quindi servizi e timer funzionano come su un server.
  • Un container Docker è progettato per essere eliminato e ricreato da un Dockerfile. Un container Incus è progettato per essere conservato, aggiornato e acquisito come snapshot.
  • Un'immagine Docker è un artefatto di build da inviare a un registry. Un'istanza Incus è costituita dallo stato memorizzato su disco in uno storage pool e viene spostata con incus export.
  • Docker isola un workload. Incus isola una macchina, quindi un singolo container può ospitare più workload e più account utente.

È possibile eseguire Docker all'interno di un container di sistema Incus. Non si eseguirebbe Incus all'interno di un container applicativo Docker. Se ciò che serve realmente è un processo per container con un passaggio di build dell'immagine, il confronto da leggere per primo è Podman e Docker su un VPS. Se invece serve un kernel separato per ogni workload anziché un kernel condiviso, Firecracker microVM su un VPS rappresenta l'approccio opposto.

Incus funziona all'interno di una VPS?

Dipende dal tipo di virtualizzazione della VPS e dal relativo kernel. Verifica entrambi prima di installare qualsiasi componente. Non basarti sulla pagina commerciale del provider. Esegui questi quattro comandi sul sistema.

systemd-detect-virt
uname -r
stat -fc %T /sys/fs/cgroup
cat /sys/fs/cgroup/cgroup.controllers

Se l'output contiene systemd-detect-virt, kvm o qemu, la VPS è una macchina virtuale con un kernel proprio. Questo è il caso più semplice, perché Incus si comporta come su hardware fisico. Se l'output contiene lxc, lxc-libvirt o openvz, la VPS è a sua volta un container che condivide il kernel del provider. I container Incus eseguiti al suo interno sono container annidati. L'annidamento funziona solo se il provider lo ha abilitato per il tuo container. Non puoi abilitarlo dall'interno, perché l'impostazione risiede sull'host, che non controlli.

stat -fc %T /sys/fs/cgroup dovrebbe stampare cgroup2fs. Qualsiasi altro risultato indica che il sistema usa cgroup (control group) v1 oppure una configurazione ibrida. Le versioni attuali di Incus non sono progettate per queste configurazioni.

cat /sys/fs/cgroup/cgroup.controllers elenca i controller dei control group delegati alla tua VPS. La documentazione di Incus indica blkio, cpuset, devices, freezer, memory e pids come requisiti. In una VPS annidata, l'elenco è spesso più breve rispetto a una VPS KVM, perché il provider decide quali controller delegare. Un controller assente da quel file non può essere usato da Incus. Di conseguenza, il limite dell'istanza che dipende da quel controller non è disponibile.

La versione del kernel è oggi più importante rispetto al passato. Ad agosto 2026, la documentazione di Incus indica due requisiti minimi diversi per i due rami mantenuti dal progetto upstream. Il ramo 6.0 LTS (supporto a lungo termine) indica: «La versione minima supportata del kernel è 5.4». Il ramo stabile corrente indica: «La versione minima supportata del kernel è 6.12». Ubuntu 24.04 include la serie 6.0 LTS nei propri repository e la abbina a un kernel 6.8. Questa combinazione è supportata. Se installi la build stabile corrente dal repository upstream sullo stesso kernel 6.8, la versione sarà inferiore al minimo documentato. Leggi quindi uname -r prima di scegliere un repository.

Se il tuo obiettivo sono macchine virtuali complete, invece dei container, il vincolo è diverso e più restrittivo. Consulta la virtualizzazione annidata su una VPS per verificare se la tua VPS può esporre /dev/kvm e Proxmox su una VPS a noleggio per il caso in cui l'hardware sia di tua proprietà.

Installare Incus su Ubuntu o Debian

Debian 13 e Ubuntu 24.04 e versioni successive includono Incus nei propri repository.

sudo apt update
sudo apt install -y incus

Su Debian, incus-base installa il supporto per i container senza i componenti per le macchine virtuali. Su Ubuntu, aggiungi qemu-system se vuoi anche istanze --vm.

Per una versione più recente di quella disponibile nella distribuzione, i pacchetti upstream si trovano in pkgs.zabbly.com. Questi comandi provengono dal README del repository ufficiale del progetto.

sudo apt update && sudo apt install -y curl
sudo mkdir -p /etc/apt/keyrings/
sudo curl -fsSL https://pkgs.zabbly.com/key.asc -o /etc/apt/keyrings/zabbly.asc
sudo sh -c 'cat <<EOF > /etc/apt/sources.list.d/zabbly-incus-stable.sources
Enabled: yes
Types: deb
URIs: https://pkgs.zabbly.com/incus/stable
Suites: $(. /etc/os-release && echo ${VERSION_CODENAME})
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/zabbly.asc
EOF'
sudo apt-get update
sudo apt-get install -y incus

Poi autorizza il tuo utente ad accedere al socket del daemon.

sudo usermod -aG incus-admin "$USER"
newgrp incus-admin
incus info

incus info visualizza la configurazione del server e conferma che il socket funziona. Un errore di autorizzazione indica che la modifica del gruppo non è ancora stata applicata alla shell; newgrp incus-admin la applica alla shell corrente, mentre un nuovo accesso risolve correttamente il problema. Considera l'appartenenza a incus-admin equivalente all'accesso root sull'host, perché l'accesso a quel socket fornisce il controllo completo di un daemon eseguito come root. Alcune distribuzioni creano anche un gruppo semplice incus per l'accesso limitato degli utenti.

Ora inizializza il daemon.

sudo incus admin init

Rispondi alle domande invece di usare incus admin init --minimal. Il percorso minimo seleziona il driver di storage dir, e la sezione successiva spiega perché questa scelta continua a influenzare la configurazione.

Avvia qualcosa e verifica che funzioni.

incus launch images:debian/13 web
incus list
incus exec web -- bash

incus list dovrebbe mostrare web come RUNNING con un indirizzo IPv4 nella subnet incusbr0. L'assenza di un indirizzo indica che DHCP (protocollo di configurazione dinamica degli host) non ha completato la procedura; la sezione sul networking tratta questo problema. Un container che non riesce ad avviarsi visualizza il motivo in incus info web --show-log, mentre gli errori a livello di daemon vengono registrati in sudo journalctl -u incus -n 50. Su un VPS in cui systemd-detect-virt ha restituito lxc o openvz, questo avvio verifica concretamente se il nesting è disponibile.

Perché il backend di storage predefinito è importante

Il backend di storage determina se uno snapshot viene creato istantaneamente o se viene eseguita una copia completa del disco del container. È l'unica scelta effettuata durante l'installazione che in seguito non si può modificare a costi contenuti.

Incus supporta dir, btrfs, lvm, zfs, Ceph e diversi driver remoti. Su una VPS con un solo disco, la scelta reale è tra dir e btrfs.

Il driver dir conserva ogni container come normali file e directory sotto /var/lib/incus. Incus lo descrive come «molto più lento di tutti gli altri driver», perché deve decomprimere ogni immagine e creare copie effettive invece di fare riferimento a blocchi condivisi. Uno snapshot di un container da 4 GiB scrive 4 GiB e richiede lo stesso tempo di cp -a. Le quote disco funzionano soltanto su ext4 o XFS con le project quota abilitate a livello di filesystem. Questa opzione non è attiva per impostazione predefinita nella maggior parte delle immagini VPS, quindi un limite disco su un pool dir spesso non ha alcun effetto.

btrfs e zfs usano la tecnica copy-on-write, quindi uno snapshot registra soltanto i blocchi modificati in seguito. Incus indica questi due driver come backend consigliati. Gli snapshot diventano quasi istantanei. Le quote disco funzionano tramite il supporto nativo alle quote del filesystem.

La maggior parte dei piani VPS offre un solo disco senza una partizione aggiuntiva, quindi il pool deve essere collocato in un file loop. Incus lo fa automaticamente quando non si specifica alcun source=.

sudo apt install -y btrfs-progs
incus storage create fast btrfs size=30GiB
incus profile device set default root pool=fast
incus launch images:debian/13 web2 -s fast

Senza size=, un pool basato su loop occupa il 20% dello spazio libero sul disco, con un minimo di 5 GiB e un massimo di 30 GiB. Impostare questo valore in modo esplicito. Il file loop è un file del filesystem root, quindi il pool e l'host condividono lo stesso spazio libero. Di conseguenza, se il pool si riempie, si riempie anche il disco dell'host.

Su Debian e Ubuntu, ZFS è un modulo DKMS e non un modulo incluso nel kernel. Viene quindi ricompilato a ogni aggiornamento del kernel e la compilazione può fallire dopo uno di questi aggiornamenti. Su un server che non viene monitorato ogni giorno, btrfs richiede meno manutenzione dei due.

Le tre modalità di rete e ciò che espone ciascuna

incus admin init crea un bridge gestito chiamato incusbr0 e vi collega ogni nuova istanza. Questo è uno dei tre modi per collegare un container. Gli altri due esistono perché il primo nasconde i container dietro il NAT (network address translation).

Bridge gestito. incusbr0 riceve una subnet privata. L'host utilizza il primo indirizzo della subnet e funge da gateway. Incus esegue DHCP e DNS (domain name system) su questa rete. Il traffico in uscita passa dall'indirizzo pubblico dell'host con il source NAT applicato. Dall'esterno non è possibile raggiungere il container finché non lo si configura esplicitamente. Per inoltrare una porta, utilizzare un proxy device.

incus config device add web http proxy listen=tcp:0.0.0.0:8080 connect=tcp:127.0.0.1:80 nat=true

nat=true esegue l'inoltro tramite regole netfilter invece di usare una connessione separata nello userspace. In questo modo l'indirizzo reale del client rimane nei log del container. Incus supporta questa modalità soltanto quando l'host è il gateway dell'istanza, come avviene nel caso incusbr0.

macvlan. Il container riceve un proprio indirizzo MAC (media access control) sulla rete fisica dell'host. Nella maggior parte delle piattaforme VPS questa configurazione non funziona, perché la porta dello switch virtuale è associata all'indirizzo MAC della VM e scarta i frame provenienti da qualsiasi altro indirizzo. Esiste anche un secondo limite, che può causare problemi anche quando la configurazione funziona. Incus documenta che "i dispositivi macvlan, pur potendo comunicare tra loro e verso l'esterno, non possono comunicare con il dispositivo padre. Di conseguenza, non è possibile usare macvlan se è necessario che le istanze comunichino con l'host stesso".

Routed. È la modalità che normalmente funziona su un VPS con indirizzi aggiuntivi. Incus documenta il dispositivo come un componente che "crea una coppia di dispositivi virtuali per collegare l'host all'istanza e configura route statiche e voci proxy ARP/NDP per consentire all'istanza di unirsi alla rete dell'interfaccia parent designata". ARP è l'address resolution protocol. Il container mantiene un indirizzo pubblico. L'host risponde alle richieste ARP per quell'indirizzo, quindi il provider vede ancora soltanto l'indirizzo MAC dell'host.

incus config device add web eth0 nic nictype=routed parent=enp1s0 ipv4.address=203.0.113.20

Ricavare il nome dell'interfaccia parent da ip route show default. Le immagini attuali usano nomi come enp1s0 o ens3, raramente eth0. Assegnare il nome eth0 al dispositivo sostituisce quello fornito dal profilo default. Il container utilizza quindi l'interfaccia routed invece del bridge. Verificare il risultato dall'interno con ip a e ip route.

Perché un container ha raggiunto un servizio sull'host

Un container su incusbr0 ha un proprio namespace di rete. Non dispone di un confine firewall rispetto all'host. L'host si trova su quel bridge all'indirizzo del gateway; dall'interno del container è quindi un vicino direttamente raggiungibile e ogni servizio dell'host in ascolto su 0.0.0.0 risponde su quell'indirizzo.

Verificalo direttamente. Sull'host, elenca i servizi in ascolto.

sudo ss -tlnp

Quindi, dall'interno di un container, usa come destinazione il gateway indicato da ip route.

ip route show default
nc -zv 10.0.0.1 6379

Se un database, un endpoint di metriche o un pannello di amministrazione sull'host è associato a 0.0.0.0, la verifica ha esito positivo. Il firewall di rete del provider non ha mai visto il pacchetto, perché il pacchetto non ha mai lasciato la macchina. Questo spiega la maggior parte delle domande del tipo «come ha fatto a raggiungerlo»: il container è isolato da Internet tramite NAT, ma non è isolato dall'host da alcun meccanismo.

Associa i servizi dell'host a 127.0.0.1 quando possibile. Poi filtra il bridge sull'host. Su un sistema con ufw, la policy predefinita di rifiuto blocca già il traffico dai container verso l'host. Questo interrompe il DNS e il DHCP di Incus; la correzione indicata nella documentazione di Incus è sudo ufw allow in on incusbr0. Quel singolo comando riapre tutte le porte dell'host a tutti i container. Consenti invece soltanto il traffico effettivamente necessario ai container.

sudo ufw allow in on incusbr0 to any port 53 proto udp
sudo ufw allow in on incusbr0 to any port 53 proto tcp
sudo ufw allow in on incusbr0 to any port 67 proto udp
sudo ufw route allow in on incusbr0
sudo ufw route allow out on incusbr0

Le due regole ufw route consentono al traffico delle istanze di attraversare l'host e raggiungere Internet. Senza di esse, la policy di routing di ufw scarta i pacchetti inoltrati; i container ricevono quindi un indirizzo, ma non raggiungono alcuna destinazione.

Snapshot e profili

Uno snapshot è una copia dell'istanza in un preciso momento, archiviata nel relativo pool di storage.

incus snapshot create web pre-upgrade
incus info web
incus snapshot restore web pre-upgrade
incus snapshot delete web pre-upgrade

incus info web elenca gli snapshot presenti nell'istanza. Pianificali per ogni istanza.

incus config set web snapshots.schedule=@daily
incus config set web snapshots.expiry=4w

Uno snapshot risiede nello stesso pool, sullo stesso disco e nello stesso server. Protegge da un aggiornamento non riuscito. Non protegge da un disco guasto o dalla cancellazione dell'istanza. Il backup è incus export e il file deve essere trasferito fuori dal server.

incus export web /root/web-backup.tar.gz
incus import /root/web-backup.tar.gz

Un profilo è un insieme denominato di chiavi di configurazione e dispositivi applicato alle istanze. Ogni istanza riceve il profilo default, salvo diversa indicazione, e questo profilo fornisce il disco root e l'interfaccia di rete. La modifica di default interessa tutte le istanze che lo utilizzano. È utile, ma consente anche di scollegare la rete da venti container in una sola operazione.

incus profile create small
incus profile set small limits.memory=512MiB
incus profile set small limits.cpu=1
incus launch images:debian/13 api -p default -p small

I profili vengono applicati nell'ordine specificato. Se la stessa chiave è impostata in più profili, prevale il valore dell'ultimo profilo nell'elenco. Per verificare la configurazione effettiva di un'istanza, usa incus config show api --expanded.

Eseguire Docker all’interno di un container Incus

Docker all’interno di un container di sistema Incus richiede l’abilitazione del nesting, perché Docker crea namespace e mount propri che, per impostazione predefinita, un container non può creare.

incus config set web security.nesting=true
incus restart web

La documentazione di Incus descrive security.nesting come «Whether to allow nesting inside of the instance» e, per i container, il valore predefinito è false. Altri due aspetti sono riportati direttamente nelle FAQ di Incus. Un container non può caricare moduli del kernel. Pertanto, un modulo richiesto da Docker deve essere caricato sull’host e indicato con incus config set web linux.kernel_modules overlay,br_netfilter. Inoltre, la creazione di un file /.dockerenv all’interno del container fa sì che Docker salti alcuni controlli che in un ambiente annidato falliscono.

Sugli host Ubuntu 24.04, le restrizioni di AppArmor sugli user namespace non privilegiati possono bloccare pivot_root eseguito da runc. Docker all’interno del container stampa:

failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error jailing process inside rootfs: pivot_root .: permission denied

e dmesg sull’host mostra una riga contenente apparmor="DENIED" operation="pivotroot" class="mount". L’impostazione che viene normalmente modificata è kernel.apparmor_restrict_unprivileged_userns. Disabilitarla non è una correzione affidabile: il report del bug Incus upstream relativo a questo esatto diniego indica che impostarla su 0 non ha risolto il problema. Prima leggi dmesg per il diniego, così puoi verificare se AppArmor è davvero la causa prima di modificare un’impostazione di sicurezza predefinita.

Se preferisci eseguire i container direttamente sul VPS e rimuovere un livello, eseguire Docker su un VPS descrive questa configurazione separatamente.

Modalità di errore e messaggi visualizzati

Le istanze perdono completamente la rete dopo l'installazione di Docker sull'host. La documentazione di Incus indica la causa: "Docker imposta la policy globale FORWARD su drop, impedendo a Incus di inoltrare il traffico e causando così la perdita della connettività di rete delle istanze." Le istanze mantengono i propri indirizzi, ma non raggiungono alcuna destinazione. Imposta ip-forward-no-drop su true in /etc/docker/daemon.json, quindi rendi persistente l'inoltro e consenti il passaggio del bridge nella catena gestita da Docker.

echo "net.ipv4.conf.all.forwarding=1" | sudo tee /etc/sysctl.d/99-forwarding.conf
sudo systemctl restart systemd-sysctl
sudo iptables -I DOCKER-USER -i incusbr0 -j ACCEPT
sudo iptables -I DOCKER-USER -o incusbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Queste regole iptables non sopravvivono autonomamente a un riavvio. Rendile persistenti.

I container smettono di avviarsi con un errore cgroup. Le FAQ di Incus documentano anche questo caso. Un messaggio relativo a Failed to mount "/sys/fs/cgroup" indica in genere che un client VPN sull'host ha montato il controller cgroup v1 net_cls sopra cgroup v2, utilizzato da Incus. sudo umount /sys/fs/cgroup/net_cls risolve il problema.

L'istanza non riceve alcun indirizzo IPv4. incus list mostra che l'istanza è in esecuzione, ma la colonna degli indirizzi è vuota. Le risposte DHCP dall'host vengono scartate, nella maggior parte dei casi da un firewall dell'host che non riconosce il bridge. Con ufw, sudo ufw allow in on incusbr0 to any port 67 proto udp ripristina il funzionamento. Monitora l'arrivo delle richieste con sudo tcpdump -ni incusbr0 port 67.

L'istanza non si avvia su un VPS annidato. Leggi prima incus info <name> --show-log, quindi sudo journalctl -u incus -n 50. Se systemd-detect-virt restituisce lxc o openvz, il problema è sul lato del provider e nessuna impostazione interna al VPS può modificarlo.

Le snapshot sono lente e il disco continua a riempirsi. Stai utilizzando un pool dir. incus storage list visualizza il driver di ogni pool. Per passare a un pool copy-on-write devi creare il nuovo pool, copiare le istanze al suo interno con incus copy web web-new -s fast, quindi eliminare gli originali dopo aver verificato che le copie si avviino.

FAQ

Un container Incus è la stessa cosa di un container Docker?

No. Docker include un singolo processo o una singola applicazione in un pacchetto. Un container di sistema Incus simula un sistema operativo completo, con il proprio init, i propri utenti, i propri servizi e il proprio gestore dei pacchetti. Un container Incus viene mantenuto e aggiornato come un server. Un container Docker viene eliminato e ricreato a partire da un'immagine. È possibile eseguire Docker all'interno di un container Incus impostando security.nesting=true sul container. Il contrario non funziona.

Posso eseguire Incus su un VPS?

Su un VPS KVM, sì. Se systemd-detect-virt restituisce kvm o qemu, hai un kernel dedicato e Incus si comporta come su un server fisico. Se restituisce lxc, lxc-libvirt o openvz, il VPS è a sua volta un container. I container Incus al suo interno sono quindi annidati e funzionano solo se il provider ha abilitato il nesting sul tuo container. Controlla anche uname -r, perché ad agosto 2026 il ramo stabile corrente di Incus documenta un kernel minimo 6.12, mentre il ramo 6.0 LTS ne documenta uno 5.4.

Quale backend di storage dovrei scegliere per Incus su un VPS?

btrfs su un file loop, a meno che tu non disponga di un dispositivo a blocchi dedicato da assegnargli. Il driver dir è documentato come molto più lento degli altri, perché copia i file invece di usare il copy-on-write. Di conseguenza, ogni snapshot riscrive l'intero container. incus admin init --minimal seleziona dir, quindi vale la pena dedicare due minuti alle domande interattive. Crea il pool con incus storage create fast btrfs size=30GiB.

Perché il mio container Incus può raggiungere un servizio in esecuzione sull'host?

Perché il bridge incusbr0 predefinito colloca l'host sulla stessa subnet del container, all'indirizzo del gateway, e tra i due non viene applicato alcun filtro. Qualsiasi servizio dell'host in ascolto su 0.0.0.0 risponde a quell'indirizzo. Il firewall del provider non vede mai questi pacchetti, perché non lasciano la macchina. Associa i servizi dell'host a 127.0.0.1. Su un host con ufw, consenti in ingresso tramite incusbr0 soltanto DNS e DHCP, invece di usare la regola generale sudo ufw allow in on incusbr0.

Come posso eseguire il backup di un container Incus?

incus export web /root/web-backup.tar.gz scrive l'istanza e i relativi snapshot in un unico file, mentre incus import li ripristina sullo stesso server o su un altro. Gli snapshot creati con incus snapshot create non sono backup: restano nello stesso pool di storage e sullo stesso disco. Resistono quindi a un aggiornamento non riuscito, ma non al guasto del server. Pianificali con incus config set web snapshots.schedule=@daily e copia gli export fuori dal server.

#incus#lxd#system-containers#virtualization#vps