Install Proxmox the way Proxmox says to, not the way I guessed

The previous commit put installimage with a Proxmox image into Task 3. That
image does not exist. Hetzner's installimage carries no Proxmox and lists it as
unsupported, so anyone following that instruction finds only Debian and ends up
back at the intermediate base system the same commit had just removed. Looked
up rather than remembered, which is what should have happened before writing it
down.

The mechanism the owner described does exist and is the official one since PVE
8.2: build the real Proxmox ISO with an embedded answer file via
proxmox-auto-install-assistant, run it under QEMU against the physical disks
from the rescue system, reboot into a finished node. Hetzner publishes a
tutorial for exactly this. No Debian, no VNC, no click — which is what the
owner said in the first place.

Two things fall out of the answer file that improve the plan.

The hand-written systemd resume service is gone. [first-boot] with
source = "from-iso" is the supported way to have the script pick itself up
after the reboot, and it is the only variant that can work before the tunnel
exists — a from-url hook would be pointing at a CluPilot it cannot reach yet.
The carry-across of the progress file stays necessary regardless: the rescue
system's copy still lives in RAM.

Trap 2 was being applied to the wrong machine. "Root partition last, not on
LVM" comes from the template traps, and the reason it exists is
GrowGuestFilesystem, which grows a GUEST filesystem. The template is built in
Task 8 from a Debian cloud image, not from the host's own layout, so the
justification written into Task 3 ("it applies to the host too, because the
template is built from here") does not hold. It remains binding for the
template, where it belongs. The host gets ZFS, and that it happens to involve
no LVM is a side effect rather than the reason — with arc-max pinned, because
the default takes half the RAM a host needs for its guests.

Also recorded: the answer file needs an fqdn and a root password that the
command line does not carry. The password is generated and thrown away, because
the platform no longer logs in over SSH and the plan already says a half
installed machine is reinstalled rather than repaired — keeping a secret for an
emergency the plan does not have only creates another place a secret lives.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feature/host-bootstrap
nexxo 2026-07-30 19:45:29 +02:00
parent 8f943f3d1b
commit 0b26e45147
1 changed files with 62 additions and 20 deletions

View File

@ -154,30 +154,72 @@ genau hier seine einzige Gelegenheit, es nicht zu tun.
> Task 7 des Plattform-Plans (`hosts.section.*`).
> - `proxmox_installed` = **PVE läuft nachweislich** (Task 4).
Das Abbild schreibt **`installimage`** aus dem Hetzner-Rettungssystem, mit
einem Proxmox-Abbild aus dessen Liste. Kein `debootstrap`, kein eigener
Partitionierer: der Anbieter kennt seine Hardware besser als dieses Skript, und
ein selbstgebauter Bootpfad auf fremdem Blech kommt bei einem Fehler nur über
die Anbieterkonsole zurück.
> **Und ein zweites Mal korrigiert, an der Mechanik.** Hier stand kurzzeitig
> `installimage` mit einem Proxmox-Abbild. **Das gibt es nicht:** Hetzners
> `installimage` führt kein Proxmox, es gilt dort als nicht unterstützt. Wer
> danach sucht, findet nur Debian — und landet wieder beim Zwischensystem, das
> gerade abgeschafft wurde.
**Der genaue Abbildname wird bei der Abnahme festgehalten, nicht hier geraten.**
Die Liste gehört dem Anbieter und ändert sich; das Skript sucht sie zur Laufzeit
ab und **bricht ab, wenn es kein passendes Proxmox-Abbild findet** — dieselbe
Regel wie beim unbekannten Release in Task 4.
Der Weg ist die **offizielle Proxmox-ISO mit eingebetteter Antwortdatei**, seit
PVE 8.2 der reguläre Weg für unbeaufsichtigte Installationen und von Hetzner
selbst als Anleitung geführt:
Die Partitionierung kommt aus den `PART`-Zeilen der `installimage`-Vorgabe:
**Root-Partition als letzte auf der Platte, kein LVM** (Falle 2 aus Block A —
sie gilt für den Host genauso, weil die Vorlage später von hier aus gebaut
wird). Danach Neustart aus dem Rettungssystem heraus.
1. **Bootmodus feststellen** (Legacy oder UEFI) — davon hängt der QEMU-Aufruf ab.
2. `answer.toml` schreiben: `[global]` mit `fqdn`, `country`, `timezone`,
`root-password-hashed` und `root-ssh-keys`; `[network]` mit `source`;
`[disk-setup]` mit dem Dateisystem und der Plattenwahl.
3. **`proxmox-auto-install-assistant prepare-iso`** backt die Antwortdatei in
die ISO. Vorher `validate-answer` — eine ISO, die wegen eines Tippfehlers in
den interaktiven Modus fällt, hängt danach unsichtbar in QEMU.
4. Die ISO **unter QEMU** laufen lassen, die gegen die **echten Platten**
schreibt. Kein VNC, kein Klick: der Eintrag „Automated Installation" wird
nach zehn Sekunden von selbst gewählt.
5. Neustart aus dem Rettungssystem heraus.
**Anbieter:** heute nur Hetzner-dediziert. Ein zweiter Weg (netcup, kein
`installimage`) wird erst geschrieben, wenn eine Maschine dasteht, auf der er
abgenommen werden kann — ein ungeprüfter Rückfallpfad ist genau die Behauptung,
die dieser Plan sonst überall vermeidet (R22).
**Dateisystem: ZFS** (`filesystem = "zfs"`, `zfs.raid` passend zur Plattenzahl).
Damit ist auch kein LVM im Spiel. `arc-max` gehört ausdrücklich in die
Antwortdatei — die Vorgabe nimmt sich die Hälfte des Arbeitsspeichers, und den
braucht ein Host, der Kunden trägt, für die Gäste.
Der Neustart ist die erste Stelle, an der das Skript die Kontrolle verliert. Es
hinterlässt deshalb einen systemd-Dienst, der es nach dem Hochfahren **selbst
wieder aufnimmt** — mit demselben Code und derselben Fortschrittsdatei.
> **Falle 2 gilt dem Gast, nicht dem Host — hier stand es falsch.** Die frühere
> Begründung („gilt für den Host genauso, weil die Vorlage später von hier aus
> gebaut wird") trägt nicht: `GrowGuestFilesystem` wächst ein *Gast*-Dateisystem,
> und die Vorlage entsteht in **Task 8** aus einem Debian-Cloud-Image, nicht aus
> dem Plattenlayout des Hosts. **Für die Vorlage bleibt Falle 2 unverändert
> verbindlich.** Für den Host ist sie gegenstandslos; dass ZFS ohnehin ohne LVM
> auskommt, ist ein Nebeneffekt und nicht der Grund.
**Anbieter:** heute nur Hetzner-dediziert. Ein zweiter Weg (netcup) wird erst
geschrieben, wenn eine Maschine dasteht, auf der er abgenommen werden kann — ein
ungeprüfter Rückfallpfad ist genau die Behauptung, die dieser Plan sonst überall
vermeidet (R22). Der ISO-Weg ist dabei die bessere Ausgangslage als
`installimage`: er hängt an nichts, was nur einem Anbieter gehört.
**Was der Installer verlangt und die Befehlszeile nicht mitbringt.** Die
Antwortdatei braucht `fqdn` und ein Root-Kennwort. Keins von beidem steht in den
sechs Angaben aus Task 1. Entschieden, bis jemand widerspricht:
- **`fqdn`** wird aus dem Hostnamen gebildet, den CluPilot ohnehin kennt. Bis
der Adminbereich ihn mitgibt, wird er aus der Rückwärtsauflösung der
öffentlichen IP genommen und, wenn auch die nichts hergibt, aus `--wg-ip`
abgeleitet. Der Name wird in Task 9 ohnehin gegen das ersetzt, was CluPilot
führt.
- **Das Root-Kennwort wird zufällig erzeugt und weggeworfen.** Niemand braucht
es: die Plattform meldet sich nicht mehr per SSH an (Spec §6), und der Plan
sagt für den Fehlerfall ausdrücklich, dass eine halb installierte Maschine
**neu aufgesetzt und nicht nachgebessert** wird (Task 10). Ein Kennwort
aufzubewahren, das nur im Notfall gebraucht würde, den es laut Plan nicht
gibt, schafft nur eine weitere Stelle, an der ein Geheimnis liegt.
- **Optional `--root-ssh-key`.** Gibt der Adminbereich einen öffentlichen
Schlüssel mit, landet er als `root-ssh-keys` in der Antwortdatei. Ohne die
Angabe gibt es keinen Weg per SSH auf die Maschine, und das ist die Vorgabe.
Der Neustart ist die erste Stelle, an der das Skript die Kontrolle verliert.
**Der Wiederanlauf ist kein handgeschriebener systemd-Dienst mehr** — die
Antwortdatei hat dafür einen `[first-boot]`-Abschnitt. Mit
`source = "from-iso"` liegt das Skript schon in der ISO und startet nach dem
Hochfahren von selbst; das ist auch der einzige Weg, der vor dem Tunnel
funktioniert, weil ein `from-url`-Hook CluPilot noch nicht erreichen könnte.
**Und genau das ist der Punkt, an dem „dieselbe Fortschrittsdatei" Arbeit ist und
keine Feststellung.** Das Rettungssystem läuft im Arbeitsspeicher; sein