# Raspberry Pi 4 (8 GB) als Proxmox VE Test-Node

Installation von Debian 13 (Trixie) ARM64 auf einem Raspberry Pi 4 mit 8 GB RAM. Das Root-Dateisystem wird mit LUKS2 verschlüsselt und beim Booten über Dropbear-SSH entsperrt.

Die Einrichtung erfolgt von einem Linux-PC mit debootstrap und einer ARM64-chroot-Umgebung. Das System erhält eine feste IP-Adresse, automatische Zeitsynchronisierung und eine deutsche UTF-8-Locale.

## 1. Voraussetzungen

- Raspberry Pi 4 mit 8 GB RAM
- USB-SSD mit mindestens 64 GB
- Debian-13-Linux-PC
- Ethernet-Verbindung
- USB-Boot-fähige Raspberry-Pi-Firmware
- SSH-Schlüssel für Administration und LUKS-Entsperrung

### Netzwerkkonfiguration

<table id="bkmrk-hostnamedarksideip-a"><colgroup><col></col><col></col></colgroup><tbody><tr><td>Hostname

</td><td>darkside

</td></tr><tr><td>IP-Adresse

</td><td>10.100.0.61

</td></tr><tr><td>Netzmaske

</td><td>255.255.0.0 (/16)

</td></tr><tr><td>Gateway

</td><td>10.100.0.1

</td></tr><tr><td>DNS

</td><td>1.1.1.1

</td></tr><tr><td>Interface

</td><td>eth0

</td></tr><tr><td>Zeitzone

</td><td>Europe/Berlin

</td></tr><tr><td>Locale

</td><td>de\_DE.UTF-8

</td></tr></tbody></table>

## 2. Datenträger vorbereiten

Die SSD besteht aus einer unverschlüsselten Boot-Partition und einer mit LUKS2 verschlüsselten Root-Partition.

<table id="bkmrk-partitionformatverwe"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><th>Partition

</th><th>Format

</th><th>Verwendung

</th></tr><tr><td>Partition 1

</td><td>FAT32

</td><td>/boot/firmware

</td></tr><tr><td>Partition 2

</td><td>LUKS2

</td><td>Verschlüsseltes Root-Dateisystem

</td></tr><tr><td>cryptroot

</td><td>ext4

</td><td>Debian und virtuelle Maschinen

</td></tr></tbody></table>

Alle folgenden administrativen Befehle werden als root ausgeführt.

Benötigte Pakete auf dem Linux-PC installieren:

```
apt update
apt install -y \
debootstrap \
debian-archive-keyring \
qemu-user \
qemu-user-binfmt \
binfmt-support \
cryptsetup \
parted \
dosfstools \
e2fsprogs \
ca-certificates
```

Datenträger identifizieren:

```
lsblk -o NAME,SIZE,MODEL,TYPE,MOUNTPOINTS
```

Im folgenden Beispiel wird /dev/sdb als Zielgerät verwendet. Die Gerätebezeichnung unbedingt prüfen. Alle Partitionen der SSD müssen ausgehängt sein.

**Achtung:** Die folgenden Befehle löschen sämtliche Daten auf dem ausgewählten Datenträger. Bei einem bereits installierten System diesen Abschnitt überspringen.

```
DISK=/dev/sdb

parted -s "$DISK" mklabel msdos
parted -s "$DISK" mkpart primary fat32 1MiB 1025MiB
parted -s "$DISK" mkpart primary 1025MiB 100%
parted -s "$DISK" set 1 boot on

partprobe "$DISK"
udevadm settle
```

Partitionen festlegen:

```
BOOT=/dev/sdb1
ROOT=/dev/sdb2
```

## 3. LUKS2-Verschlüsselung

Boot-Partition formatieren:

```
mkfs.vfat -F32 -n PVEBOOT "$BOOT"
```

Root-Partition mit AES-256-XTS und Argon2id verschlüsseln:

```
cryptsetup luksFormat \
--type luks2 \
--cipher aes-xts-plain64 \
--key-size 512 \
--pbkdf argon2id \
--pbkdf-memory 524288 \
--pbkdf-parallel 2 \
--iter-time 2000 \
--verify-passphrase \
"$ROOT"
```

Eine lange, zufällig erzeugte Passphrase verwenden. Die tatsächlichen Argon2-Parameter werden auf dem einrichtenden Rechner kalibriert und müssen später auf dem Raspberry Pi getestet werden.

LUKS-Partition öffnen:

```
cryptsetup open "$ROOT" cryptroot
```

Dateisystem erstellen:

```
mkfs.ext4 -L pve-root /dev/mapper/cryptroot
```

UUIDs ermitteln und notieren:

```
cryptsetup luksUUID "$ROOT"
blkid -s UUID -o value "$BOOT"
```

## 4. Debian installieren

Dateisysteme einhängen:

```
mkdir -p /mnt/Temp/1

mount /dev/mapper/cryptroot /mnt/Temp/1

mkdir -p /mnt/Temp/1/boot/firmware

mount "$BOOT" /mnt/Temp/1/boot/firmware
```

Debian 13 installieren:

```
debootstrap \
--arch=arm64 \
--keyring=/usr/share/keyrings/debian-archive-keyring.gpg \
trixie \
/mnt/Temp/1 \
https://deb.debian.org/debian
```

### Crypttab konfigurieren

```
nano /mnt/Temp/1/etc/crypttab
```

Eintrag:

```
cryptroot UUID=LUKS-UUID none luks,initramfs
```

LUKS-UUID durch die zuvor ermittelte UUID ersetzen.

### Fstab konfigurieren

```
nano /mnt/Temp/1/etc/fstab
```

Inhalt:

```
/dev/mapper/cryptroot / ext4 defaults,noatime 0 1
UUID=BOOT-UUID /boot/firmware vfat defaults,umask=0077 0 2
```

BOOT-UUID durch die UUID der FAT32-Partition ersetzen.

## 5. ARM64-chroot betreten

Systemdateisysteme einbinden:

```
for DIR in dev proc sys run; do
    mount --rbind "/$DIR" "/mnt/Temp/1/$DIR"
    mount --make-rslave "/mnt/Temp/1/$DIR"
done
```

DNS-Konfiguration für die Installation:

```
cp -L /etc/resolv.conf /mnt/Temp/1/etc/resolv.conf
```

ARM64-chroot betreten:

```
chroot /mnt/Temp/1 /bin/bash
```

Architektur prüfen:

```
dpkg --print-architecture
```

Die Ausgabe muss arm64 sein. Die folgenden Befehle werden innerhalb der chroot-Umgebung ausgeführt.

## 6. Debian-Basissystem

APT-Paketquellen prüfen:

```
nano /etc/apt/sources.list
```

Die folgenden Debian-Quellen verwenden. Gleichwertige vorhandene Einträge unter /etc/apt/sources.list.d nicht duplizieren.

```
deb https://deb.debian.org/debian trixie main non-free-firmware
deb https://deb.debian.org/debian trixie-updates main non-free-firmware
deb https://security.debian.org/debian-security trixie-security main non-free-firmware
```

Pakete installieren:

```
apt update

apt install -y \
linux-image-arm64 \
raspi-firmware \
initramfs-tools \
cryptsetup-initramfs \
dropbear-initramfs \
openssh-server \
ifupdown2 \
systemd-sysv \
systemd-timesyncd \
locales \
tzdata \
ca-certificates \
curl \
git \
nano \
less \
busybox
```

## 7. Locale konfigurieren

Das System erhält die deutsche UTF-8-Locale. Die Locale muss erzeugt werden, bevor sie von Shell, SSH und Programmen verwendet werden kann.

Locale-Konfiguration öffnen:

```
nano /etc/locale.gen
```

Folgende Zeile aktivieren:

```
de_DE.UTF-8 UTF-8
```

Falls ein Kommentarzeichen vor der Zeile steht, dieses entfernen.

Locale erzeugen:

```
locale-gen
```

Systemsprüngliche Locale setzen:

```
update-locale LANG=de_DE.UTF-8
```

Verfügbare Locales prüfen:

```
locale -a
```

Erwartete Ausgabe enthält:

```
de_DE.utf8
```

LC\_ALL wird nicht dauerhaft gesetzt. Programme erhalten die gewünschten Kategorieeinstellungen über LANG oder spezifische LC\_-Variablen.

### Zeitzone einstellen

Zeitzone konfigurieren:

```
ln -sfn /usr/share/zoneinfo/Europe/Berlin /etc/localtime

echo Europe/Berlin > /etc/timezone
```

Zeitzone prüfen:

```
date
```

In einer chroot-Umgebung stammt die aktuelle Uhrzeit vom Linux-Host. Die eigentliche Netzwerkzeitsynchronisierung erfolgt später auf dem Raspberry Pi.

## 8. NTP-Zeitsynchronisierung konfigurieren

Der Raspberry Pi besitzt normalerweise keine batteriegepufferte Echtzeituhr. Nach einem Neustart kann die Systemzeit deshalb falsch sein.

Eine falsche Uhrzeit kann HTTPS-Verbindungen und die Zertifikatsüberprüfung von APT verhindern.

Als Zeitdienst wird systemd-timesyncd verwendet.

Konfigurationsverzeichnis erstellen:

```
mkdir -p /etc/systemd/timesyncd.conf.d
```

Konfiguration bearbeiten:

```
nano /etc/systemd/timesyncd.conf.d/10-ntp.conf
```

Folgenden Inhalt eintragen:

```
[Time]
NTP=162.159.200.1 162.159.200.123 time.cloudflare.com 0.de.pool.ntp.org 1.de.pool.ntp.org
PollIntervalMinSec=32
PollIntervalMaxSec=2048
SaveIntervalSec=60
```

Die ersten beiden Adressen sind NTP-Server von Cloudflare. Sie sind auch ohne DNS-Auflösung erreichbar.

Für NTP muss ausgehender UDP-Verkehr auf Port 123 erlaubt sein.

Zeitdienst für den Systemstart aktivieren:

```
systemctl enable systemd-timesyncd.service
```

systemd-timesyncd wird beim regulären Systemstart aktiviert. Innerhalb von chroot wird kein laufender Zeitdienst benötigt.

Der Dienst speichert regelmäßig einen Zeitstempel, damit die Systemzeit bei späteren Neustarts nicht immer auf einen sehr alten Wert zurückfällt.

## 9. Netzwerk dauerhaft konfigurieren

Die Netzwerkverbindung im Initramfs ist unabhängig von der normalen Debian- Netzwerkkonfiguration.

Deshalb muss eth0 auch im installierten Debian-System eingerichtet werden.

Netzwerkdatei öffnen:

```
nano /etc/network/interfaces
```

Folgende Konfiguration verwenden:

```
# Loopback
auto lo
iface lo inet loopback

# Ethernet
auto eth0
iface eth0 inet static
    address 10.100.0.61/16
    gateway 10.100.0.1

# Weitere Interfaces
source /etc/network/interfaces.d/*
```

Die Management-IP liegt zunächst direkt auf eth0. Eine Linux-Bridge für virtuelle Maschinen wird erst nach erfolgreicher Einrichtung des Basissystems konfiguriert.

Die gleiche Management-IP darf später nicht gleichzeitig auf eth0 und vmbr0 liegen.

Netzwerkdienst aktivieren:

```
systemctl enable networking.service
```

### DNS konfigurieren

DNS-Konfiguration öffnen:

```
nano /etc/resolv.conf
```

Inhalt:

```
nameserver 1.1.1.1
```

Diese Konfiguration setzt voraus, dass /etc/resolv.conf als reguläre Datei verwaltet wird und kein anderer Netzwerkdienst ihren Inhalt automatisch ersetzt.

Für die Namensauflösung muss DNS über UDP beziehungsweise TCP Port 53 erreichbar sein.

