SSD Nodes Learn 🎉 VPS dès $5.50/mois
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-21

Installer des conteneurs système Incus sur un VPS

Installez Incus sur un VPS avec son init, ses utilisateurs et ses services. Vérifiez la virtualisation, configurez le stockage et le réseau, puis corrigez les pannes courantes.

Ce qu’est un conteneur système Incus

Les conteneurs système Incus sur un VPS fournissent une machine complète avec son propre système d’initialisation et ses propres comptes utilisateur. Il ne s’agit pas d’un processus unique auquel est associé un système de fichiers. Le conteneur démarre, exécute un processus d’initialisation en tant que PID 1 et répond à systemctl. Il partage le kernel de l’hôte ; ce n’est donc pas une machine virtuelle. Tout ce qui se trouve au-dessus du kernel se comporte comme sur une machine autonome.

Incus est le fork communautaire de LXD, maintenu dans le cadre du projet Linux Containers. La commande cliente est incus. Incus peut également exécuter de véritables machines virtuelles avec QEMU lorsque vous passez --vm, mais le conteneur système est la principale raison pour laquelle la plupart des utilisateurs l’installent. C’est aussi le sujet du reste de ce guide.

Pourquoi les comparaisons avec Docker induisent en erreur

Docker empaquette un processus. Incus empaquette un système d’exploitation. La documentation d’Incus établit clairement cette distinction : « Les conteneurs d’application (fournis par Docker, par exemple) empaquettent un seul processus ou une seule application. Les conteneurs système, en revanche, simulent un système d’exploitation complet, comme celui que vous exécuteriez sur un hôte ou dans une machine virtuelle. »

Cette différence modifie la façon dont vous utilisez le système au quotidien.

  • Une image Docker n’a pas d’init, donc systemctl échoue à l’intérieur. Un conteneur Incus exécute un système d’init, donc les services et les timers fonctionnent comme sur un serveur.
  • Un conteneur Docker est conçu pour être supprimé puis reconstruit depuis un Dockerfile. Un conteneur Incus est conçu pour être conservé, mis à jour et sauvegardé par snapshot.
  • Une image Docker est un artefact de build que vous poussez vers un registry. Une instance Incus correspond à un état stocké sur disque dans un pool de stockage, et vous la déplacez avec incus export.
  • Docker isole une charge de travail. Incus isole une machine : un conteneur peut donc héberger plusieurs charges de travail et plusieurs comptes utilisateur.

Vous pouvez exécuter Docker dans un conteneur système Incus. En revanche, vous n’exécuteriez pas Incus dans un conteneur d’application Docker. Si vous avez réellement besoin d’un processus par conteneur avec une étape de build d’image, Podman et Docker sur un VPS est la comparaison à consulter en premier. Si vous voulez un kernel distinct pour chaque charge de travail au lieu d’un kernel partagé, Les microVM Firecracker sur un VPS présente l’approche opposée.

Incus fonctionnera-t-il dans un VPS ?

Cela dépend du type de virtualisation de votre VPS et de son kernel. Vérifiez donc ces deux éléments avant toute installation. Ne vous fiez pas à la page commerciale de votre fournisseur. Exécutez ces quatre commandes sur le serveur.

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

systemd-detect-virt affichant kvm ou qemu signifie que votre VPS est une machine virtuelle avec son propre kernel. C’est le cas le plus simple, car Incus se comporte alors comme sur une machine physique. L’affichage de lxc, lxc-libvirt ou openvz signifie que votre VPS est lui-même un conteneur qui partage le kernel du fournisseur. Les conteneurs Incus qu’il contient sont des conteneurs imbriqués. L’imbrication ne fonctionne que si le fournisseur l’a activée pour votre conteneur. Vous ne pouvez pas l’activer depuis celui-ci, car ce paramètre se trouve sur l’hôte, auquel vous n’avez pas accès.

stat -fc %T /sys/fs/cgroup doit afficher cgroup2fs. Toute autre valeur signifie que le serveur utilise une organisation cgroup (control group) v1 ou hybride, que la version actuelle d’Incus ne prend pas en charge.

cat /sys/fs/cgroup/cgroup.controllers affiche les contrôleurs de control group qui vous sont délégués. La documentation d’Incus indique que blkio, cpuset, devices, freezer, memory et pids sont requis. Dans un VPS imbriqué, cette liste est souvent plus courte que dans un VPS KVM, car le fournisseur choisit les contrôleurs qu’il délègue. Un contrôleur absent de ce fichier est un contrôleur qu’Incus ne peut pas utiliser. La limite d’instances qui en dépend ne vous est donc pas disponible.

