Table des matières

Serveur iPXE - Clonezilla sur Debian 13 et Nginx

Cette documentation a été élaborée avec l'aide de Lumo, l'assistant
d'intelligence artificielle   développé par Proton (https://lumo.proton.me). 
Mais malheureusement pour l'instant ça ne fonctionne pas :(
Les postes clients se connectent mais ne semblent pas trouver boot.ipxe 
ReunigKozh

Pourquoi un serveur iPXE - Clonezilla

L'opération de solidarité numérique débutée en 2009 par le Centre des Abeilles avec l'aide technique de Linux Quimper se traduit aujourd'hui par le don d'une vingtaine d'ordinateurs par semaine. Configurer ces ordinateurs avec Clonezilla peut se faire avec une ou plusieurs clés usb Clonezilla. Ces manipulations deviennent fastidieuses surtout lorsqu'il faut mettre à jour ces différentes clés. Un serveur DRBL - Clonezilla est d'une utilisation complexe puisqu'il faut intervenir aussi bien sur le serveur que sur le poste client pour le déploiement des systèmes sur les postes clients. Par contre un serveur iPxe couplé à Clonezilla à l'avantage de laisser à chaque poste client le choix de l'image système à cloner, par exemple Debian BIOS ou UEFI sans intervenir sur le serveur lui-même.

Architecture cible

Internet <-> [eno1 / ext] Debian 13 Serveur Clonezilla [enp2s0 / lan] <-> Switch <-> Postes clients (BIOS/UEFI)
                   │                        │
              NAT/routing             dnsmasq (DHCP+TFTP)
                                       Nginx (HTTP fichiers Clonezilla)
                                       

1. Prérequis système

1.1 Interfaces réseau

Identifier les deux interfaces :

ip a

On suppose dans cette page que :

1.2 Configuration de l'interface interne

Créer/éditer la configuration réseau avec (ifupdown classique) ajouté à :

/etc/network/interfaces

auto enp2s0
iface enp2s0 inet static
  address 192.168.100.1/24
  dns-nameservers 8.8.8.8 1.1.1.1

Puis activer :

sudo ifdown enp2s0 2>/dev/null; sudo ifup enp2s0

⚠️ Ne définissez pas de passerelle par défaut sur enp2s0 si eno1 fournit déjà la route par défaut. Retirez la ligne gateway ci-dessus dans ce cas.

2. Installation des paquets

sudo apt update
sudo apt install -y nginx dnsmasq ipxe-qemu pxelinux syslinux-common wget rsync unzip nftables

Le résultat peut-être celui-là

wget est déjà la version la plus récente (1.25.0-2).
rsync est déjà la version la plus récente (3.4.1+ds1-5+deb13u4).
rsync passé en « installé manuellement ».
unzip est déjà la version la plus récente (6.0-29+deb13u1).
unzip passé en « installé manuellement ».
nftables est déjà la version la plus récente (1.1.3-1).
Installation de :
dnsmasq  ipxe-qemu  nginx  pxelinux  syslinux-common
Installation de dépendances : 
nginx-common
Paquets suggérés :
resolvconf  fcgiwrap  nginx-doc  tftpd-hpa

3. Préparation des fichiers Clonezilla

3.1 Téléchargement de Clonezilla Live

A partir de https://clonezilla.org/downloads.php télécharger la dernière version stable de Clonezilla dans /tmp puis

cd /tmp
sudo unzip clonezilla-live-3.3.3-15-amd64.zip -d /tmp/cz

3.2 Extraction des fichiers de démarrage

Clonezilla Live utilise une architecture classique de live-boot : noyau Linux, initramfs, et filesystem.squashfs.

sudo mkdir -p /var/www/html/clonezilla/live
sudo mkdir -p /srv/tftp/boot

# Copier les fichiers du système de fichiers live (squashfs + vmlinuz + initrd)

sudo cp /tmp/cz/live/vmlinuz /var/www/html/clonezilla/live/
sudo cp /tmp/cz/live/initrd.img /var/www/html/clonezilla/live/
sudo cp /tmp/cz/live/filesystem.squashfs /var/www/html/clonezilla/live/

# Copier aussi les fichiers pour TFTP (si besoin de PXELINUX en fallback)

sudo cp /tmp/cz/live/vmlinuz /srv/tftp/boot/
sudo cp /tmp/cz/live/initrd.img /srv/tftp/boot/

Arborescence cible

/var/www/html/clonezilla/
├── live/
│   ├── vmlinuz
│   ├── initrd.img
│   └── filesystem.squashfs
└── boot.ipxe              ← script iPXE personnalisé