## 10. Hostname konfigurieren

Hostname bearbeiten:

```
nano /etc/hostname
```

Inhalt:

```
darkside
```

Hosts-Datei bearbeiten:

```
nano /etc/hosts
```

Folgende Einträge verwenden:

```
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback

10.100.0.61 darkside.home.arpa darkside
```

Der Hostname muss auf die tatsächliche Management-IP des Servers auflösbar sein.

## 11. SSH-Zugang einrichten

Root-Passwort setzen:

```
passwd
```

Für den SSH-Zugang wird ein eigener Ed25519-Administrationsschlüssel verwendet.

Den öffentlichen Schlüssel auf dem administrierenden Linux-Client erzeugen:

```
ssh-keygen -t ed25519 -a 100 \
-f ~/.ssh/id_pi4_admin \
-C "Pi4 Administration"
```

Den privaten Schlüssel ausschließlich auf dem Linux-Client speichern.

Auf dem Raspberry-Pi-Dateisystem:

```
install -d -m 0700 /root/.ssh

nano /root/.ssh/authorized_keys
```

Den vollständigen öffentlichen Schlüssel aus id\_pi4\_admin.pub eintragen.

Dateirechte setzen:

```
chmod 0600 /root/.ssh/authorized_keys
```

SSH-Konfiguration erstellen:

```
nano /etc/ssh/sshd_config.d/10-security.conf
```

Inhalt:

```
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
X11Forwarding no
MaxAuthTries 3
```

SSH-Hostkeys erzeugen, falls sie fehlen:

```
ssh-keygen -A
```

SSH-Konfiguration prüfen:

```
sshd -t
```

SSH-Dienst aktivieren:

```
systemctl enable ssh.service
```

## 12. Initramfs-Netzwerk

Für die LUKS-Entsperrung wird eth0 bereits innerhalb des Initramfs aktiviert.

Datei öffnen:

```
nano /etc/initramfs-tools/initramfs.conf
```

Folgende Werte setzen:

```
MODULES=most
DEVICE=eth0
```

Die statische IP-Adresse wird über einen Kernelparameter konfiguriert.

Datei öffnen:

```
nano /etc/default/raspi-extra-cmdline
```

Folgende Zeile eintragen:

```
ip=10.100.0.61::10.100.0.1:255.255.0.0:darkside:eth0:none
```

Die Zeile darf keine zusätzlichen Zeilenumbrüche enthalten.

## 13. Raspberry-Pi-Firmware

Firmware-Konfiguration öffnen:

```
nano /etc/default/raspi-firmware
```

Folgende Werte setzen:

```
ROOTPART="/dev/mapper/cryptroot"
KERNEL="auto"
INITRAMFS="auto"
```

Die bestehende Konfiguration des Firmwarepakets ansonsten beibehalten.

Auf einem Raspberry Pi 4 mit USB-SSD können zusätzliche USB-Treiber im Initramfs benötigt werden, insbesondere reset\_raspberrypi.

Datei öffnen:

```
nano /etc/initramfs-tools/modules
```

Das benötigte Modul ergänzen, sofern es beim installierten Kernel als Modul vorliegt:

```
reset_raspberrypi
```

## 14. Dropbear für LUKS konfigurieren

Ein separater SSH-Schlüssel wird für die Entsperrung der LUKS-Partition verwendet.

Schlüssel auf dem Linux-Client erzeugen:

```
ssh-keygen -t ed25519 -a 100 \
-f ~/.ssh/id_pi4_unlock \
-C "Pi4 LUKS Unlock"
```

Dropbear-Verzeichnis erstellen:

```
install -d -m 0700 /etc/dropbear/initramfs
```

Authorized-Keys-Datei öffnen:

```
nano /etc/dropbear/initramfs/authorized_keys
```

Den öffentlichen Entsperrschlüssel mit folgenden Optionen eintragen:

```
no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="/bin/cryptroot-unlock" ssh-ed25519 SSH-PUBLIC-KEY
```