La version du kernel est plus importante qu’auparavant. En août 2026, la documentation d’Incus indique deux versions minimales différentes pour les deux branches maintenues en amont. La branche 6.0 LTS (long term support) indique : « The minimum supported kernel version is 5.4. » La branche stable actuelle indique : « The minimum supported kernel version is 6.12. » Ubuntu 24.04 fournit la série 6.0 LTS dans son propre repository et l’associe à un kernel 6.8, une combinaison prise en charge. Installer la version stable actuelle depuis le repository amont sur ce même kernel 6.8 vous place sous la version minimale documentée. Consultez donc uname -r avant de choisir un repository.

Si votre objectif est d’exécuter des machines virtuelles complètes plutôt que des conteneurs, la contrainte est différente et plus stricte. Consultez la virtualisation imbriquée dans un VPS pour vérifier si votre VPS peut exposer /dev/kvm, et Proxmox sur un VPS loué si vous possédez le matériel.

Installer Incus sur Ubuntu ou Debian

Debian 13, ainsi qu’Ubuntu 24.04 et les versions ultérieures, fournissent Incus dans leurs propres dépôts.

sudo apt update
sudo apt install -y incus

Sur Debian, incus-base installe la prise en charge des conteneurs sans les composants de machines virtuelles. Sur Ubuntu, ajoutez qemu-system si vous voulez également des instances --vm.

Pour utiliser une version plus récente que celle fournie par votre distribution, les paquets du projet sont disponibles à pkgs.zabbly.com. Ces commandes proviennent du README du dépôt officiel du projet.

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

Donnez ensuite à votre utilisateur l’accès au socket du daemon.

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

incus info affiche la configuration du serveur et confirme que le socket fonctionne. Une erreur de permission signifie que le changement de groupe n’a pas encore été pris en compte par votre shell. newgrp incus-admin l’applique au shell actuel, tandis qu’une nouvelle connexion l’applique correctement. Considérez l’appartenance à incus-admin comme équivalente à root sur l’hôte, car l’accès à ce socket donne le contrôle total d’un daemon qui s’exécute en tant que root. Certaines distributions créent également un groupe incus standard pour un accès utilisateur limité.

Initialisez maintenant le daemon.

sudo incus admin init

Répondez aux questions au lieu d’utiliser incus admin init --minimal. Le parcours minimal sélectionne le driver de stockage dir. La section suivante explique pourquoi ce choix vous accompagne ensuite.

Lancez quelque chose et vérifiez que cela fonctionne.

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

incus list doit afficher web comme RUNNING, avec une adresse IPv4 sur le sous-réseau incusbr0. L’absence d’adresse signifie que DHCP (Dynamic Host Configuration Protocol) n’a pas terminé, comme l’explique la section sur le réseau. Un conteneur qui ne démarre pas indique la raison dans incus info web --show-log, tandis que les erreurs au niveau du daemon apparaissent dans sudo journalctl -u incus -n 50. Sur un VPS où systemd-detect-virt a renvoyé lxc ou openvz, ce lancement vérifie réellement si la nesting est disponible pour vous.

Pourquoi le backend de stockage par défaut est important

Le backend de stockage détermine si un snapshot est instantané ou s’il correspond à une copie complète du disque du conteneur. C’est le seul choix effectué lors de l’installation qu’il est difficile de modifier ultérieurement à faible coût.

Incus prend en charge dir, btrfs, lvm, zfs, Ceph et plusieurs drivers distants. Sur un VPS doté d’un seul disque, le choix réel se fait entre dir et btrfs.

Le driver dir conserve chaque conteneur sous forme de fichiers et de répertoires ordinaires dans /var/lib/incus. Incus le décrit comme « beaucoup plus lent que tous les autres drivers », car il doit décompresser chaque image et créer de véritables copies au lieu de référencer des blocs partagés. Un snapshot d’un conteneur de 4 GiB écrit 4 GiB et prend autant de temps que cp -a. Les quotas disque fonctionnent uniquement sur ext4 ou XFS avec les project quotas activés au niveau du système de fichiers. Ils ne sont généralement pas activés par défaut sur la plupart des images VPS. Une limite disque définie sur un pool dir n’a donc souvent aucun effet.