/var/lib/tftpboot/
├── undionly.kpxe           # BIOS Legacy
├── snponly.efi             # UEFI Secure Boot (prioritaire)
├── ipxe.efi                # UEFI non sécurisé (fallback)
└── boot.ipxe               # Script principal

copiez aussi dans   /srv/tftp/

Copier les firmwares iPXE vers le répertoire TFTP :

# Créer le répertoire TFTP si nécessaire
sudo mkdir -p /var/lib/tftpboot

# Télécharger les binaires iPXE depuis le site officiel
cd /var/lib/tftpboot

# Pour BIOS (Legacy)
sudo wget http://boot.ipxe.org/undionly.kpxe

# Pour UEFI x86-64 Secure Boot (prioritaire)
sudo wget http://boot.ipxe.org/x86_64-efi/snponly.efi

# Pour UEFI x86-64 non sécurisé (fallback)
sudo wget http://boot.ipxe.org/x86_64-efi/ipxe.efi


sudo cp /var/lib/tftpboot/undionly.kpxe /srv/tftp/
sudo cp /var/lib/tftpboot/snponly.efi /srv/tftp/
sudo cp /var/lib/tftpboot/ipxe.efi /srv/tftp/

4. Création du script iPXE

Le script iPXE est le cœur de la chaîne de boot. Il télécharge le noyau et l'initramfs de Clonezilla depuis Nginx en HTTP, puis démarre Clonezilla avec les bons paramètres.

sudo tee /var/www/html/clonezilla/boot.ipxe << 'IPXEEOF'
#!ipxe

echo ============================================
echo   Clonezilla Live via iPXE
echo   Server: 192.168.100.1
echo ============================================
echo

set server_ip 192.168.100.1
set http_base http://${server_ip}/clonezilla/live

kernel ${http_base}/vmlinuz boot=live username=user union=overlay config components quiet ocs_prerun="dhclient" ocs_live_run="ocs-live-general" ocs_live_extra_param="" keyboard-layouts=fr locales=fr_FR.UTF-8 ip=dhcp nosplash vga=791
initrd ${http_base}/initrd.img
boot
IPXEEOF

Explication des paramètres du noyau

Paramètre                          Rôle
boot=live                          Active le mode live-boot de Debian/Clonezilla
username=user                      Utilisateur de la session live
union=overlay                      Système de fichiers en overlay
config components quiet            Charge les composants de config, mode silencieux
ocs_prerun="dhclient"              Démarre un client DHCP avant Clonezilla (pour avoir le réseau dans CZ)
ocs_live_run="ocs-live-general"    Lance le menu Clonezilla interactif
keyboard-layouts=fr                Disposition clavier français (adaptez si besoin)
locales=fr_FR.UTF-8                Locale française
ip=dhcp                            Configuration IP via DHCP au boot
vga=791                            Résolution 1024×768 (adaptez selon vos écrans)

Copier le script également en TFTP (au cas où) :

sudo cp /var/www/html/clonezilla/boot.ipxe /srv/tftp/boot.ipxe
sudo cp /var/www/html/clonezilla/boot.ipxe /var/lib/tftpboot/boot.ipxe

💡 Si vous souhaitez automatiser le clonage sans menu interactif, remplacez ocs_live_run par exemple :

ocs_live_run="ocs-sr -g auto -e1 auto -e2 -c -r -j2 restoredisk IMAGE_NAME sda"

(à adapter selon votre image et vos disques cibles)

5. Configuration de dnsmasq (DHCP + TFTP + Proxy-DNS)

dnsmasq gère à la fois le DHCP, le TFTP et la redirection vers iPXE en fonction du type de client (BIOS ou UEFI).

5.1 Fichier de configuration principal

sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig 2>/dev/null
sudo tee /etc/dnsmasq.conf << 'DNSMASQEOF'


# =====================================================
# dnsmasq - Serveur Clonezilla (DHCP + TFTP + DNS proxy)
# =====================================================

# --- Écoute uniquement sur l'interface interne ---
interface=enp2s0
bind-interfaces

# --- Plage DHCP ---
dhcp-range=192.168.100.100,192.168.100.200,255.255.255.0,12h
dhcp-option=option:router,192.168.100.1
dhcp-option=option:dns-server,192.168.100.1,8.8.8.8

# --- TFTP ---
enable-tftp
tftp-root=/srv/tftp

# --- Redirection selon le type de boot client ---

# Option 43 (Vendor Class) pour identifier les clients PXE
dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-match=set:efi-x86_64,option:client-arch,9
dhcp-match=set:bios-x86,option:client-arch,0

