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:
| # | Ansatz | Backend | SSH-Server |
|---|---|---|---|
| 1 | systemd + mkinitcpio | systemd | tinyssh |
| 2 | Busybox + mkinitcpio | busybox | dropbear / tinyssh |
| 3 | systemd + dracut | systemd | openssh |
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:
r8169inMODULES=: sinnvoll. Mein Standard-Initramfs enthielt gar keine Netzwerk-Module.autodetectwürder8169zwar 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→encryptsshvorfilesystems.encryptsshmuss nachdropbearstehen, weil es die Passphrase über genau den SSH-Kanal empfängt, dendropbearzuvor öffnet; und vorlvm2/filesystems, damit das Crypto-Mapping existiert, bevor LVM scannt.encryptsshist ein kompatibler Ersatz fürencrypt, 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.