Wer eine vollverschlüsselte Workstation im Keller, im Rack oder remote neu starten will, kennt das Problem: Der Rechner hängt beim Booten an der LUKS-Passphrasen-Abfrage, und niemand ist vor Ort, um sie einzutippen. Die Lösung ist ein leichtgewichtiger SSH-Server, der schon im Initramfs läuft, bevor die Root-Partition gemountet wird. Man verbindet sich von außen, tippt die Passphrase über die SSH-Verbindung und der Rechner bootet normal weiter.

Ich beschreibe unten, wie ich das auf meiner Arch-Linux-Workstation eingerichtet habe, welche Variante ich gewählt habe und was bei Problemen hilft. Gedacht ist das Setup für ein Einzelgerät im Homelab; für produktive Server würde ich andere Wege evaluieren.

Getestet mit: Arch Linux (Rolling, Stand Oktober 2026), Kernel 7.2.7, mkinitcpio-extras 5-1, dropbear 2026.94.

Ausgangslage

Mein Rechner ist ein klassisches Single-LUKS-Container-Setup:

nvme0n1
├── nvme0n1p1  → /efi              (vfat, unverschlüsselt)
├── nvme0n1p2  → /boot             (ext4, unverschlüsselt)
└── nvme0n1p3  → crypto_LUKS       → cryptlvm (LVM PV)
                                       ├── vg0/root  → /
                                       ├── vg0/home  → /home
                                       └── vg0/swap  → swap

Eine Passphrase entsperrt den Container, LVM kümmert sich um den Rest. Bootloader ist GRUB 2.12 (UEFI), Initramfs-Backend ist mkinitcpio mit den klassischen Hooks (udev, encrypt) auf Basis der Busybox-Variante. Mkinitcpio baut das Initramfs aus einzelnen Bausteinen, genannt Hooks; die traditionelle Variante nutzt Busybox als Werkzeugsammlung im frühen Boot, udev ist der Geräte-Manager, der Hardware erkennt und Netzwerkschnittstellen ihre modernen Namen (enp14s0 usw.) gibt. Netzwerk läuft über NetworkManager, die primäre Karte ist eine Realtek-Karte (Treiber r8169) als enp14s0. In der Initramfs-Phase gilt jedoch der Kernel-Name eth0, darauf kommen wir in Schritt 4 zurück.

Die Varianten im Arch-Wiki und meine Wahl

Das Arch-Wiki beschreibt unter Dm-crypt/Specialties#Remote_unlocking_of_root_(or_other)_partition drei Wege, die sich in Initramfs-Backend und SSH-Server unterscheiden:

#AnsatzBackendSSH-Server
1systemd + mkinitcpiosystemdtinyssh
2Busybox + mkinitcpiobusyboxdropbear / tinyssh
3systemd + dracutsystemdopenssh

Eine Fußnote aus dem Wiki: Die alten Empfehlungen mkinitcpio-netconf, mkinitcpio-dropbear und mkinitcpio-tinyssh gelten als unmaintained und sollten nicht mehr verwendet werden. Die aktuellen Pakete für Weg 2 sind mkinitcpio-utils (offizielles Repo extra, liefert encryptssh) und mkinitcpio-extras (AUR, liefert netconf und dropbear); für Weg 1 mkinitcpio-systemd-extras (AUR). Dropbear-Homepage: https://matt.ucc.asn.au/dropbear/dropbear.html.

Ich habe Weg 2 umgesetzt: Busybox-basierte mkinitcpio mit Dropbear. Er passt zu einer bestehenden udev/encrypt-Konfiguration, kommt ohne paralleles systemd-networkd-Setup aus und ist ein minimaler Eingriff in die bisherige mkinitcpio.conf: die Hooks netconf und dropbear ergänzen, encrypt gegen encryptssh austauschen und r8169 in MODULES= eintragen (Pinning, siehe Schritt 3). Wer ohnehin schon eine systemd-basierte Initramfs fährt oder dracut nutzt, sollte die entsprechenden Alternativen betrachten.