# BIOS Legacy → charger undionly.kpxe
dhcp-boot=tag:bios-x86,undionly.kpxe

# UEFI x86_64 → charger ipxe-snponly.efi
dhcp-boot=tag:efi-x86_64,ipxe-snponly.efi

# --- Proxy DNS (résolution locale + forward) ---
domain-needed
bogus-priv
server=8.8.8.8
server=1.1.1.1

# --- Logs (utile pour debug) ---
log-dhcp
log-facility=/var/log/dnsmasq.log
DNSMASQEOF

5.2 Désactiver le démarrage automatique par défaut de dnsmasq systemd-resolved

Sur Debian 13, vérifiez que systemd-resolved n'est pas en conflit sur le port 53 :

sudo ss -tlnup | grep :53

Sortie typique si systemd-resolved est actif

udp  0  0  127.0.0.53:53  0.0.0.0:*  users:(("systemd-resolve",pid=1234,fd=10))
tcp  0  0  127.0.0.53:53  0.0.0.0:*  users:(("systemd-resolve",pid=1234,fd=11))

# Voir si dnsmasq essaie de binder le port 53

sudo grep -n "port" /etc/dnsmasq.conf

# Si systemd-resolved est actif et occupe le port 53 (Garder ou désactiver systemd-resolved est peu important)

sudo systemctl stop systemd-resolved 2>/dev/null || true
sudo systemctl disable systemd-resolved 2>/dev/null || true

# Alternative: désactiver le stub listener dans systemd-resolved

# Editez /etc/systemd/resolved.conf et mettez DNSStubListener=no
# Puis: sudo systemctl restart systemd-resolved

5.3 Redémarrage de dnsmasq

sudo systemctl enable dnsmasq
sudo systemctl restart dnsmasq
sudo systemctl status dnsmasq

Vérifiez que le DHCP et le TFTP écoutent :

sudo ss -ulnp | grep -E ':67 |:69 '

Résultat Correct (dnsmasq fonctionnel)

udp   LISTEN  0  1  0.0.0.0:67  0.0.0.0:*  users:(("dnsmasq",pid=1234,fd=5))
udp   LISTEN  0  1  0.0.0.0:68  0.0.0.0:*  users:(("dnsmasq",pid=1234,fd=6))
udp   LISTEN  0  1  0.0.0.0:69  0.0.0.0:*  users:(("dnsmasq",pid=1234,fd=7))
sudo ss -tulnp | grep :53

Résultat Problématique

# dnsmasq écoute sur 0.0.0.0:53 (conflit si port=0)
udp   LISTEN  0  511  0.0.0.0:53  0.0.0.0:*  users:(("dnsmasq",pid=1234,fd=8))

# OU conflit entre plusieurs services
udp   LISTEN  0  511  0.0.0.0:53  0.0.0.0:*  users:(("dnsmasq",pid=1234,fd=8))
tcp   LISTEN  0  511  0.0.0.0:53  0.0.0.0:*  users:(("dnsmasq",pid=1234,fd=9))

⚠️ Si dnsmasq écoute sur 0.0.0.0:53 alors que vous avez port=0, vérifiez la configuration /etc/dnsmasq.conf

6. Configuration de Nginx

6.1 Création du bloc serveur

sudo tee /etc/nginx/sites-available/clonezilla << 'NGINXEOF'
server {
  listen 80;
  listen [::]:80;
  
  server_name 192.168.100.1;
  
  # Servir uniquement sur l'interface interne
  # Pour limiter l'accès au réseau local de clonage :
  allow 192.168.100.0/24;
  deny all;
  
  root /var/www/html;
  
  location /clonezilla/ {
      autoindex on;
      
      add_header Cache-Control "no-cache, no-store";
      
      # Types MIME corrects
      types {
          application/octet-stream squashfs;
          application/octet-stream kpxe;
          application/octet-stream efi;
          application/octet-stream img;
          text/plain ipxe;
      }
            default_type application/octet-stream;
  }
  
  # Page d'accueil optionnelle
  location / {
      try_files $uri $uri/ =404;
  }
}
NGINXEOF

6.2 Activation du site

sudo rm -f /etc/nginx/sites-enabled/default
sudo ln -sf /etc/nginx/sites-available/clonezilla /etc/nginx/sites-enabled/clonezilla

# Vérifier la syntaxe

sudo nginx -t

# Redémarrer

sudo systemctl restart nginx
sudo systemctl enable nginx

6.3 Test de l'accès HTTP

Depuis une machine du réseau 192.168.100.0/24 :

