← Retour au site Chargement…

rescriptum

Servir les médias de démarrage

Guide

Généré le 30 août 2026

Servir les médias de démarrage

Servir les médias de démarrage

Une réponse dit à une machine comment s’installer. Elle ne dit rien de l’endroit d’où vient l’installeur — et jusqu’ici c’était le serveur web de quelqu’un d’autre, hébergeant des images que personne ne confrontait aux réponses écrites pour elles.

Avec un répertoire de médias, le même serveur fait les deux. La MAC d’une machine choisit sa réponse et l’image pour laquelle cette réponse a été écrite, et les deux ne peuvent plus diverger puisqu’un seul composant décide des deux.

$ export RESCRIPTUM_MEDIA_DIR=/srv/media

Non défini, tout est éteint. Rien ne change pour un déploiement existant tant que vous ne la définissez pas.

Où vivent les images de base

Aucune image d’installation n’est dans ce projet, ni dans une version publiée. Une ISO est l’artefact de quelqu’un d’autre, elle pèse un à quatre gigaoctets, et elle change à son propre rythme — trois raisons distinctes pour qu’elle vive sur votre disque plutôt que dans le nôtre. RESCRIPTUM_MEDIA_DIR est l’endroit où vous les gardez, et ce répertoire est l’archive : ce que l’éditeur a publié, sur disque, jamais modifié ensuite.

Ce dernier point est une propriété, pas une promesse. Rien ici ne réécrit une image — en préparer une produit un fichier compagnon et une injection appliquée au fil de l’eau (voir Préparer une image Proxmox), de sorte que les octets sur disque restent exactement ce que l’éditeur a publié et que leur empreinte reste vérifiable contre le SHA256SUMS de l’éditeur. media list dit quelles entrées sont l’archive et lesquelles en dérivent.

Faire entrer une image

Trois façons, et la première est celle à privilégier.

Choisir dans un catalogue

$ rescriptum media sources
SOURCE       NAME              WHAT IT INSTALLS
proxmox-ve   Proxmox VE        the founding case — answers come from a file injected into the image
debian       Debian            netinst images; the answer is a preseed on the kernel command line
ubuntu       Ubuntu LTS        autoinstall, via a cloud-init datasource on the kernel command line
almalinux    AlmaLinux 9       kickstart, named on the kernel command line
rocky        Rocky Linux 9     kickstart, named on the kernel command line

$ rescriptum media sources proxmox-ve
reading https://enterprise.proxmox.com/iso/SHA256SUMS …
Proxmox VE — the founding case — answers come from a file injected into the image
  proxmox-ve_9.2-1.iso
  proxmox-ve_9.2-1-arm64.iso
  proxmox-ve_9.1-1.iso

$ rescriptum media add --from proxmox-ve proxmox-ve_9.2-1.iso

Rien concernant une image précise n’est stocké dans ce serveur. Chaque catalogue nomme l’index de sommes que l’éditeur publie déjà à côté de ses propres images, et les noms comme les empreintes en sont lus au moment où vous demandez — la liste est donc celle que cet éditeur a aujourd’hui, et l’empreinte est la sienne. Une table d’URL figée dans une version publiée proposerait les images du trimestre dernier, dont certaines supprimées depuis.

Ce que cela vaut, dit franchement. Prendre l’empreinte sur le serveur qui sert l’image n’est pas une vérification de signature. En HTTPS cela authentifie le domaine de l’éditeur et cela attrape un téléchargement tronqué, un miroir corrompu et un fichier qui a changé en dessous — l’essentiel de ce qui arrive vraiment — et rien de plus. Si vous voulez davantage, utilisez la section suivante avec une empreinte que vous avez obtenue vous-même.

Laisser le serveur la récupérer

$ rescriptum media add https://enterprise.proxmox.com/iso/proxmox-ve_8.4-1.iso \
    --sha256 9f86d081884c7d65…
fetching https://enterprise.proxmox.com/iso/proxmox-ve_8.4-1.iso
  with curl, into /srv/media/proxmox-ve_8.4-1.iso.part
