La première semaine avec Proxmox, j’ai créé toutes mes machines en VM. Par réflexe, par habitude des hyperviseurs classiques. Au bout de quelques jours, le nœud tournait avec 14 Go de RAM utilisée pour huit services qui auraient pu tenir dans 4 Go en LXC. J’ai tout défait et recommencé.
La distinction VM / LXC n’est pas une question de préférence – c’est de l’architecture. Voilà comment j’y pense aujourd’hui.
VM ou LXC : la vraie différence
Une VM KVM est une machine complète émulée. Elle a son propre noyau Linux (ou Windows, ou FreeBSD), son propre espace mémoire isolé, ses propres processus init. Proxmox ne voit qu’un processus QEMU par VM. L’isolation est maximale.
Un container LXC partage le noyau de l’hôte Proxmox. Chaque LXC a son propre espace de noms (PID, réseau, filesytem), mais il n’y a pas d’émulation matérielle. Démarrage en 2 secondes au lieu de 30. Overhead mémoire quasi nul. Et si un service dans le LXC a besoin de plus de RAM, Proxmox lui en donne sans négociation noyau.
La règle que j’applique :
- LXC pour tout ce qui est Linux et ne nécessite pas de noyau custom : Pi-hole, Nginx, bases de données, Gitea, Vaultwarden, monitoring.
- VM pour Windows (évidemment), pour Home Assistant OS (HAOS – Proxmox a des templates VM officiels), pour tout ce qui a besoin d’un noyau spécifique ou de PCI passthrough.
- VM aussi pour Docker si on veut faire tourner des containers Docker dans Proxmox – techniquement possible en LXC non-privileged avec
nesting=1, mais c’est un coin qui mord.
La différence de consommation mémoire est réelle. Un LXC Debian 12 minimal avec Pi-hole installé : ~90 Mo de RAM utilisée. La même chose en VM Ubuntu : ~512 Mo minimum, souvent 800 Mo en pratique.
Télécharger les templates LXC
Proxmox n’inclut pas les templates par défaut. On les télécharge depuis l’interface web ou en CLI :
# Mettre à jour la liste des templates disponibles
pveam update
# Voir ce qui est disponible
pveam available | grep -E "debian|ubuntu|alpine"
# Télécharger Debian 12 et Ubuntu 24.04
pveam download local debian-12-standard12.7-1amd64.tar.zst
pveam download local ubuntu-24.04-standard24.04-2amd64.tar.zst
Les templates sont stockés dans /var/lib/vz/template/cache/. On les retrouve dans l’interface web sous local > CT Templates.
Créer son premier LXC
Je me sers de la CLI pour la création – c’est plus rapide à documenter et à rejouer. L’interface web fait la même chose avec une GUI.
pct create 150 local:vztmpl/debian-12-standard12.7-1amd64.tar.zst
--hostname pihole
--memory 512
--cores 1
--net0 name=eth0,bridge=vmbr0,ip=192.168.1.150/24,gw=192.168.1.1
--storage local-lvm
--rootfs local-lvm:4
--unprivileged 1
--features nesting=1
--onboot 1
pct start 150
pct enter 150
Quelques points sur ces options :
--unprivileged 1 – toujours. Un LXC privileged tourne avec les droits root réels de l’hôte. Une fuite de container privileged donne accès root au nœud Proxmox. Pas pour un homelab.
--features nesting=1 – nécessaire si on veut faire tourner Docker ou des containers dans le LXC. Pas nécessaire pour Pi-hole ou Nginx.
--onboot 1 – le LXC démarre automatiquement au démarrage de Proxmox. À activer pour les services critiques (Pi-hole, Nginx Proxy Manager).
Créer sa première VM Ubuntu avec cloud-init
Pour les VMs Linux, cloud-init change la donne. Au lieu de passer par l’installeur interactif à chaque nouvelle VM, on télécharge une image cloud, on l’importe, on configure cloud-init une fois, et on clone à volonté.
# Télécharger l'image cloud Ubuntu 24.04 LTS (Noble)
cd /tmp
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
# Créer la VM template (ID 9000 par convention)
qm create 9000
--name ubuntu-24.04-template
--memory 2048
--cores 2
--net0 virtio,bridge=vmbr0
--scsihw virtio-scsi-pci
--agent enabled=1
# Importer le disque
qm importdisk 9000 noble-server-cloudimg-amd64.img local-lvm
# Configurer le disque et cloud-init
qm set 9000
--scsi0 local-lvm:vm-9000-disk-0,discard=on,ssd=1
--ide2 local-lvm:cloudinit
--boot order=scsi0
--serial0 socket
--vga serial0
# Configurer cloud-init
qm set 9000
--ciuser pascal
--sshkeys ~/.ssh/authorized_keys
--ipconfig0 ip=dhcp
# Convertir en template
qm template 9000
Pour créer une nouvelle VM à partir de ce template :
qm clone 9000 200 --name mon-service --full
qm set 200 --memory 1024 --cores 1
qm set 200 --ipconfig0 ip=192.168.30.200/24,gw=192.168.30.1
qm start 200
La VM est disponible en SSH dans les 30 secondes suivant le démarrage, sans passer par un installeur.
Convention de nommage et d’IDs
J’utilise une convention d’IDs pour m’y retrouver :
100–149 : Infrastructure et réseau (Pi-hole, Nginx Proxy Manager, VPN)
150–199 : Services internes (Pi-hole est en 150, c'est son slot)
200–299 : Services auto-hébergés (Nextcloud, Gitea, Jellyfin...)
300–399 : VMs Linux (monitoring, outils)
700–799 : VMs Windows (si besoin)
9000–9099 : Templates
Les noms : j’essaie de mettre le nom du service, pas un nom cryptique. pihole, npm (Nginx Proxy Manager), grafana, nextcloud. Pas vm-01, vm-02.
Snapshots avant toute mise à jour
Un snapshot LXC ou VM prend quelques secondes et ne coûte rien tant qu’on a de l’espace.
# Snapshot d'un LXC avant mise à jour
pct snapshot 150 avant-pihole-update --description "Pi-hole 5.18, avant upgrade 5.19"
# Si la mise à jour casse quelque chose
pct rollback 150 avant-pihole-update
# Lister les snapshots
pct listsnapshot 150
Pour les VMs :
qm snapshot 200 avant-upgrade --description "Avant apt dist-upgrade Debian 12.7"
qm rollback 200 avant-upgrade
Ce qui a coincé
La première VM cloud-init, cloud-init ne s’exécutait pas au démarrage. Après 20 minutes à chercher, la cause : j’avais oublié d’attacher le disque cloud-init à la VM (--ide2 local-lvm:cloudinit). Sans ce disque, QEMU ne transmet pas les données cloud-init à l’image. Le hostname restait ubuntu, le user ubuntu (pas pascal), pas de clé SSH.
La commande manquante pour vérifier :
qm config 200 | grep ide2
# Doit retourner : ide2: local-lvm:vm-200-disk-1,media=cdrom
Depuis, je vérifie systématiquement que ide2 est bien configuré avant de démarrer un template cloné.
Résultat après une semaine de migration
En repassant les services de VMs vers LXC là où c’était pertinent, j’ai libéré ~8 Go de RAM sur le nœud. Avec 32 Go au total, j’ai maintenant ~20 Go disponibles pour les workloads réels, contre ~12 Go avant. La consommation idle du nœud est passée de ~35% à ~22% de RAM selon Proxmox.
Série « Homelab Proxmox MS-01 » – Article 3/10