curl http://192.168.100.1/clonezilla/boot.ipxe
curl -I http://192.168.100.1/clonezilla/live/vmlinuz

Vous devez voir 200 OK et le contenu du script/de la liste.

7. Configuration du routage et du NAT

Pour que les postes clients puissent accéder à Internet notamment pour que Clonezilla puisse télécharger des mises à jour, ou que les machines clonées aient un accès réseau après le clone, il faut activer le routage IPv4 et le NAT entre enp2s0 (lan) et eno1 (wan).

7.1 Activation du forwarding IPv4

sudo tee -a /etc/sysctl.d/99-clonezilla-routing.conf << 'EOF'
net.ipv4.ip_forward = 1
EOF
sudo sysctl -p /etc/sysctl.d/99-clonezilla-routing.conf

7.2 Règles NAT avec nftables

Sur Debian 13, nftables remplace iptables :

sudo tee /etc/nftables.conf << 'NFTCONF'
#!/usr/sbin/nft -f

flush ruleset

table ip nat {
  chain postrouting {
      type nat hook postrouting priority srcnat; policy accept;
      
      # Masquerade : tout le trafic sortant par eno1 (internet)
      oifname "eno1" masquerade
  }
}

table ip filter {
  chain forward {
      type filter hook forward priority filter; policy drop;
      
      # Autoriser le trafic établi à revenir
      ct state established,related accept
      
      # Autoriser le trafic du LAN de clonage vers internet
      iifname "enp2s0" oifname "eno1" accept
      
      # Bloquer le trafic d'internet vers le LAN de clonage (sécurité)
      iifname "eno1" oifname "enp2s0" drop
  }
}
NFTCONF
sudo chmod +x /etc/nftables.conf
sudo systemctl enable nftables
sudo systemctl restart nftables

Vérification :

sudo nft list ruleset

💡 Si vous préférez toujours utiliser iptables (wrapper nft) :

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
sudo iptables -A FORWARD -i enp2s0 -o eno1 -j ACCEPT
sudo iptables -A FORWARD -i eno1 -o enp2s0 -m state --state RELATED,ESTABLISHED -j ACCEPT

8. Chaîne de boot détaillée

Voici le flux complet de démarrage d'un poste client :

(sequence omitted — described below)

Étape 1 — Demande DHCP :

Le poste client (BIOS ou UEFI) émet une requête DHCP Discover sur enp2s0. dnsmasq répond avec une IP dans la plage 192.168.100.100-200 et indique le fichier de boot correspondant à l'architecture détectée :

  1. BIOS → undionly.kpxe (firmware iPXE pour PXE legacy)
  2. UEFI x86_64 → ipxe-snponly.efi (firmware iPXE pour UEFI)

Étape 2 — Transfert TFTP :

Le client télécharge le firmware iPXE via TFTP depuis /srv/tftp/.

Étape 3 — Exécution du script iPXE :

Le firmware iPXE se charge, obtient son adresse DHCP, puis exécute le script boot.ipxe. Selon votre configuration, iPXE peut soit le charger automatiquement s'il est passé comme option (voir note ci-dessous), soit vous pouvez faire en sorte que le script iPXE soit chargé après le chargement du firmware.

⚠️** Point critique** : Par défaut, le firmware iPXE ne sait pas quel script exécuter. Deux approches :

Approche A — Embed le script dans le firmware iPXE (recommandé) : Compiler iPXE avec un script embarqué qui pointe vers http://192.168.100.1/clonezilla/boot.ipxe.

Approche B — Chaînage via dnsmasq (plus simple) : Configurer dnsmasq pour envoyer l'option option:bootfile-name avec l'URL HTTP directement. Mais iPXE doit d'abord être chargé, puis demander une deuxième IP. Voici comment :

8.1 Configuration dnsmasq avec double DHCP (chain loading iPXE)

Modifiez la section de boot dans /etc/dnsmasq.conf :

sudo tee -a /etc/dnsmasq.conf << 'DNSMASQAPPEND'

# === Chaînage iPXE (double DHCP) ===

# Tag pour distinguer la première demande PXE (firmware standard)
# de la seconde demande (déjà iPXE)
dhcp-userclass=set:ipxe,iPXE

# BIOS Legacy
dhcp-boot=tag:!ipxe,tag:bios-x86,undionly.kpxe
dhcp-boot=tag:ipxe,tag:bios-x86,http://192.168.100.1/clonezilla/boot.ipxe