btrfs et zfs utilisent la copie sur écriture. Un snapshot enregistre uniquement les blocs modifiés après sa création. Incus recommande ces deux backends. Les snapshots deviennent presque instantanés. Les quotas disque utilisent la prise en charge native des quotas du système de fichiers.

La plupart des offres VPS fournissent un seul disque sans partition disponible supplémentaire. Il faut donc placer le pool dans un fichier loop. Incus s’en charge si vous ne fournissez aucun 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

Sans size=, un pool basé sur loop utilise 20% de l’espace disque libre, avec un minimum de 5 GiB et un maximum de 30 GiB. Définissez cette valeur explicitement. Le fichier loop se trouve sur le système de fichiers racine. Le pool et l’hôte partagent donc le même espace libre. Si le pool est rempli, le disque de l’hôte est lui aussi rempli.

Sous Debian et Ubuntu, ZFS est un module DKMS et non un module intégré au noyau. Il est donc recompilé à chaque mise à niveau du noyau et cette compilation peut échouer. Sur un serveur que vous ne surveillez pas quotidiennement, btrfs demande moins de maintenance que l’autre option.

Les trois modes réseau et ce que chacun expose

incus admin init crée un bridge géré appelé incusbr0 et y place chaque nouvelle instance. Il s’agit de l’une des trois façons de connecter un conteneur. Les deux autres existent parce que le premier mode masque vos conteneurs derrière du NAT (network address translation).

Bridge géré. incusbr0 reçoit un sous-réseau privé. L’hôte en détient la première adresse et sert de gateway. Incus y fournit DHCP et DNS (domain name system). Le trafic sortant passe par l’adresse publique de l’hôte avec application d’un SNAT. Rien venant de l’extérieur n’atteint le conteneur tant que vous ne l’autorisez pas. Pour rediriger un port, utilisez un périphérique proxy.

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 effectue la redirection avec des règles netfilter au lieu de passer par une connexion userspace distincte. La véritable adresse du client reste donc visible dans les journaux du conteneur. Incus ne prend en charge ce mode que lorsque l’hôte est la gateway de l’instance, ce qui correspond exactement au cas incusbr0.

macvlan. Le conteneur reçoit sa propre adresse MAC (media access control) sur le réseau physique de l’hôte. Sur la plupart des plateformes VPS, cela échoue, car le port du virtual switch est associé à l’adresse MAC de votre VM et ignore les trames provenant d’une autre adresse. Une deuxième limitation pose problème, même lorsque ce mode fonctionne. Incus précise que « les périphériques macvlan peuvent communiquer entre eux et avec l’extérieur, mais pas avec leur périphérique parent. Vous ne pouvez donc pas utiliser macvlan si vos instances doivent communiquer avec l’hôte lui-même ».

Routed. C’est généralement le mode qui fonctionne sur un VPS disposant d’adresses supplémentaires. Incus décrit ce périphérique comme un mécanisme qui « crée une paire de périphériques virtuels pour connecter l’hôte à l’instance et configure des routes statiques ainsi que des entrées proxy ARP/NDP afin de permettre à l’instance de rejoindre le réseau d’une interface parent désignée ». ARP est l’address resolution protocol. Le conteneur conserve une adresse publique. L’hôte répond aux requêtes ARP pour cette adresse. Le fournisseur ne voit donc toujours que l’adresse MAC de l’hôte.

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

Relevez le nom de l’interface parent dans ip route show default. Les images actuelles utilisent des noms comme enp1s0 ou ens3, et rarement eth0. Le fait de nommer le périphérique eth0 remplace celui fourni par le profil default. Le conteneur utilise donc l’interface routée au lieu du bridge. Vérifiez le résultat depuis l’intérieur avec ip a et ip route.

Pourquoi un conteneur a pu atteindre un service sur l’hôte

Un conteneur sur incusbr0 possède son propre espace de noms réseau. Il n’a pas de frontière firewall avec l’hôte. L’hôte se trouve sur ce bridge à l’adresse de gateway. Depuis le conteneur, il est donc directement accessible, et tous les services de l’hôte liés à 0.0.0.0 y répondent.

Vérifiez-le vous-même. Sur l’hôte, listez les services en écoute.

sudo ss -tlnp

Ensuite, depuis un conteneur, ciblez la gateway indiquée par ip route.

ip route show default
nc -zv 10.0.0.1 6379

Si une base de données, un endpoint de métriques ou un panneau d’administration sur l’hôte est lié à 0.0.0.0, le test réussit. Le firewall réseau de votre fournisseur n’a jamais vu le paquet, car celui-ci n’a pas quitté la machine. C’est ce qui explique la plupart des questions du type « comment a-t-il pu atteindre ce service ? » : le conteneur est isolé d’Internet par le NAT, mais rien ne l’isole de l’hôte.

