Vous gérez encore vos serveurs à la main, via une console web ou des scripts bricolés ? Il est temps de passer à l’étape suivante. Terraform est l’outil de référence pour décrire, provisionner et gérer votre infrastructure de manière déclarative, reproductible et versionnée.
Ce guide vous accompagne pas à pas, de l’installation jusqu’au déploiement concret d’un serveur chez Hetzner, en passant par la gestion du state et l’introduction aux modules. Aucun prérequis cloud exotique : on reste sur des providers européens accessibles.
Qu’est-ce que Terraform ?
Terraform est un outil open source créé par HashiCorp en 2014. Il permet de définir votre infrastructure sous forme de code (Infrastructure as Code, ou IaC) dans un langage déclaratif appelé HCL (HashiCorp Configuration Language).
Le principe est simple : vous décrivez l’état souhaité de votre infrastructure dans des fichiers .tf, et Terraform se charge de créer, modifier ou supprimer les ressources nécessaires pour atteindre cet état.
Pourquoi adopter Terraform ?
- Reproductibilité — Le même code produit la même infrastructure, à chaque fois. Fini les « ça marchait sur mon setup ».
- Versionnement — Votre infra vit dans Git, avec historique, reviews et rollback.
- Multi-provider — Un seul outil pour Hetzner, Infomaniak, Cloudflare, et des centaines d’autres.
- Planification — Terraform montre exactement ce qu’il va faire avant de le faire (
plan). - Collaboration — Toute l’équipe travaille sur la même base de code, avec des conventions partagées.
Terraform vs Ansible, Pulumi et les autres
Terraform n’est pas le seul outil d’IaC, mais il occupe une place bien définie :
| Outil | Approche | Force principale |
|---|---|---|
| Terraform | Déclaratif, provisionnement | Gestion du cycle de vie des ressources cloud |
| Ansible | Impératif/déclaratif, configuration | Configuration des serveurs une fois créés |
| Pulumi | Impératif (langages généraux) | IaC en Python, Go, TypeScript |
En pratique, Terraform et Ansible sont souvent complémentaires : Terraform crée les serveurs, Ansible les configure.
Installation de Terraform
Terraform est un binaire unique, sans dépendance. L’installation prend moins d’une minute.
Sur macOS (Homebrew)
# Installation via Homebrew — la méthode recommandée sur macOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
Sur Linux (Debian/Ubuntu)
# Ajout du dépôt officiel HashiCorp
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring-hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
Vérification
# Vérifiez que Terraform est bien installé
terraform version
# Terraform v1.x.x
Astuce : Utilisez tfenv pour gérer plusieurs versions de Terraform en parallèle, surtout si vous travaillez sur plusieurs projets.
Les concepts fondamentaux
Avant d’écrire du code, quelques notions essentielles à comprendre.
Providers
Un provider est un plugin qui permet à Terraform de communiquer avec une API. Chaque service (Hetzner, Cloudflare, GitHub…) a son propre provider. C’est le pont entre votre code HCL et l’infrastructure réelle.
Resources
Une resource représente un élément d’infrastructure : un serveur, un réseau, un enregistrement DNS, un volume de stockage. Chaque resource a un type (défini par le provider) et des attributs configurables.
State (état)
Le state est un fichier JSON (terraform.tfstate) qui contient la cartographie entre vos resources déclarées et les ressources réelles qui existent chez le provider. C’est la mémoire de Terraform — on y reviendra en détail plus loin.
Le workflow Terraform
Le cycle de travail avec Terraform suit trois commandes clés :
# 1. Initialiser le projet (télécharge les providers)
terraform init
# 2. Prévisualiser les changements
terraform plan
# 3. Appliquer les changements
terraform apply
Ce workflow init → plan → apply deviendra votre routine quotidienne.
Premier projet : un serveur Hetzner
Passons à la pratique. Nous allons déployer un serveur cloud chez Hetzner, un hébergeur allemand réputé pour ses prix compétitifs et ses datacenters européens (Falkenstein, Nuremberg, Helsinki, Ashburn).
Prérequis
- Un compte Hetzner Cloud (inscription gratuite)
- Un API token généré dans la console Hetzner (Cloud Console → Projet → Security → API Tokens → Generate API Token avec permissions Read & Write)
Structure du projet
Créez un répertoire propre pour votre premier projet :
mkdir terraform-hetzner-demo && cd terraform-hetzner-demo
Nous allons créer trois fichiers — une convention classique en Terraform :
terraform-hetzner-demo/
├── main.tf # Ressources principales
├── variables.tf # Déclaration des variables
└── outputs.tf # Valeurs de sortie
Configurer le provider Hetzner
Commençons par variables.tf pour déclarer nos variables :
# variables.tf — Déclaration des variables du projet
variable "hcloud_token" {
description = "Token API Hetzner Cloud"
type = string
sensitive = true # Masque la valeur dans les logs
}
variable "server_name" {
description = "Nom du serveur"
type = string
default = "web-01"
}
variable "server_type" {
description = "Type d'instance Hetzner (cpx11, cx22, cx32...)"
type = string
default = "cx22" # 2 vCPU, 4 Go RAM — bon rapport qualité/prix
}
variable "location" {
description = "Datacenter Hetzner (nbg1, fsn1, hel1)"
type = string
default = "nbg1" # Nuremberg, Allemagne
}
Ensuite, main.tf avec le provider et notre première resource :
# main.tf — Configuration principale
# Déclaration du provider Hetzner et de sa version minimale
terraform {
required_providers {
hcloud = {
source = "hetznercloud/hcloud"
version = "~> 1.45" # Accepte les versions 1.45.x
}
}
# Version minimale de Terraform requise
required_version = ">= 1.6.0"
}
# Configuration du provider avec notre token API
provider "hcloud" {
token = var.hcloud_token
}
# --- Clé SSH ---
# On importe notre clé publique pour se connecter au serveur
resource "hcloud_ssh_key" "default" {
name = "ma-cle-ssh"
public_key = file("~/.ssh/id_ed25519.pub") # Adaptez le chemin si nécessaire
}
# --- Serveur ---
# Notre premier serveur cloud
resource "hcloud_server" "web" {
name = var.server_name
image = "ubuntu-24.04" # Image OS
server_type = var.server_type # Type d'instance
location = var.location # Datacenter
ssh_keys = [hcloud_ssh_key.default.id] # Référence à la clé SSH ci-dessus
# Labels pour organiser vos ressources
labels = {
environment = "dev"
managed_by = "terraform"
}
}
Enfin, outputs.tf pour récupérer les informations utiles après le déploiement :
# outputs.tf — Valeurs affichées après le déploiement
output "server_ip" {
description = "Adresse IPv4 publique du serveur"
value = hcloud_server.web.ipv4_address
}
output "server_status" {
description = "Statut du serveur"
value = hcloud_server.web.status
}
Premier déploiement
C’est le moment de vérité. Suivez ces étapes dans l’ordre :
# 1. Initialiser le projet — télécharge le provider Hetzner
terraform init
# 2. Définir le token (ne le mettez JAMAIS en dur dans le code)
export TF_VAR_hcloud_token="votre-token-api-ici"
# 3. Prévisualiser les changements
terraform plan
La commande plan affiche un résumé détaillé de ce que Terraform va créer :
Plan: 2 to add, 0 to change, 0 to destroy.
Tout est clair ? On applique :
# 4. Appliquer — Terraform demande confirmation avant d'agir
terraform apply
Tapez yes à la confirmation. En quelques secondes, votre serveur est provisionné. Terraform affiche les outputs :
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
server_ip = "88.99.xxx.xxx"
server_status = "running"
Vous pouvez maintenant vous connecter :
ssh root@$(terraform output -raw server_ip)
Comprendre le State
Le state est un concept central en Terraform, et souvent source de confusion pour les débutants. Prenons le temps de bien le comprendre.
À quoi sert le state ?
Après un terraform apply, Terraform crée un fichier terraform.tfstate dans votre répertoire. Ce fichier JSON contient la correspondance exacte entre vos ressources déclarées en HCL et les ressources réelles chez le provider.
Sans ce fichier, Terraform ne saurait pas :
- Quelles ressources il a déjà créées
- Quels attributs ont changé depuis le dernier apply
- Quelles ressources supprimer si vous les retirez du code
Le state local vs distant
Par défaut, le state est stocké localement dans terraform.tfstate. Cela pose deux problèmes :
- Collaboration — Si deux personnes appliquent en même temps, le state est corrompu.
- Sécurité — Le state contient des données sensibles (IPs, identifiants…).
La solution : un backend distant. Voici un exemple avec un bucket S3-compatible (disponible chez beaucoup de providers, dont Infomaniak) :
# Backend distant — stocke le state dans un bucket S3-compatible
terraform {
backend "s3" {
bucket = "mon-terraform-state"
key = "hetzner-demo/terraform.tfstate"
region = "eu-west-1"
endpoint = "https://s3.pub1.infomaniak.cloud" # Exemple Infomaniak
# Désactiver les validations spécifiques AWS
skip_credentials_validation = true
skip_region_validation = true
skip_metadata_api_check = true
}
}
Règles d’or pour le state
- Ne jamais commit le fichier
terraform.tfstatedans Git. Ajoutez-le à votre.gitignore. - Toujours utiliser un backend distant dès que vous travaillez en équipe.
- Activer le locking pour empêcher les modifications concurrentes.
- Ne jamais éditer le state manuellement, sauf avec
terraform state(commandes dédiées).
# .gitignore recommandé pour tout projet Terraform
*.tfstate
*.tfstate.*
.terraform/
*.tfvars # Contient potentiellement des secrets
Introduction aux modules
Une fois votre premier projet fonctionnel, vous allez vite vouloir réutiliser du code. C’est exactement le rôle des modules.
Un module Terraform est simplement un répertoire contenant des fichiers .tf. Votre projet actuel est déjà un module — le module racine (root module).
Créer un module réutilisable
Imaginons un module pour créer un serveur Hetzner avec des paramètres standardisés :
modules/
└── hetzner-server/
├── main.tf
├── variables.tf
└── outputs.tf
# modules/hetzner-server/variables.tf
variable "name" {
description = "Nom du serveur"
type = string
}
variable "server_type" {
description = "Type d'instance"
type = string
default = "cx22"
}
variable "image" {
description = "Image OS"
type = string
default = "ubuntu-24.04"
}
variable "location" {
description = "Datacenter"
type = string
default = "nbg1"
}
variable "ssh_key_ids" {
description = "Liste des IDs de clés SSH"
type = list(string)
}
variable "labels" {
description = "Labels à appliquer au serveur"
type = map(string)
default = {}
}
# modules/hetzner-server/main.tf
resource "hcloud_server" "this" {
name = var.name
image = var.image
server_type = var.server_type
location = var.location
ssh_keys = var.ssh_key_ids
labels = merge(
{ managed_by = "terraform" }, # Label toujours présent
var.labels # Labels personnalisés
)
}
# modules/hetzner-server/outputs.tf
output "id" {
value = hcloud_server.this.id
}
output "ipv4_address" {
value = hcloud_server.this.ipv4_address
}
output "status" {
value = hcloud_server.this.status
}
Utiliser le module
De retour dans votre module racine, appelez le module pour créer plusieurs serveurs :
# main.tf — Utilisation du module pour créer deux serveurs
module "web_server" {
source = "./modules/hetzner-server"
name = "web-prod-01"
server_type = "cx22"
location = "fsn1" # Falkenstein
ssh_key_ids = [hcloud_ssh_key.default.id]
labels = {
role = "web"
environment = "production"
}
}
module "db_server" {
source = "./modules/hetzner-server"
name = "db-prod-01"
server_type = "cx32" # Plus puissant pour la BDD
location = "fsn1"
ssh_key_ids = [hcloud_ssh_key.default.id]
labels = {
role = "database"
environment = "production"
}
}
Après un terraform init (nécessaire quand on ajoute un module), le plan montrera la création des deux serveurs avec leurs configurations respectives.
Bonnes pratiques pour bien démarrer
Voici les conventions qui vous épargneront des heures de débogage et rendront vos projets maintenables sur le long terme.
1. Structurez vos fichiers
Même pour un petit projet, séparez vos fichiers par responsabilité :
projet/
├── main.tf # Ressources principales
├── variables.tf # Toutes les variables
├── outputs.tf # Toutes les sorties
├── versions.tf # Contraintes de versions (providers, Terraform)
├── terraform.tfvars # Valeurs des variables (ne pas commit si secrets)
└── .gitignore
2. Épinglez vos versions
Ne laissez jamais Terraform choisir la version du provider :
# versions.tf — Verrouillez les versions pour la reproductibilité
terraform {
required_version = ">= 1.6.0, < 2.0.0"
required_providers {
hcloud = {
source = "hetznercloud/hcloud"
version = "~> 1.45" # Accepte 1.45.x, pas 1.46.0
}
}
}
Commitez aussi le fichier .terraform.lock.hcl — c’est le lockfile des providers, comme un package-lock.json.
3. Utilisez des variables, jamais de valeurs en dur
Les tokens, noms, tailles d’instance : tout passe par des variables. Les secrets passent par des variables d’environnement préfixées TF_VAR_ :
# Méthode sécurisée pour passer un secret
export TF_VAR_hcloud_token="hc_xxxxxxxxxxxxx"
4. Nommez avec intention
Adoptez une convention de nommage cohérente dès le début :
# ✅ Bon — descriptif et cohérent
resource "hcloud_server" "web_production" { ... }
resource "hcloud_server" "db_production" { ... }
# ❌ Mauvais — générique et ambigu
resource "hcloud_server" "server1" { ... }
resource "hcloud_server" "main" { ... }
5. Validez avant de commit
Intégrez ces commandes dans votre workflow (ou votre CI) :
# Vérifier la syntaxe HCL
terraform fmt -check
# Valider la configuration
terraform validate
# Formater automatiquement le code
terraform fmt -recursive
6. Utilisez terraform plan religieusement
Ne faites jamais un apply sans avoir lu le plan. C’est votre filet de sécurité. En CI/CD, sauvegardez le plan pour l’appliquer de manière identique :
# Sauvegarder le plan dans un fichier binaire
terraform plan -out=tfplan
# Appliquer exactement ce plan (sans reconfirmation)
terraform apply tfplan
7. Nettoyez après vous
Pour détruire proprement toute l’infrastructure d’un projet de test :
# Prévisualiser la destruction
terraform plan -destroy
# Détruire les ressources (avec confirmation)
terraform destroy
Aller plus loin
Ce guide couvre les fondations. Voici les prochaines étapes pour progresser :
- Workspaces — Gérer plusieurs environnements (dev, staging, prod) avec le même code.
- Data sources — Interroger des ressources existantes sans les gérer.
- Provisioners — Exécuter des scripts sur les serveurs après création (préférez Ansible pour ça).
- Terraform Cloud / Spacelift — Automatiser les apply dans un pipeline CI/CD.
- Terragrunt — Orchestrer des projets Terraform complexes avec moins de répétition.
- Import — Importer des ressources existantes dans le state avec
terraform importou le blocimport(Terraform 1.5+).
Conclusion
Terraform transforme la gestion d’infrastructure en un processus prévisible, versionné et collaboratif. Avec les bases couvertes dans ce guide — providers, resources, state, modules et bonnes pratiques — vous avez tout ce qu’il faut pour démarrer concrètement.
Le meilleur conseil : commencez petit. Un serveur, un réseau, un DNS. Itérez. Chaque terraform apply réussi renforce votre compréhension. Et surtout, commitez votre code — votre infrastructure mérite le même soin que votre application.
La courbe d’apprentissage est réelle, mais le retour sur investissement est massif. Une fois que vous aurez goûté au terraform plan avant chaque changement d’infra, vous ne reviendrez plus en arrière.
Cet article fait partie de la série Infrastructure as Code sur devopslab.ch. Retrouvez nos autres guides pour approfondir Terraform, Ansible et les pratiques DevOps modernes.
🖥️ Pratique sur ton propre serveur
Pour suivre Terraform pour débutants : automatiser son infrastructure pas à pas en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.
Sur cette page
Articles liés
Comparatif hébergement cloud 2026 : AWS vs GCP vs Azure vs alternatives
AWS vs GCP vs Azure vs alternatives : comparatif complet des hébergements cloud en 2026 avec pricing détaillé.
Datadog vs New Relic vs Grafana : quel outil de monitoring choisir en 2026 ?
Datadog vs New Relic vs Grafana : comparatif honnête pour choisir le meilleur outil de monitoring en 2026.
Le DevOps en 2026 : bien plus que des outils
Le DevOps ne se résume pas à Docker, Kubernetes ou Terraform. C'est avant tout une culture, un état d'esprit. Découvrez la vraie définition du DevOps, ses principes fondateurs (Three Ways, CALMS), son cycle de vie complet, et pourquoi tant d'entreprises échouent en ne voyant que la partie technique.