# UEFI x86_64
dhcp-boot=tag:!ipxe,tag:efi-x86_64,ipxe-snponly.efi
dhcp-boot=tag:ipxe,tag:efi-x86_64,http://192.168.100.1/clonezilla/boot.ipxe
DNSMASQAPPEND

📝 Le principe : lors de la première requête DHCP, le client n'est pas encore iPXE (tag:!ipxe), donc dnsmasq lui donne le firmware iPXE via TFTP. Lors de la seconde requête DHCP, iPXE s'identifie via son user-class (tag:ipxe), et dnsmasq lui donne l'URL HTTP du script boot.ipxe.

Relancez dnsmasq :

sudo systemctl restart dnsmasq

Étape 4 — Téléchargement HTTP (Nginx) :

iPXE exécute boot.ipxe, qui télécharge vmlinuz et initrd.img depuis http://192.168.100.1/clonezilla/live/ (beaucoup plus rapide que TFTP).

Étape 5 — Boot Clonezilla : Le noyau démarre, monte le filesystem.squashfs, et Clonezilla s'exécute avec les paramètres spécifiés.

9. Vérifications et dépannage

9.1 Journal dnsmasq

sudo tail -f /var/log/dnsmasq.log

Vous devriez voir les étapes DHCP, la détection de l'architecture (BIOS/UEFI), et l'envoi du bon fichier de boot.

9.2 Journal Nginx

sudo tail -f /var/log/nginx/access.log

Vous devriez voir les requêtes GET pour /clonezilla/boot.ipxe, /clonezilla/live/vmlinuz, /clonezilla/live/initrd.img.

9.3 Tests manuels

Depuis une machine du réseau de clonage :

# Tester le DHCP
sudo dhclient -d -v enp2s0
# Tester TFTP (installer tftp-hpa)
sudo apt install tftp-hpa
tftp 192.168.100.1 -c get undionly.kpxe
tftp 192.168.100.1 -c get ipxe-snponly.efi
# Tester HTTP
curl http://192.168.100.1/clonezilla/boot.ipxe
curl -I http://192.168.100.1/clonezilla/live/filesystem.squashfs

9.4 Tableau de dépannage

Symptôme                           Cause probable                  Solution
Le client n'obtient pas d'IP DHCP  dnsmasq n'écoute pas sur enp2s0   Vérifier interface=enp2s0 et bind-interfaces
Pas de transfert TFTP              Mauvais tftp-root ou permissions  chmod -R 755 /srv/tftp et vérifier les noms de fichiers
iPXE charge mais ne trouve pas boot.ipxe   dnsmasq ne fait pas le chaînage HTTP     Vérifier la configuration dhcp-userclass et les dhcp-boot
Nginx retourne 403                 Restriction allow/deny           Vérifier que le client est bien dans 192.168.100.0/24
filesystem.squashfs introuvable    Mauvais nom de fichier           Vérifier ls /tmp/cz/live/ et adapter
Boot UEFI échoue                   Mauvais firmware EFI             Essayer ipxe.efi au lieu de ipxe-snponly.efi selon le firmware de la carte réseau
Pas d'accès Internet après clonage NAT inactif                      sysctl net.ipv4.ip_forward doit renvoyer 1, vérifier nft list ruleset
Les performances de clonage sont lentes   Routage via NAT          Normal si tout passe par le serveur ; Clonezilla utilise le réseau local

10. Récapitulatif du flux réseau

Flux réseau complet info

Client (BIOS/UEFI) → DHCP sur enp2s0 → dnsmasq fournit IP + firmware iPXE via TFTP → iPXE recharge DHCP (user-class iPXE) → dnsmasq répond avec URL HTTP http://192.168.100.1/clonezilla/boot.ipxe → Nginx sert boot.ipxe, vmlinuz, initrd.img, filesystem.squashfs → Clonezilla démarre → NAT via eno1 permet l'accès Internet aux machines clonées.

Points critiques warning

  1. Le chaînage double-DHCP (user-class iPXE) est essentiel pour router du firmware PXE vers le script HTTP.
  2. L'option client-arch 7/9 identifie UEFI, 0 identifie BIOS. 3) nftables doit masquerader eno1 et forwarder enp2s0→eno1. 4) Le filesystem.squashfs doit être accessible en HTTP pour que Clonezilla fonctionne.

11. Sécurité et bonnes pratiques

Cette configuration vous donne un serveur de clonage autonome, capable de démarrer aussi bien les machines BIOS qu'UEFI via iPXE en IPv4, tout en permettant l'accès Internet aux machines clonées grâce au NAT. Le principal avantage d'iPXE est la vitesse de transfert (HTTP au lieu de TFTP) et la flexibilité du scripting de boot.