Tutos

Déployer une VM Debian sur Proxmox avec Terraform

Les fichiers, le token d'API créé dans l'interface Proxmox, trois commandes. Simple et direct.

  • Niveau débutant
  • 30 min
  • Mis à jour le 3 octobre 2026

Objectif : une commande, et une VM Debian 13 tourne sur ton Proxmox avec une IP fixe et ta clé SSH. Terraform parle à Proxmox par son API avec un token ; Proxmox télécharge l'image Debian officielle et crée la VM.

Avant de commencer
  • Proxmox VE 9 et un accès root à l'interface web.
  • Terraform installé sur ton poste (terraform -version) : guide d'installation officiel.
  • Une clé SSH sur ton poste. Sinon : ssh-keygen -t ed25519.

Arborescence du projet

proxmox-debian/
proxmox-debian/
├── provider.tf        connexion à Proxmox
├── variables.tf       liste des paramètres
├── terraform.tfvars   tes valeurs (nœud, IP...)
├── main.tf            image Debian + VM
└── outputs.tf         commande SSH affichée à la fin
Ton poste
mkdir proxmox-debian && cd proxmox-debian

Le contenu des fichiers

Copie chaque bloc dans le fichier du même nom. Tu n'as à modifier que terraform.tfvars.

provider.tf
terraform {
  required_providers {
    proxmox = {
      source  = "bpg/proxmox"
      version = "~> 0.114.0"
    }
  }
}

provider "proxmox" {
  # Adresse et token lus dans PROXMOX_VE_ENDPOINT et PROXMOX_VE_API_TOKEN
  insecure = true # certificat auto-signé de Proxmox
}
variables.tf
variable "proxmox_node" {
  description = "Nom du nœud Proxmox"
  type        = string
}

variable "vm_id" {
  description = "ID libre pour la VM"
  type        = number
}

variable "vm_name" {
  description = "Nom de la VM"
  type        = string
}

variable "ip" {
  description = "IP de la VM avec le masque, ex. 192.168.1.50/24"
  type        = string
}

variable "gateway" {
  description = "Passerelle du réseau"
  type        = string
}

variable "ssh_key" {
  description = "Chemin de ta clé SSH publique"
  type        = string
  default     = "~/.ssh/id_ed25519.pub"
}
terraform.tfvars
proxmox_node = "pve"
vm_id        = 210
vm_name      = "debian-01"
ip           = "192.168.1.50/24"
gateway      = "192.168.1.1"
main.tf
# 1. Proxmox télécharge l'image cloud Debian 13
resource "proxmox_download_file" "debian_13" {
  node_name    = var.proxmox_node
  datastore_id = "local"
  content_type = "import"
  url          = "https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2"
  file_name    = "debian-13-genericcloud-amd64.qcow2"
  overwrite    = false
}

# 2. La VM, créée à partir de cette image
resource "proxmox_virtual_environment_vm" "debian" {
  node_name       = var.proxmox_node
  vm_id           = var.vm_id
  name            = var.vm_name
  stop_on_destroy = true

  cpu {
    cores = 2
    type  = "x86-64-v2-AES"
  }

  memory {
    dedicated = 2048 # Mo
  }

  disk {
    datastore_id = "local-lvm"
    import_from  = proxmox_download_file.debian_13.id
    interface    = "scsi0"
    size         = 20 # Go
  }

  network_device {
    bridge = "vmbr0"
  }

  serial_device {} # obligatoire pour les images cloud Debian

  # cloud-init : réseau, utilisateur et clé SSH au premier démarrage
  initialization {
    datastore_id = "local-lvm"

    dns {
      servers = ["1.1.1.1", "9.9.9.9"]
    }

    ip_config {
      ipv4 {
        address = var.ip
        gateway = var.gateway
      }
    }

    user_account {
      username = "debian"
      keys     = [trimspace(file(pathexpand(var.ssh_key)))]
    }
  }
}
outputs.tf
output "ssh" {
  value = "ssh debian@${split("/", var.ip)[0]}"
}
Les 3 valeurs à adapter à ton Proxmox
  • local-lvm : ton stockage de disques (peut être local-zfs).
  • vmbr0 : ton bridge réseau.
  • proxmox_node : le nom affiché sous Datacenter dans l'arbre de gauche.

Autoriser les images sur le stockage local

Proxmox doit pouvoir ranger l'image Debian dans local. Dans l'interface web : Datacenter › Storage › local › Edit.

Dans Content, ajoute Import à ce qui est déjà sélectionné, puis OK.

Reproduction de la fenêtre Proxmox (pas de capture officielle pour cet écran). En rouge : ce que tu remplis.

Pour vérifier : local › Summary, la ligne Content doit maintenant contenir Import.

Résumé du stockage local dans Proxmox
Bloc Status de local › Summary, recadré (le pointillé marque la coupe). La ligne Content liste les types autorisés ; après ta modification, Import doit y apparaître. Capture : documentation officielle Proxmox VE, © Proxmox Server Solutions GmbH, AGPLv3.