######################################################################## 100.0%
verifying 1.5G …
fetched 1.5G via curl, digest verified

Elle atterrit sous un nom en .part et n’est renommée qu’une fois l’empreinte vérifiée : un téléchargement partiel ne devient jamais une entrée du catalogue — le catalogue analyse ce qu’il trouve, et une ISO tronquée s’analyse comme une image inconnue qu’une machine essaierait ensuite de démarrer. Une récupération interrompue laisse le .part en place, et relancer la commande la reprend.

--sha256 est obligatoire ici, parce que rien d’autre ne vérifierait ce qui est arrivé. Les éditeurs publient un SHA256SUMS à côté de l’image. Si vous voulez vraiment vous en passer, dites --unverified — l’important est que sauter cette vérification soit un acte délibéré et non le défaut, puisque cela décide ce que chaque machine du réseau installe.

--as NOM.iso choisit le nom de fichier quand l’URL n’en implique pas d’utilisable.

::: tip Il n’y a pas de TLS dans ce binaire rustls et un magasin de racines, c’est une quarantaine de crates et plus d’un mégaoctet sur ARMv7, pour un travail dont chaque hôte a déjà l’outil. Donc ceci lance curl, ou wget si c’est lui qui est installé, et le dit franchement s’il n’en trouve aucun — auquel cas la réponse est celle ci-dessous. :::

Ou la poser vous-même

En SMB, en scp, depuis là où l’ISO se trouve déjà — le geste naturel sur un NAS — puis l’enregistrer :

$ rescriptum media add /srv/media/pve-8.4.iso --sha256 9f86d081884c7d65…
hashing /srv/media/pve-8.4.iso …
  10% (152.0M of 1.5G)

pve-8.4  9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
  proxmox Proxmox Virtual Environment 8.4-1
  kernel /boot/linux26
  initrd /boot/initrd.img
  wrote /srv/media/pve-8.4.media

--sha256 est facultatif et mérite d’être fourni : une empreinte qui ne correspond pas, c’est soit un téléchargement tronqué soit le mauvais fichier, et les deux installeraient la mauvaise chose sur chaque machine qui demande. Rien n’est enregistré en cas d’écart.

Rien n’est copié et l’image n’est jamais modifiée. Ce que media add écrit, c’est le fichier compagnon .media posé à côté, qui retient l’empreinte et ce que la détection a trouvé. C’est tout l’intérêt : hacher 1,5 Go prend près d’une minute, et le serveur ne doit jamais passer une minute dans une requête.

Une image sans compagnon apparaît quand même et est servie quand même — elle n’a simplement pas d’empreinte à revérifier, et elle est analysée à la volée.

Ce qu’il sait dire d’une image

$ rescriptum media list
ID                   FAMILY   ARCH       VERSION                          SIZE  PINNED
pve-8.4              proxmox  x86_64     Proxmox Virtual Environment…     1.5G  9f86d0818
ubuntu-24.04         ubuntu   x86_64     Ubuntu-Server 24.04.1 LTS        2.1G  —
gparted-1.6          unknown  —          GPARTED-LIVE                   420.0M  —

Six familles sont reconnues — Proxmox, Debian, Ubuntu, RHEL et ses dérivés, SUSE et Fedora CoreOS — à partir d’une table de marqueurs situés dans l’image. Là où un éditeur a laissé une chaîne de version, elle est reprise ; l’identifiant de volume sert de repli.

Une image que rien ne reconnaît est quand même listée et quand même servie. Ne pas savoir la décrire n’est pas la même chose que ne pas savoir s’en servir : elle peut être sanbootée, écrite sur une clé, ou récupérée entière par le firmware. Ce qu’elle ne peut pas faire, c’est produire une strophe de démarrage, et le serveur le dit plutôt que de deviner.

Les points d’entrée

Le listener média a sa propre socket, sur 0.0.0.0:8001 par défaut.

