[Hetzner] 2026 - Proxmox Installation mit ZFS


Proxmox VE 9.2 auf einem Hetzner-Root-Server installieren (ZFS, per ISO über QEMU)

Alle Befehle aus dem Video zum Kopieren. Von oben nach unten abarbeiten – jeder Block ist eine Einheit.

Legende: [RESCUE] = im Hetzner-Rescue-System · [LOKAL] = auf deinem eigenen Rechner · [VM] = im installierten System (per SSH auf Port 2222)

Inhalt: Blöcke 0–13 = der Ablauf · Anhang A = Voraussetzungen · Anhang B = Parameter erklärt · Anhang C = Notfall · Anhang D = häufige Rückfragen · Anhang E = Quellen


:warning: Die zwei Regeln, an denen alles hängt

  1. Die Platten müssen als SATA durchgereicht werden (nicht als NVMe), sonst heißen sie in der VM anders als auf dem Blech.
  2. Vor dem ersten Start auf Blech muss der Interfacename korrigiert werden (Block 8) – sonst bootet der Server, ist aber nicht mehr erreichbar.

Block 0 · Robot vorbereiten

  1. Robot → Server auswählen → Reiter Rescue → Linux, 64 Bit, SSH-Key → Rescue-System aktivieren
  2. Reiter ResetAutomatischen Hardware-Reset ausführen
  3. Etwa 60 Sekunden warten

Block 1 · [LOKAL] Verbinden

ssh root@SERVER-IP

Block 2 · [RESCUE] Werte automatisch ermitteln

IFACE=$(ip -o -4 route show default | awk '{print $5}')
MAC=$(cat /sys/class/net/$IFACE/address)
NIC=$(ip -d link show $IFACE | awk '/altname/{print $2; exit}')
CIDR=$(ip -o -4 addr show $IFACE | awk '{print $4}')
GW=$(ip -o -4 route show default | awk '{print $3}')
[ -d /sys/firmware/efi ] && BOOTMODE=UEFI || BOOTMODE=Legacy

# Netzadresse fuer QEMU berechnen (damit SSH in die VM spaeter funktioniert)
IPADDR=${CIDR%/*}; PLEN=${CIDR#*/}
IFS=. read -r o1 o2 o3 o4 <<< "$IPADDR"
_ip=$(( (o1<<24)|(o2<<16)|(o3<<8)|o4 ))
_mask=$(( (0xFFFFFFFF << (32-PLEN)) & 0xFFFFFFFF ))
_net=$(( _ip & _mask ))
NETADDR="$(( (_net>>24)&255 )).$(( (_net>>16)&255 )).$(( (_net>>8)&255 )).$(( _net&255 ))"
NETMASK="$(( (_mask>>24)&255 )).$(( (_mask>>16)&255 )).$(( (_mask>>8)&255 )).$(( _mask&255 ))"

cat <<EOF

===== NOTIEREN / ABFOTOGRAFIEREN =====
Boot-Modus : $BOOTMODE
Interface  : $IFACE   (Blech-Name: ${NIC:-KEIN ALTNAME - siehe Hinweis})
MAC        : $MAC
IP/Praefix : $CIDR
Gateway    : $GW
QEMU-Netz  : $NETADDR/$NETMASK  (automatisch berechnet)
======================================
EOF
lsblk -d -o NAME,SIZE,MODEL,ROTA

:pushpin: Diese Werte brauchst du gleich mehrfach. Steht bei „Blech-Name" nichts, schau dir ip -d link show $IFACE an – ohne altname gilt der Name aus $IFACE.

:warning: Alle folgenden Blöcke nutzen diese Variablen. Wenn du das Terminal wechselst, Block 2 dort erneut ausführen.

Block 3 · [RESCUE] Pakete und ISO

apt update
apt install -y qemu-system-x86 ovmf
mkdir -p /tmp/work && cd /tmp/work