SSH-PUBLIC-KEY durch den vollständigen öffentlichen Ed25519-Schlüssel ersetzen.

Dateirechte setzen:

```
chmod 0600 /etc/dropbear/initramfs/authorized_keys
```

Dropbear konfigurieren:

```
nano /etc/dropbear/initramfs/dropbear.conf
```

Inhalt:

```
DROPBEAR_OPTIONS="-p 2222 -s -j -k -I 120"
```

Dropbear akzeptiert damit nur Schlüsselauthentifizierung auf Port 2222.

Die Hostkeys von Dropbear müssen vor dem ersten Verbindungsaufbau sicher dokumentiert und auf dem SSH-Client verifiziert werden.

## 15. Initramfs erstellen

Installierte Kernel-Version ermitteln:

```
ls /lib/modules
```

Die gewünschte Kernel-Version auswählen und das passende Initramfs erstellen.

Beispiel:

```
KVER=$(ls /lib/modules | sort -V | tail -n 1)

if [ -f "/boot/initrd.img-$KVER" ]; then
    update-initramfs -u -k "$KVER"
else
    update-initramfs -c -k "$KVER"
fi
```

Boot-Konfiguration prüfen:

```
cat /boot/firmware/config.txt
cat /boot/firmware/cmdline.txt
```

cmdline.txt muss auf /dev/mapper/cryptroot verweisen und den statischen ip-Parameter enthalten.

Initramfs-Inhalt überprüfen:

```
lsinitramfs "/boot/initrd.img-$KVER" | less
```

Besonders die Cryptsetup-Komponenten, Dropbear, authorized\_keys, cryptroot-unlock, USB- und Ethernet-Treiber kontrollieren.

## 16. Installation abschließen

chroot verlassen:

```
exit
```

Dateisysteme kontrollieren:

```
findmnt -R /mnt/Temp/1
```

Alle Ziel-Mountpoints aushängen:

```
umount -R /mnt/Temp/1
```

LUKS schließen:

```
cryptsetup close cryptroot
```

Schreibvorgänge abschließen:

```
sync
```

Die USB-SSD ist jetzt für den ersten Boot vorbereitet.

## 17. LUKS über SSH entsperren

Nach dem Start sollte Dropbear im Initramfs auf Port 2222 erreichbar sein.

SSH-Verbindung herstellen:

```
ssh -t \
-p 2222 \
-i ~/.ssh/id_pi4_unlock \
root@10.100.0.61
```

Den SSH-Hostkey mit dem zuvor dokumentierten Fingerprint vergleichen.

Anschließend die LUKS-Passphrase eingeben.

Nach erfolgreicher Entsperrung startet das normale Debian-System.

Reguläre SSH-Verbindung:

```
ssh -i ~/.ssh/id_pi4_admin root@10.100.0.61
```

## 18. Ersten Systemstart überprüfen

Netzwerk kontrollieren:

```
ip -br address
ip route show default
```

Erwartete Netzwerkkonfiguration:

```
eth0  UP  10.100.0.61/16
```

Namensauflösung prüfen:

```
getent ahostsv4 deb.debian.org
```

### Zeitsynchronisierung kontrollieren

Systemzeit anzeigen:

```
date
timedatectl status
```

Zeitdienst aktivieren:

```
systemctl enable --now systemd-timesyncd
```

Synchronisierungsstatus anzeigen:

```
timedatectl timesync-status
timedatectl show -p NTPSynchronized
```

Erwarteter Status nach erfolgreicher Synchronisierung:

```
NTPSynchronized=yes
```

Erst nach erfolgreicher Zeitsynchronisierung Paketdownloads und größere Systemupdates durchführen.

## 19. Fehlerbehebung: HTTPS-Zertifikate

Folgende Fehlermeldung kann auftreten, wenn die Systemzeit falsch ist:

```
SSL connection failed:
certificate verify failed
```

Aktuelle Zeit überprüfen:

```
date -u
```

NTP-Dienst kontrollieren:

```
systemctl status systemd-timesyncd --no-pager
timedatectl timesync-status
```