Umsetzung

Schritt 1: Pakete

mkinitcpio-utils (offizielles Repo extra) liefert den encryptssh-Hook, mkinitcpio-extras (AUR, installiert via AUR-Helper, hier yay; alternativ paru oder manueller makepkg -si-Bau) die Hooks netconf und dropbear. Wer noch das Paket mkinitcpio-nfs-utils installiert hat, muss es vorher entfernen. mkinitcpio-extras bringt einen eigenen netconf-Hook mit und kollidiert damit:

sudo pacman -Rns mkinitcpio-nfs-utils

Erst dann installieren:

sudo pacman -S dropbear mkinitcpio-utils
yay -S mkinitcpio-extras

Die Hooks netconf, dropbear, encryptssh stehen danach unter /usr/lib/initcpio/install/ (Install-Seite) bzw. /usr/lib/initcpio/hooks/ (Laufzeit-Seite) zur Verfügung.

Schritt 2: SSH-Key hinterlegen

Während des Initramfs ist die Root-Partition (und damit auch /root und /home) verschlüsselt, die normale ~/.ssh/authorized_keys ist also physisch nicht lesbar. Der dropbear-Hook liest statisch /etc/dropbear/root_key (Arch-Pfad, nicht der Debian-Pfad /etc/dropbear/initramfs/authorized_keys). Die Anmeldung erfolgt als root, einen regulären Benutzer gibt es in dieser Phase nicht.

sudo install -d -m 700 /etc/dropbear
# Statt user@example.com den Kommentar des gewünschten Keys nehmen:
grep "user@example.com" ~/.ssh/authorized_keys \
  | sudo tee /etc/dropbear/root_key > /dev/null
sudo chmod 600 /etc/dropbear/root_key

Ich habe einen bestehenden RSA-Key wiederverwendet, der ohnehin auf allen meinen Geräten liegt. Wer Schlüssel streng getrennt hält, generiert stattdessen einen dedizierten Key nur für diesen Zweck: Er lässt sich gezielt rotieren, falls ein Gerät kompromittiert wird, und die LUKS-Entsperrung hängt nicht an Keys, die anderweitig im Einsatz sind. Dafür muss man auf jedem Unlock-Gerät einen weiteren Private Key verwalten. Der Private Key sollte in jedem Fall passphrasengeschützt sein.

Für den Notfall lohnt sich ein zweiter LUKS-Keyslot mit einer anderen Passphrase (cryptsetup luksAddKey /dev/nvme0n1p3, fragt zuerst die bestehende Passphrase ab), damit man auch dann noch entsperren kann, wenn die primäre Passphrase vergessen wurde oder kein Unlock-Client greifbar ist.

Schritt 3: mkinitcpio.conf anpassen

Vor der Änderung ein Backup anlegen. Wir brauchen es im Rollback:

sudo cp /etc/mkinitcpio.conf /etc/mkinitcpio.conf.bak.$(date +%F)
sudo cp /etc/default/grub /etc/default/grub.bak.$(date +%F)

Dann die beiden Zeilen anpassen:

- MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)
+ MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm r8169)

- HOOKS=(base udev autodetect microcode modconf keyboard keymap consolefont block encrypt lvm2 filesystems fsck)
+ HOOKS=(base udev autodetect microcode modconf keyboard keymap consolefont block netconf dropbear encryptssh lvm2 filesystems fsck)

Zwei Details:

  • r8169 in MODULES=: sinnvoll. Mein Standard-Initramfs enthielt gar keine Netzwerk-Module. autodetect würde r8169 zwar beim Neubau ziehen, weil die Karte aktiv ist, aber das Pinning schützt vor Sonderfällen, wenn das Image mal ohne aktive Karte gebaut wird, etwa aus einem chroot oder Live-System.
  • Hook-Reihenfolge: netconf → dropbear → encryptssh vor filesystems. encryptssh muss nach dropbear stehen, weil es die Passphrase über genau den SSH-Kanal empfängt, den dropbear zuvor öffnet; und vor lvm2/filesystems, damit das Crypto-Mapping existiert, bevor LVM scannt. encryptssh ist ein kompatibler Ersatz für encrypt, der lokal weiterhin funktioniert.