Liez les services de l’hôte à 127.0.0.1 partout où c’est possible. Filtrez ensuite le bridge sur l’hôte. Sur une machine utilisant ufw, la stratégie par défaut deny bloque déjà le trafic des conteneurs vers l’hôte. Cela empêche le DNS et le DHCP d’Incus de fonctionner. La documentation d’Incus indique sudo ufw allow in on incusbr0 comme correctif. Cette seule commande rouvre tous les ports de l’hôte à tous les conteneurs. Autorisez plutôt uniquement les services dont les conteneurs ont réellement besoin.

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

Les deux règles ufw route permettent au trafic des instances de traverser l’hôte vers Internet. Sans elles, la stratégie routed de ufw rejette les paquets transférés. Les conteneurs obtiennent donc une adresse, mais ne peuvent rien atteindre.

Instantanés et profils

Un snapshot est une copie de l’instance à un instant donné, stockée dans son pool de stockage.

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

incus info web liste les snapshots détenus par l’instance. Planifiez-les pour chaque instance.

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

Un snapshot se trouve dans le même pool, sur le même disque et sur le même serveur. Il vous protège contre une mise à niveau défectueuse. Il ne vous protège pas contre une panne de disque ni contre la suppression de l’instance. La sauvegarde est incus export, et le fichier doit quitter le serveur.

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

Un profil est un ensemble nommé de clés de configuration et de périphériques appliqué aux instances. Chaque instance reçoit le profil default, sauf indication contraire. Ce profil fournit son disque racine et son interface réseau. Modifier default modifie toutes les instances qui l’utilisent. C’est utile, mais cela permet aussi de détacher le réseau de vingt conteneurs en une seule fois.

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

Les profils sont appliqués dans l’ordre. Une clé définie dans le dernier profil listé est donc prioritaire. Utilisez incus config show api --expanded pour voir la configuration réellement obtenue par une instance.

Exécuter Docker dans un conteneur Incus

Docker dans un conteneur système Incus nécessite l’activation de l’imbrication, car Docker crée ses propres namespaces et mounts, ce qu’un conteneur ne peut pas faire par défaut.

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

Incus décrit security.nesting comme « Autoriser l’imbrication dans l’instance », et cette option vaut false par défaut pour les conteneurs. Deux autres points viennent directement de la FAQ Incus. Un conteneur ne peut pas charger de modules du kernel. Un module requis par Docker doit donc être chargé sur l’hôte et indiqué avec incus config set web linux.kernel_modules overlay,br_netfilter. La création d’un fichier /.dockerenv dans le conteneur permet également à Docker d’ignorer certains contrôles qui échouent dans un environnement imbriqué.

Sur les hôtes Ubuntu 24.04, les restrictions AppArmor concernant les user namespaces non privilégiés peuvent bloquer le pivot_root effectué par runc. Docker dans le conteneur affiche :

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

et le dmesg de l’hôte contient une ligne avec apparmor="DENIED" operation="pivotroot" class="mount". Le paramètre auquel on pense est kernel.apparmor_restrict_unprivileged_userns. Le désactiver n’est pas une solution fiable : le rapport de bug Incus en amont consacré exactement à ce refus indique que sa valeur 0 n’a pas résolu le problème. Consultez d’abord dmesg pour ce refus, afin de vérifier qu’AppArmor est réellement en cause avant de modifier un paramètre de sécurité par défaut.

Si vous préférez exécuter les conteneurs directement sur le VPS et supprimer une couche, la page Exécuter Docker sur un VPS décrit cette configuration séparément.

Modes d’échec et messages affichés

Les instances perdent tout accès réseau après l’installation de Docker sur l’hôte. La documentation d’Incus en indique la cause : « Docker définit la policy globale FORWARD sur drop, ce qui empêche Incus de transférer le trafic et fait donc perdre leur connectivité réseau aux instances. » Les instances conservent leurs adresses, mais ne joignent plus rien. Définissez ip-forward-no-drop sur true dans /etc/docker/daemon.json, puis rendez le forwarding persistant et autorisez le bridge dans la propre chaîne de 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

Ces règles iptables ne survivent pas à un reboot. Rendez-les persistantes.