Falls NTP noch nicht zur Verfügung steht und die Uhr stark falsch geht, kann die Uhrzeit vorübergehend manuell auf einen vertrauenswürdigen aktuellen UTC-Wert gesetzt werden.

Beispiel mit dem aktuellen UTC-Zeitwert des Linux-Clients:

```
date -u -s "JAHR-MONAT-TAG STUNDE:MINUTE:SEKUNDE"
```

Die Platzhalter müssen durch eine tatsächlich aktuelle UTC-Zeit ersetzt werden.

Nach Korrektur der Uhrzeit kann APT erneut verwendet werden:

```
apt update
```

Falls der TLS-Fehler weiterhin besteht, anschließend CA-Zertifikate, Paketquellen und mögliche TLS-Interception prüfen.

Die HTTPS-Zertifikatsprüfung darf nicht deaktiviert werden.

## 20. Fehlerbehebung: Locale

Bei folgender Meldung fehlt die gewünschte Locale oder die SSH-Umgebung verwendet nicht unterstützte Locale-Werte:

```
setlocale: LC_CTYPE:
cannot change locale (de_DE.UTF-8)
```

Verfügbare Locales überprüfen:

```
locale -a
```

Locale-Konfiguration öffnen:

```
nano /etc/locale.gen
```

Folgende Zeile aktivieren:

```
de_DE.UTF-8 UTF-8
```

Locale neu erzeugen:

```
locale-gen
```

Standardeinstellung aktualisieren:

```
update-locale LANG=de_DE.UTF-8
```

Anschließend eine neue SSH-Sitzung öffnen. Die setlocale-Warnungen sollten verschwinden.

## 21. Fehlerbehebung: Netzwerk

Falls das Netzwerk im Initramfs funktioniert, aber nach der LUKS-Entsperrung ausfällt, die reguläre Netzwerkkonfiguration prüfen.

```
cat /etc/network/interfaces
ip -br address
ip route
```

/etc/network/interfaces muss die statische Konfiguration von eth0 enthalten.

Bei einem beschädigten oder unvollständigen System kann die verschlüsselte SSD auf einem anderen Linux-PC entschlüsselt und die Konfigurationsdatei repariert werden.

## 22. Proxmox VE vorbereiten

Erst wenn Debian, LUKS, SSH, Netzwerk und Zeitsynchronisierung zuverlässig funktionieren, wird die Virtualisierungsplattform eingerichtet.

Proxmox VE 9 stellt ARM64-Pakete bereit. Der Raspberry Pi 4 ist als Plattform jedoch nicht Teil der unterstützten Proxmox-Hardware.

Vor einer Installation müssen insbesondere die Paketabhängigkeiten und die Auswirkungen auf den Raspberry-Pi-Kernel geprüft werden.

Den funktionierenden Bootkernel, raspi-firmware, cryptsetup-initramfs und dropbear-initramfs nicht unkontrolliert ersetzen oder entfernen.

Vor dem Einrichten einer Proxmox-Bridge muss die bisherige Management-IP von eth0 auf vmbr0 umgestellt werden. Dabei darf die IP nicht doppelt vergeben werden.

Eine Aufnahme in einen bestehenden Proxmox-Cluster erfolgt erst nach vollständiger Funktionsprüfung.

## 23. Dokumentation

- [Debian – Raspberry Pi 4](https://wiki.debian.org/RaspberryPi4)
- [systemd-timesyncd – Konfiguration](https://manpages.debian.org/trixie/systemd-timesyncd/timesyncd.conf.5.en.html)
- [Debian – locale-gen](https://manpages.debian.org/trixie/locales/locale-gen.8.en.html)
- [Cryptsetup – Remote Unlock](https://cryptsetup-team.pages.debian.net/cryptsetup/README.Debian.html)
- [Cloudflare NTP](https://developers.cloudflare.com/time-services/ntp/usage/)
- [Proxmox VE Dokumentation](https://pve.proxmox.com/pve-docs/)