RouteCe qui revient
GET /le catalogue en texte, ou en JSON avec Accept: application/json
GET /<id>/isol’image
GET /<id>/kernelle noyau, diffusé depuis l’intérieur de l’image
GET /<id>/initrdl’initrd, de même
GET /<id>/initrd+isol’initrd avec l’image ajoutée, pour les vieux chargeurs
GET /<id>/file/<chemin>n’importe quel fichier dans l’image
GET /health200 OK

Rien n’est extrait et rien n’est décompressé. Un fichier dans une image ISO9660 est une plage d’octets contiguë : servir /pve-8.4/kernel est donc un positionnement et une longueur — le même travail de quelques kilo-octets que l’image fasse 400 Mo ou 4 Go.

Les plages (Range), ETag, If-Range et HEAD sont tous traités, parce que les vrais clients en ont besoin : casper d’Ubuntu et anaconda de Red Hat récupèrent tous deux par plages, et le démarrage HTTP UEFI envoie un HEAD avant de récupérer quoi que ce soit.

Pourquoi c’est un second listener

Ce n’est pas une préférence — trois raisons distinctes, dont une seule suffirait :

  • Le point de réponse répond sur n’importe quel chemin, puisque l’URL est gravée dans une ISO. Un préfixe /media/… découperait un espace réservé dans un espace délibérément ouvert.
  • RESCRIPTUM_TIMEOUT_SECS est une échéance de connexion entière de dix secondes. Un transfert de 1,5 Go dure quinze secondes en gigabit et deux minutes en 100 Mbit : tous les téléchargements seraient tués en vol — et cela ressemblerait à un réseau instable, pas à un réglage.
  • Un téléchargement retient un jeton de connexion pendant des minutes. Partager ce budget avec les réponses, c’est un déploiement qui affame ses propres installations.

Les deux ont des budgets séparés, et un test le prouve au lieu de l’espérer : les réponses continuent d’aboutir avec quatre transferts en cours.

Démarrer une machine depuis tout ça

media ipxe écrit la strophe de démarrage d’une image :

$ rescriptum media ipxe pve-8.4
#!ipxe
# Proxmox Virtual Environment 8.4-1 — generated by `rescriptum media ipxe pve-8.4`.
# An ordinary answer document: selection, layering and templating all apply.
kernel http://192.0.2.10:8001/pve-8.4/kernel ramdisk_size=16777216 rw quiet initrd=initrd.img \
    splash=silent proxmox-start-auto-installer
initrd http://192.0.2.10:8001/pve-8.4/initrd initrd.img
initrd http://192.0.2.10:8001/pve-8.4/iso proxmox.iso
boot

Il imprime un script, il n’en installe pas. Enregistrez-le dans le répertoire des réponses et c’est un document de réponse ordinaire — sélectionné, superposé et gabarisé comme n’importe quel autre :

$ rescriptum media ipxe pve-8.4 > /srv/answers/groups/rack-a/boot.ipxe

C’est bien le point. Le serveur ne devient pas malin sur le démarrage ; il gagne un générateur, et le moteur de composition que vous avez déjà fait le reste. Un {{ mac }} dans l’URL de réponse générée est rempli à chaque requête depuis les faits de la machine.

Chaque famille reçoit ce dont elle a réellement besoin, et elles ne se ressemblent pas :

FamilleComment la réponse lui parvient
Proxmox VEdans l’image, via auto-installer-mode.toml — et proxmox-start-auto-installer sur la ligne de commande pour choisir la voie automatisée
Debianpreseed/url=…
Ubuntuds=nocloud-net;s=…/, d’où cloud-init récupère user-data et meta-data
Famille RHELinst.ks=…
SUSEautoyast=…
Fedora CoreOSignition.config.url=…

Proxmox est le cas à part, et il vaut la peine de savoir pourquoi : c’est le seul qui porte l’emplacement de la réponse à l’intérieur de l’image plutôt que sur la ligne de commande du noyau. C’est aussi pour cela que c’est le seul à devoir passer une fois par prepare-iso — voir Préparer les médias d’installation.