Les conteneurs ne démarrent plus à cause d’une erreur cgroup. La FAQ d’Incus documente ce cas. Un message concernant Failed to mount "/sys/fs/cgroup" signifie généralement qu’un client VPN sur l’hôte a monté le contrôleur cgroup v1 net_cls par-dessus cgroup v2, qu’utilise Incus. sudo umount /sys/fs/cgroup/net_cls corrige le problème.

L’instance n’obtient aucune adresse IPv4. incus list l’affiche comme active, avec une colonne d’adresses vide. Les réponses DHCP de l’hôte sont bloquées, le plus souvent par un firewall sur l’hôte qui ne connaît pas le bridge. Avec ufw, sudo ufw allow in on incusbr0 to any port 67 proto udp rétablit le fonctionnement. Surveillez l’arrivée des requêtes avec sudo tcpdump -ni incusbr0 port 67.

L’instance refuse de démarrer sur un VPS imbriqué. Consultez d’abord incus info <name> --show-log, puis sudo journalctl -u incus -n 50. Si systemd-detect-virt indiquait lxc ou openvz, le problème vient du fournisseur et aucun réglage dans votre VPS ne peut le résoudre.

Les snapshots sont lents et le disque continue de se remplir. Vous utilisez un pool dir. incus storage list affiche le driver de chaque pool. Migrer vers un pool copy-on-write consiste à créer le nouveau pool, à y copier les instances avec incus copy web web-new -s fast, puis à supprimer les originales après avoir vérifié que les copies démarrent.

FAQ

Un conteneur Incus est-il la même chose qu’un conteneur Docker ?

Non. Docker empaquette un seul processus ou une seule application. Un conteneur système Incus simule un système d’exploitation complet, avec son propre init, ses propres utilisateurs, ses propres services et son propre gestionnaire de paquets. Vous conservez un conteneur Incus et vous le mettez à jour comme un serveur. Vous supprimez un conteneur Docker et vous le recréez à partir d’une image. Vous pouvez exécuter Docker dans un conteneur Incus en définissant security.nesting=true sur le conteneur. L’inverse ne fonctionne pas.

Puis-je exécuter Incus sur un VPS ?

Sur un VPS KVM, oui. Si systemd-detect-virt affiche kvm ou qemu, vous disposez de votre propre noyau et Incus se comporte comme sur une machine physique. S’il affiche lxc, lxc-libvirt ou openvz, votre VPS est lui-même un conteneur. Les conteneurs Incus qu’il contient sont donc imbriqués et ne fonctionnent que si le fournisseur a activé l’imbrication sur votre conteneur. Vérifiez également uname -r, car en août 2026 la branche stable actuelle d’Incus documente un noyau minimal en version 6.12, tandis que la branche LTS 6.0 documente la version 5.4.

Quel backend de stockage choisir pour Incus sur un VPS ?

btrfs sur un fichier loop, sauf si vous disposez d’un périphérique bloc dédié. Le pilote dir est documenté comme beaucoup plus lent que les autres, car il copie les fichiers au lieu d’utiliser le copy-on-write. Chaque snapshot réécrit donc tout le conteneur. incus admin init --minimal sélectionne dir, ce qui justifie de consacrer deux minutes aux questions interactives. Créez le pool avec incus storage create fast btrfs size=30GiB.

Pourquoi mon conteneur Incus peut-il atteindre un service exécuté sur l’hôte ?

Parce que le bridge incusbr0 par défaut place l’hôte sur le même sous-réseau que le conteneur, à l’adresse de la gateway, et qu’aucun filtrage ne s’effectue entre eux. Tout service de l’hôte lié à 0.0.0.0 répond à cette adresse. Le firewall de votre fournisseur ne voit jamais ces paquets, car ils ne quittent pas la machine. Liez les services de l’hôte à 127.0.0.1. Sur un hôte utilisant ufw, autorisez uniquement DNS et DHCP en entrée sur incusbr0, au lieu d’utiliser l’autorisation générale sudo ufw allow in on incusbr0.

Comment sauvegarder un conteneur Incus ?

incus export web /root/web-backup.tar.gz écrit l’instance et ses snapshots dans un seul fichier, et incus import la restaure sur le même serveur ou sur un autre. Les snapshots créés avec incus snapshot create ne sont pas des sauvegardes. Ils se trouvent dans le même pool de stockage, sur le même disque. Ils résistent donc à une mise à jour défectueuse, mais pas à une panne du serveur. Planifiez-les avec incus config set web snapshots.schedule=@daily et copiez les exports hors de la machine.

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