ISOFILE=$(curl -s https://enterprise.proxmox.com/iso/ | grep -o 'proxmox-ve_[0-9.]*-[0-9]*\.iso' | sort -V | tail -1)
echo "Gefunden: $ISOFILE"
curl -O "https://enterprise.proxmox.com/iso/$ISOFILE"
ls -lh /tmp/work

Falls die Erkennung leer bleibt, Version auf der Proxmox-Downloadseite nachsehen und manuell setzen:

ISOFILE=proxmox-ve_9.2-1.iso
curl -O "https://enterprise.proxmox.com/iso/$ISOFILE"

Block 4 · [RESCUE] Installer starten

Der Block erkennt selbst, ob dein Server per UEFI oder Legacy bootet.

cd /tmp/work
cp /usr/share/OVMF/OVMF_VARS.fd /tmp/work/OVMF_VARS.fd 2>/dev/null

QEMU_COMMON=(
  -enable-kvm -machine q35 -m 8192 -smp 4
  -device ich9-ahci,id=ahci
  -drive file=/dev/sda,format=raw,if=none,id=drive0,cache=none
  -device ide-hd,drive=drive0,bus=ahci.0
  -drive file=/dev/sdb,format=raw,if=none,id=drive1,cache=none
  -device ide-hd,drive=drive1,bus=ahci.1
  -netdev user,id=net0,net=$NETADDR/$NETMASK,host=$GW,hostfwd=tcp::2222-$IPADDR:22
  -device virtio-net-pci,netdev=net0,mac=$MAC
  -vnc 127.0.0.1:0
)

if [ -d /sys/firmware/efi ]; then
  qemu-system-x86_64 "${QEMU_COMMON[@]}" \
    -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \
    -drive if=pflash,format=raw,file=/tmp/work/OVMF_VARS.fd \
    -cdrom "/tmp/work/$ISOFILE" -boot order=d
else
  qemu-system-x86_64 "${QEMU_COMMON[@]}" \
    -cdrom "/tmp/work/$ISOFILE" -boot order=d
fi

:warning: Das Terminal bleibt jetzt belegt – nicht schließen.

Erklärung der Parameter siehe Anhang B.

Block 5 · [LOKAL] VNC-Tunnel öffnen

Zweites Terminal auf deinem Rechner:

ssh -L 5900:127.0.0.1:5900 root@SERVER-IP

Dann im VNC-Programm zu localhost:5900 verbinden.

:keyboard: Tastatur: Es ist bewusst kein -k de gesetzt, weil über VNC sonst die AltGr-Ebene bricht. Es gilt US-Layout[ und ] liegen rechts neben dem P, Umlaute funktionieren nicht.

:warning: Root-Passwort ohne AltGr-Zeichen wählen (kein @ [ ] { } \ | ~). Sonst kommt das Passwort anders an, als du es tippst. Lieber ein einfaches setzen und nach dem ersten SSH-Login mit passwd ändern.

Block 6 · Im Installer

Schritt Eingabe
Filesystem Optionszfs (RAID1) → nur sda und sdb aktiv lassen
Country / Zeitzone / Tastatur Germany / Europe/Berlin / de
Passwort und E-Mail einfaches Passwort (siehe Warnung), echte Adresse für Systemmeldungen
Management Interface die angebotene Karte
Hostname (FQDN) z. B. pve.deinedomain.de
IP-Adresse Wert IP/Praefix aus Block 2
Gateway Wert aus Block 2
DNS 1.1.1.1

Nach „Installation successful" QEMU im Rescue-Terminal mit Strg+C beenden.

:bulb: RAID1 spiegelt (halbe Kapazität, ein Laufwerk darf ausfallen). RAID0 gibt die volle Kapazität, aber keinen Schutz – bei einem Produktivserver keine gute Idee.

Block 7 · [RESCUE] Kontrolle und zweiter Start

lsblk -f | grep -E 'sda|sdb'

Erwartet: auf beiden Platten je eine vfat-Partition (EFI) und eine zfs_member-Partition mit dem Pool rpool.

Jetzt das installierte System starten – diesmal ohne ISO:

cd /tmp/work
if [ -d /sys/firmware/efi ]; then
  qemu-system-x86_64 "${QEMU_COMMON[@]}" \
    -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \
    -drive if=pflash,format=raw,file=/tmp/work/OVMF_VARS.fd \
    -boot order=c
else
  qemu-system-x86_64 "${QEMU_COMMON[@]}" -boot order=c
fi

:pushpin: Ist QEMU_COMMON nicht mehr gesetzt (neues Terminal), führe Block 2 und den QEMU_COMMON=(...)-Teil aus Block 4 erneut aus.

Block 8 · [VM] Interfacename korrigieren

:rotating_light: Der wichtigste Block. Wer ihn überspringt, hat gleich einen Server, der läuft, aber nicht erreichbar ist.

Der Installer schreibt die Netzwerkkonfiguration mit dem Namen, den die Karte innerhalb der QEMU-VM hat (etwa enp0s3). Auf dem Blech heißt dieselbe Karte anders (etwa enp9s0).

Drittes Terminal → ins Rescue einloggen → von dort in die VM:

ssh -p 2222 root@127.0.0.1

Eine Zeile anpassen, den Rest kopieren:

NIC=enp9s0        # <<< ANPASSEN: Blech-Name aus Block 2

cp /etc/network/interfaces /etc/network/interfaces.bak
OLD=$(grep -oP '^\s*bridge-ports\s+\K\S+' /etc/network/interfaces | head -1)
echo "Ersetze '$OLD' durch '$NIC'"
sed -i "s/\b${OLD}\b/${NIC}/g" /etc/network/interfaces
cat /etc/network/interfaces

Prüfen: Sowohl in iface … inet manual als auch bei bridge-ports muss jetzt dein Name stehen. Dann:

update-initramfs -u -k all
poweroff

QEMU beendet sich, du bist zurück im Rescue-Terminal.

Block 9 · [RESCUE] Auf Blech booten

reboot now

:warning: Rescue-System nicht erneut aktivieren. Rund 90 Sekunden warten.

Block 10 · [LOKAL] Verbinden und prüfen

ssh-keygen -R SERVER-IP
ssh root@SERVER-IP
uname -r          # muss "pve" enthalten
zpool status      # rpool ONLINE, beide Platten ONLINE

Block 11 · Repositories und Update

Proxmox 9.x nutzt das DEB822-Format. Enterprise-Repo raus, No-Subscription rein:

rm -f /etc/apt/sources.list.d/pve-enterprise.sources /etc/apt/sources.list.d/ceph.sources

CODENAME=$(. /etc/os-release && echo "$VERSION_CODENAME")
cat > /etc/apt/sources.list.d/pve-no-sub.sources << EOF
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: ${CODENAME}
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF

apt update && apt dist-upgrade -y
systemctl status pve-cluster pvedaemon pveproxy pvestatd --no-pager

Weboberfläche: https://SERVER-IP:8006 · Benutzer root · Realm Linux PAM

Block 12 · IP-Forwarding aktivieren

:warning: Pflichtschritt, sobald deine VMs eigene öffentliche IPs bekommen oder über NAT ins Internet sollen. Hetzner liefert das Standard-System mit deaktiviertem Paket-Forwarding aus – ohne diesen Schritt kommt keine VM ins Netz.

cat > /etc/sysctl.d/99-hetzner-forwarding.conf << 'EOF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF

sysctl --system
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding

Erwartet: beide Werte stehen auf 1.

Hetzners eigene Anleitung kommentiert stattdessen Zeilen in /etc/sysctl.conf per sed ein – das klappt nur, solange diese Zeilen dort existieren. Eine eigene Datei unter /etc/sysctl.d/ ist robuster und übersteht Systemupgrades. Wer nur IPv4 oder nur IPv6 braucht, lässt die jeweils andere Zeile weg.

Block 13 · Direkt danach erledigen

passwd
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl reload ssh

:warning: SSH-Key-Login in einem zweiten Terminal testen, bevor du das erste schließt.

  • Passwort geändert, Key-Login funktioniert
  • IP-Forwarding aktiv (Block 12)
  • Weboberfläche nicht dauerhaft offen im Internet (siehe Folgevideo)
  • Backup-Strategie überlegt
  • Für VMs mit öffentlichen IPs: geroutetes Setup nötig (Hetzner bindet IPs an MAC-Adressen)


Anhang A · Voraussetzungen

  • Hetzner-Dedicated-Server (Robot), zwei Platten als sda und sdb
  • SSH-Key im Hetzner-Account hinterlegt
  • Ein VNC-Programm auf dem eigenen Rechner (TigerVNC, RealVNC, Remmina, unter macOS die Bildschirmfreigabe)
  • Rund 45–60 Minuten Zeit beim ersten Durchlauf

Warum dieser Weg? Der offizielle Hetzner-Weg (Debian per installimage, danach Upgrade auf Proxmox) ist einfacher, liefert aber kein ZFS-Root. Wer Snapshots, Prüfsummen und Replikation will, muss den Original-Installer laufen lassen – und genau das passiert hier in einer QEMU-VM, die auf die echten Platten schreibt.

Anhang B · Die QEMU-Parameter erklärt

Parameter Zweck
-device ich9-ahci + -device ide-hd Platten werden als SATA durchgereicht – der Installer sieht sda/sdb, exakt wie auf dem Blech. Mit -device nvme hießen sie in der VM nvme0n1 und passten nicht mehr
cache=none Schreibzugriffe gehen direkt auf die Platte, kein Host-Cache dazwischen
mac=$MAC Die virtuelle Karte bekommt die echte MAC des Servers
net= / host= QEMUs User-Networking arbeitet sonst im Netz 10.0.2.0/24. Da die VM die statische Hetzner-IP hat, liefe eine Weiterleitung dorthin ins Leere. Mit diesen Optionen legt Slirp das echte Subnetz an
hostfwd=tcp::2222-$IPADDR:22 SSH-Zugang in die VM über Port 2222 des Rescue-Systems
-machine q35 Moderner Chipsatz mit PCIe statt des uralten i440fx
-enable-kvm Hardwarebeschleunigung, sonst dauert die Installation ewig
-vnc 127.0.0.1:0 Bildschirm nur lokal, wird per SSH getunnelt

Sonderfall: Liegt dein Gateway außerhalb des eigenen Subnetzes (bei Hetzner gelegentlich /32 mit pointopoint), lehnt QEMU host=$GW ab („failed to parse netmask" oder ähnlich). Dann den Teil net=…,host=…,hostfwd=… durch ein schlichtes -netdev user,id=net0 ersetzen und die Befehle aus Block 8 direkt im VNC-Fenster tippen.

Anhang C · Notfall – Server kommt nach dem Reboot nicht hoch

Kein Grund zur Panik, das ist reparierbar. Im Robot Rescue aktivieren, Hardware-Reset auslösen, dann:

ssh root@SERVER-IP

zpool import -f -R /mnt rpool
cat /mnt/etc/network/interfaces
ip -d link show                      # echten Namen gegenpruefen
nano /mnt/etc/network/interfaces     # korrigieren
zpool export rpool
reboot now

Typische Ursachen: falscher Interfacename, Tippfehler bei IP oder Gateway, update-initramfs vergessen.

Plan B unter Zeitdruck: Rescue → installimage → Debian 13 → offizielles Upgrade auf Proxmox. Verzichtet auf ZFS-Root, ist dafür praktisch unkaputtbar.

Anhang D · Häufige Rückfragen

Warum überhaupt QEMU statt einfach die ISO booten?
Ohne KVM-Konsole kommst du am Hetzner-Server nicht an ein Boot-Menü. Die ISO läuft deshalb in einer VM im Rescue-System und schreibt dabei direkt auf die physischen Platten.

Kann ich das auch unbeaufsichtigt automatisieren?
Ja – mit proxmox-auto-install-assistant und einer Antwortdatei. Hetzner hat dazu ein eigenes Tutorial, siehe Anhang E.

Meine Platten heißen nvme0n1 statt sda.
Dann in Block 4 die vier AHCI-Zeilen ersetzen durch -drive file=/dev/nvme0n1,format=raw,if=none,id=drive0 plus -device nvme,drive=drive0,serial=nvme0 (analog für die zweite Platte).

Reicht eine Platte?
Ja, dann im Installer statt RAID1 einfach ZFS RAID0 mit einer Platte wählen und in Block 4 die Zeilen für sdb weglassen.

Anhang E · Quellen


:speech_balloon: Fragen, Fehler gefunden oder eine bessere Lösung? Schreib es unten in den Thread – der Beitrag ist ein Wiki, Korrekturen kann jeder direkt einarbeiten.