Schritt 4: Kernel-Parameter für die IP

Der netconf-Hook wertet den Kernel-Parameter ip= aus. Für DHCP reicht ip=dhcp, ich wollte aber eine statische Adresse:

ip=<ipv4>::<gateway>:<netmask>:<hostname>:<interface>:none

Wichtig zum <interface>-Feld: In der Initramfs-Phase gilt der Kernel-Name des Interfaces (eth0), nicht der udev-Name (enp14s0). Udev benennt erst später um. Also eth0 eintragen, nicht den Namen, den das Interface im laufenden System trägt.

eingebaut in /etc/default/grub:

- GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=<uuid>:cryptlvm:allow-discards loglevel=3 nvidia-drm.modeset=1 drm.modeset=1"
+ GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=<uuid>:cryptlvm:allow-discards loglevel=3 nvidia-drm.modeset=1 drm.modeset=1 ip=192.168.0.10::192.168.0.1:255.255.255.0:myhost:eth0:none"

Danach sudo grub-mkconfig -o /boot/grub/grub.cfg und kontrollieren, dass der ip=-Parameter in der generierten grub.cfg auftaucht. Bei mir stand er korrekt in beiden Menü-Einträgen (default und fallback).

Schritt 5: Initramfs neu bauen

-P baut alle Presets (Profildateien, siehe unten); wer nur das laufende Kernel-Paket bauen will, nimmt -p linux. Der dropbear-Hook lauscht per Default auf Port 2222; änderbar via Kernel-Parameter dropbear_port=<port> in GRUB_CMDLINE_LINUX_DEFAULT.

sudo mkinitcpio -P

In der Ausgabe sah ich die Hooks in der richtigen Reihenfolge laufen. Dropbear generierte beim ersten Bau automatisch eigene Host-Keys (rsa/ecdsa/ed25519) unter /etc/dropbear/. Niemals die Host-Keys des produktiven sshd weiterverwenden. Das Initramfs liegt als Datei unverschlüsselt in /boot und ist für jeden lesbar, der an die Platte kommt; die privaten Host-Keys wären damit kompromittiert und ließen sich für Man-in-the-Middle-Angriffe auf künftige Unlock-Sessions nutzen.

Wer physischen Zugriff zum Rechner hat, kann außerdem das gesamte Initramfs austauschen und die eingegebene Passphrase abfangen. Dieses Setup schützt nicht vor Evil-Maid-Angriffen. Gegenmaßnahmen wären Secure Boot mit signiertem Initramfs oder ein verschlüsselter /boot-Bereich, beides außerhalb des Rahmens dieser Anleitung.

Verifikation vor dem Reboot

Vor dem Reboot will man wissen, dass alles im Image gelandet ist. Das Werkzeug dafür heißt lsinitcpio:

IMG=/boot/initramfs-linux.img

# Treiber für die Netzwerkkarte?
lsinitcpio "$IMG" | grep r8169
# → usr/lib/modules/…/drivers/net/ethernet/realtek/r8169.ko.zst

# Dropbear-Binary?
lsinitcpio "$IMG" | grep -E 'dropbear$'
# → usr/bin/dropbear

# Hinterlegter Public Key?
lsinitcpio "$IMG" | grep root_key
# → etc/dropbear/root_key

# Krypto-Stack?
lsinitcpio "$IMG" | grep -E 'cryptsetup$|dm-crypt'
# → usr/bin/cryptsetup, usr/lib/modules/…/dm-crypt.ko.zst