::: tip Vous avez déjà lancé prepare-iso --pxe ? Cela laisse un répertoire contenant vmlinuz, initrd.img et une ISO allégée. Pointez RESCRIPTUM_MEDIA_DIR dessus et cela fonctionne tel quel : l’image allégée est toujours reconnue comme Proxmox, et le noyau et l’initrd posés à côté sont trouvés et servis. :::

Préparer une image Proxmox

Proxmox est la seule famille à porter l’emplacement de la réponse à l’intérieur de l’image, dans /auto-installer-mode.toml. Cela imposait jusqu’ici de lancer proxmox-auto-install-assistant prepare-iso ailleurs d’abord.

$ rescriptum media prepare pve-8.4
pve-8.4-http  prepared from pve-8.4
  answer   http://192.0.2.10:8000/proxmox
  injects  /auto-installer-mode.toml (198 bytes)
  image    1610612736 bytes (source 1610610688 + 2048 appended)
  wrote    /srv/media/pve-8.4-http.media

Nothing was copied. Serve it as /pve-8.4-http/iso, or write it to a stick with
  rescriptum media export pve-8.4-http /tmp/pve-8.4-http.iso

Ce qui vient d’être écrit est un fichier compagnon : environ deux cents octets qui tiennent lieu de 1,5 Go. La source n’est jamais modifiée, jamais copiée, et son empreinte publiée reste vérifiable. Le fichier est injecté au fil de l’eau, donc changer plus tard l’URL de réponse réécrit ces deux cents octets plutôt qu’un gigaoctet — et les deux entrées apparaissent dans media list, adossées à une seule image sur disque.

--as NOM choisit le nom de l’entrée dérivée, et --url, --cert-fingerprint et --token disent ce qui va dans le fichier.

Pour une clé USB

$ rescriptum media export pve-8.4-http /tmp/pve-auto.iso

Matérialise exactement ce que le listener aurait servi, par le même chemin de code. Une clé écrite autrement serait une seconde implémentation à maintenir honnête, et l’écart ne se verrait que sur le bureau de quelqu’un.

Quand il refuse

Refuser est ici une réponse complète, parce que le repli tient en une commande sur n’importe quelle Debian et que ce serveur sert très bien son résultat :

$ proxmox-auto-install-assistant prepare-iso pve.iso --fetch-from http --url …

Il refuse quand l’image n’a ni Rock Ridge ni Joliet — le fichier ne pourrait alors exister que sous un nom 8.3 tronqué comme AUTO_INS.TOM;1, et l’installeur ne le trouverait jamais. Il refuse une image UDF, parce qu’une ISO Windows ne garde ses gros fichiers que dans l’arbre UDF et que patcher l’arbre ISO9660 produirait quelque chose qui a l’air juste et ne l’est pas. Et il refuse quand le répertoire racine n’a pas de mou dans aucun de ses secteurs : déplacer l’extent entraînerait les tables de chemins, ce qui n’est délibérément pas fait.

Il refuse aussi de préparer une image non-Proxmox, en nommant l’alternative : toutes les autres familles prennent l’URL sur la ligne de commande du noyau, là où media ipxe la met déjà.

Si la source change en dessous

Les décalages d’injection sont calculés contre une image donnée. Une source qui aurait changé serait patchée au mauvais endroit, produisant une image qui se monte et qui est fausse — le fichier compagnon retient donc la taille de la source, et le catalogue refuse quand elle ne correspond plus :

  problem: pve-8.4-http.media: pve-8.4 was 1610610688 bytes when this was prepared and
  is 1610612736 now. The injection offsets no longer apply — re-run `media prepare`.

Dire au serveur son propre nom

Dès qu’il écrit des URL dans les scripts qu’il sert, le serveur a besoin d’un nom pour lui-même qu’une machine puisse réellement atteindre. 0.0.0.0:8001 n’en est pas un.

$ export RESCRIPTUM_PUBLIC_HOST=192.0.2.10