Créer le rôle Terraform

Datacenter › Permissions › Roles › Create. Nom : TerraformProv. Dans Privileges, coche ces privilèges :

Privilèges à cocher
Datastore.Allocate
Datastore.AllocateSpace
Datastore.AllocateTemplate
Datastore.Audit
Pool.Allocate
Pool.Audit
SDN.Use
Sys.Audit
Sys.Console
Sys.Modify
VM.Allocate
VM.Audit
VM.Clone
VM.Config.CDROM
VM.Config.Cloudinit
VM.Config.CPU
VM.Config.Disk
VM.Config.HWType
VM.Config.Memory
VM.Config.Network
VM.Config.Options
VM.Console
VM.GuestAgent.Audit
VM.Migrate
VM.PowerMgmt
Fenêtre Create: Role de Proxmox
La fenêtre Create: Role. Le champ Privileges est une liste à cocher. Capture : documentation officielle Proxmox VE, © Proxmox Server Solutions GmbH, AGPLv3.
VM.Monitor

Si un ancien tuto te dit de cocher VM.Monitor : ce privilège n'existe plus sur Proxmox 9, ignore-le.

Créer l'utilisateur

Datacenter › Permissions › Users › Add.

Reproduction de la fenêtre Proxmox (pas de capture officielle pour cet écran). En rouge : ce que tu remplis.

Le compte complet s'appelle terraform@pve. Le mot de passe ne servira pas à Terraform (il utilise le token), mais il est demandé.

Donner le rôle à l'utilisateur

Datacenter › Permissions › Add › User Permission.

Reproduction de la fenêtre Proxmox (pas de capture officielle pour cet écran). En rouge : ce que tu remplis.

Path / avec Propagate coché : le droit s'applique à tout le Proxmox (nœuds, stockages, VM).

Créer le token d'API

Datacenter › Permissions › API Tokens › Add.

Reproduction de la fenêtre Proxmox (pas de capture officielle pour cet écran). En rouge : ce que tu remplis.
Décoche Privilege Separation

C'est l'oubli le plus courant. Coché, le token n'a aucun droit tant qu'on ne lui en donne pas séparément, et Terraform reçoit des erreurs 403. Décoché, il reprend les droits de terraform@pve.

Après Add, Proxmox affiche le secret :

Reproduction de la fenêtre Proxmox (pas de capture officielle pour cet écran). En rouge : ce que tu copies.
Affiché une seule fois

Copie le secret maintenant. Si tu fermes la fenêtre sans l'avoir noté, supprime le token et recrées-en un.

Lancer la création

Dans le dossier proxmox-debian, donne l'adresse et le token à Terraform. Remplace l'IP et le secret par les tiens :

Ton poste
export PROXMOX_VE_ENDPOINT='https://192.168.1.10:8006/'
export PROXMOX_VE_API_TOKEN='terraform@pve!provider=3f6c1a2e-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

Format du token : Token ID + = + Secret. Garde les guillemets simples, à cause du !.

Ton poste
terraform init      # télécharge le provider Proxmox
terraform plan      # montre ce qui va être créé
terraform apply     # crée, après avoir tapé yes

Le plan doit finir par :

Sortie attendue
Plan: 2 to add, 0 to change, 0 to destroy.

Et l'apply, au bout d'une à quelques minutes :

Sortie attendue
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

ssh = "ssh [email protected]"

Vérifier

Dans Proxmox, la VM 210 apparaît dans l'arbre. Son onglet Cloud-Init reprend tes paramètres : utilisateur, clé SSH, IP et passerelle.

Onglet Cloud-Init d'une VM Proxmox
L'onglet Cloud-Init d'une VM : on y retrouve l'utilisateur, la clé SSH et la configuration IP. Capture : documentation officielle Proxmox VE, © Proxmox Server Solutions GmbH, AGPLv3.

Attends une minute que la VM finisse de démarrer, puis connecte-toi avec la commande affichée par Terraform :

Ton poste
ssh [email protected]
cloud-init status   # doit répondre : status: done

Supprimer la VM

Ton poste
terraform destroy   # supprime la VM et l'image, après avoir tapé yes

Pour recréer : terraform apply. C'est tout l'intérêt : la VM se reconstruit à l'identique quand tu veux.

Si ça bloque

MessageSolution
401Token ou secret mal copié. Refais les export avec des guillemets simples.
403 Permission check failedPrivilege Separation est resté coché (étape 7), ou un privilège manque dans le rôle (étape 4).
Erreur sur le contenu importImport n'est pas activé sur le stockage local (étape 3).
VM 210 already existsChange vm_id dans terraform.tfvars.
SSH refuséAttends que cloud-init termine, et vérifie que ssh_key pointe sur ta clé publique.