Bei mir waren alle Komponenten da: r8169.ko.zst, usr/bin/dropbear, etc/dropbear/root_key, die frischen Host-Keys, usr/bin/cryptsetup, dm-crypt.ko.zst, usr/bin/lvm und usr/bin/ipconfig für die statische IP. Erst dann habe ich rebootet.

Reboot und erster Test

sudo reboot

Vom Unlock-Client aus:

ssh -p 2222 root@192.168.0.10

Beim ersten Mal erwartet man eine Man-in-the-Middle-Warnung. Dropbear hat eigene Host-Keys, die sich von denen des produktiven sshd unterscheiden. Vor dem Akzeptieren den Fingerprint verifizieren (nach dem Bau mit dropbearkey -y -f /etc/dropbear/dropbear_ed25519_host_key | ssh-keygen -lf - ausgeben und notiert), sonst ist die Warnung wirkungslos. Danach:

Please unlock disk cryptlvm:
cryptsetup: cryptlvm set up successfully
Shared connection to 192.168.0.10 closed.

Die Verbindung schließt sich, 30–60 Sekunden später bootet das System durch und der reguläre sshd ist erreichbar.

Bleibt der SSH-Unlock aus, wartet encryptssh nicht endlos: Nach der regulären lokalen Passphrase-Abfrage (die parallel läuft) gibt das System irgendwann auf oder bootet in eine Notfall-Shell, je nach Konfiguration. Wer remote sitzt und keine Verbindung aufbauen kann, hat zwei Optionen: lokal an die Konsole gehen, oder den Reboot abbrechen und von vorn. Ein automatischer Fallback auf “boot ohne Entschlüsselung” gibt es nicht.

Praxistipp für die ~/.ssh/config auf dem Unlock-Client (Pfad des IdentityFile an den eigenen Key anpassen, bei mir der wiederverwendete RSA-Key):

Host myhost-unlock
  HostName 192.168.0.10
  Port 2222
  User root
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes
  UserKnownHostsFile ~/.ssh/known_hosts.myhost.initramfs

Der separate known_hosts-Eintrag verhindert Konflikte mit den produktiven Host-Keys desselben Rechners.

Rollback

Vorab: Der Rollback unten funktioniert nur, wenn das System noch bootet. Die .bak-Dateien liegen auf der verschlüsselten Root-Partition und sind nicht erreichbar, wenn das Initramfs kaputt ist. Für den echten Notfall (System bootet nicht mehr) braucht es die Live-USB/arch-chroot-Prozedur: vom Installationsmedium booten, cryptsetup open /dev/nvme0n1p3 cryptlvm, vgchange -ay, Root- und Boot-Partitionen nach /mnt mounten, arch-chroot /mnt, und erst dann die folgenden Befehle.

Falls beim ersten Versuch etwas hakt, greift lokal weiterhin die Passphrase-Abfrage an der Konsole. encryptssh ist abwärtskompatibel zu encrypt. Zurück auf Anfang geht es mit den Backups aus Schritt 3 (Dateiname durch das jeweilige Datum ersetzen):

sudo cp /etc/mkinitcpio.conf.bak.<datum> /etc/mkinitcpio.conf
sudo cp /etc/default/grub.bak.<datum> /etc/default/grub
sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo mkinitcpio -P

Fazit

Remote-Unlock über Dropbear im Initramfs ist etablierte Technik. Auf Arch Linux mit den richtigen Hooks lässt sich das unkompliziert umsetzen. Weg 2 war für mein Setup die Variante mit dem kleinsten Eingriff: kein Backend-Wechsel, keine parallelen Konfigurationen, zwei Hooks ergänzt, encrypt gegen encryptssh getauscht, ein Modul gepinnt. Fertig.

Wer ohnehin schon systemd-basierte Initramfs fährt oder dracut nutzt, sollte die entsprechenden Alternativen aus dem Wiki betrachten. Für eine bestehende Busybox-basierte mkinitcpio-Konfiguration ist das mein Standardweg.