Un hôte, jamais une URL. Pas de schéma, pas de port, pas de chemin — le serveur écrit des URL pour deux listeners, et une valeur portant un port épinglerait chaque script généré sur l’un d’eux. Chaque URL ajoute le port de son propre listener. Une valeur portant l’un des trois est refusée au démarrage, en nommant lequel.

Laissée vide, elle demande à la table de routage laquelle des adresses de cet hôte fait face à l’extérieur — et sur un segment sans route par défaut, se rabat sur la liste des interfaces, ce qui sur un hôte à une seule adresse n’est pas une déduction du tout. Dans les deux cas elle dit au démarrage ce qu’elle a retenu, et s’il y avait quelque chose à trancher :

RESCRIPTUM_PUBLIC_HOST is not set — using 192.0.2.10, the only address this host has.
Every generated URL will name it.
warning: RESCRIPTUM_PUBLIC_HOST is not set — derived 192.0.2.10, which is what every
generated URL will name. This host also has 10.8.0.4. If the machines reach it on one of
those instead, set it explicitly.

C’est la seconde qu’il faut prendre au sérieux : une mauvaise déduction produit une machine qui démarre, enchaîne, et se bloque sur une adresse qui n’existe pas. Nommer les autres adresses est ce qui rend la question tranchable depuis le journal lui-même, plutôt qu’en allant regarder l’hôte. Le NAT est le cas qu’aucune des deux lignes ne peut attraper : l’adresse est bien celle de cet hôte, et bien celle que les machines n’atteignent pas.

Le garder honnête

$ rescriptum media check
checking media in /srv/media
  2 image(s), 1 verified against a recorded digest
  note: ubuntu-24.04 has no recorded digest — `media add` records one
  ok — everything recorded still matches

Son code de sortie est un contrat, comme celui de check : zéro quand tout ce qui a été enregistré correspond toujours, un quand quelque chose a dérivé. deploy.sh s’y fie.

Une image qui a changé sous une empreinte enregistrée est la seule panne qui installe silencieusement quelque chose que personne n’a relu, donc elle est bruyante :

  FAIL pve-8.4: the image no longer matches what was recorded
       recorded 9f86d081884c7d65…
       found    7d793037a0760186…

Ce que cela prouve, c’est l’intégrité, pas l’authenticité : ce qui est servi est ce qui a été enregistré. Savoir si ce qui a été enregistré est bien ce que l’éditeur a publié relève de ses propres signatures, et --sha256 au moment du media add est l’endroit où cette vérification se place.

Qui a le droit de récupérer

Le trafic de démarrage n’est pas authentifié, et forcément : une ROM PXE n’a aucun identifiant — la même nécessité qui gouverne déjà le point de réponse. Les contrôles sont donc structurels : lecture seule, borné au catalogue, et aucun chemin de système de fichiers n’est jamais construit à partir d’une requête. Plus un qui peut dire pas vous :

$ export RESCRIPTUM_BOOT_ALLOW=10.0.0.0/8,192.168.0.0/16

Non définie, n’importe qui pouvant atteindre le port, ce qui sur un VLAN de provisionnement est la configuration honnête. Un VLAN de démarrage est la recommandation qui fonctionne vraiment ; voir Sécurité.

Réglages

VariableDéfautÀ quoi elle sert
RESCRIPTUM_MEDIA_ADDR0.0.0.0:8001Le listener
RESCRIPTUM_MEDIA_TIMEOUT_SECS600Échéance du transfert entier
RESCRIPTUM_MEDIA_MAX_CONNECTIONS16Transferts simultanés

Seize, c’est bas volontairement. Chaque transfert retient son jeton pendant des minutes, et le petit bout de ce sur quoi cela doit tourner est un NAS avec un disque mécanique : seize transferts à 64 Kio par morceau font environ deux méga-octets de tampons, une arithmétique qui doit tenir dans 512 Mo de RAM.

Sur une machine de datacenter, montez-la. Le point de réponse a son propre budget et n’est touché dans aucun des deux cas.