TL;DR
| |
Plus netconsole to another machine to learn why it went down (below).
The problem
A host with a LUKS-encrypted root (passphrase only, no TPM) freezes mid-morning. No power cut, the journal stops mid-line, no errors. Nobody notices until someone walks over and powers it on by hand: six hours down.
Three things stretch the outage and erase the evidence:
| Problem | Consequence | Fix |
|---|---|---|
| No watchdog | A frozen kernel waits for a human | Hardware watchdog petted by systemd |
kdump active (Ubuntu default) with kernel.panic=0 | The capture kernel needs the passphrase to write /var/crash, boots with no USB and no network, and waits forever | Turn kdump off, kernel.panic=10 |
| Passphrase-only LUKS root | Any unattended reboot stops at the prompt | dropbear in the initramfs |
| A hard freeze leaves nothing in the local journal | No way to find the cause | netconsole to another machine |
1. Hardware watchdog and reboot on panic
On Intel machines the chipset watchdog is iTCO_wdt. Ubuntu blacklists every watchdog driver, but that only stops automatic loading; loading it by name works:
| |
systemd pets it. If PID 1 stops petting for 60 s (frozen kernel), the chipset resets the machine. RebootWatchdogSec also bounds shutdowns that hang:
| |
| |
So that panics and lockups reboot instead of hanging:
| |
kernel.printk = 5 … raises the console level so warnings also go out over netconsole (step 3). hardlockup_panic needs the NMI watchdog, which is on by default.
kdump: with an encrypted root and no automatic unlock, its capture kernel cannot write the dump and sits at the passphrase prompt. Turn it off:
| |
And get back the memory it reserves. kdump-tools.cfg adds crashkernel= from /etc/default/grub.d/, and those files are read in alphabetical order: a file that strips it has to sort after it (zz-, not 99-):
| |
That way a package update cannot bring it back.
2. Unlock LUKS over SSH with dropbear
dropbear-initramfs puts a minimal SSH server in the initramfs, started before the disk is opened:
| |
Options in /etc/dropbear/initramfs/dropbear.conf (on older Debian/Ubuntu the file is /etc/dropbear-initramfs/config):
| |
| Option | Why |
|---|---|
-p 2222 | A different port from the real sshd: the host key differs, so known_hosts does not clash |
-s | No passwords, keys only |
-j -k | No port forwarding |
-I 300 | Drops idle sessions after 5 min |
-c cryptroot-unlock | Every login runs cryptroot-unlock and nothing else |
IFDOWN="*" | When done, takes the NIC down and flushes it so the real system configures it from scratch (matters if a bridge sits on top) |
Restricted public keys, one per line:
| |
Initramfs network with a static IP, without touching GRUB (kernel ip= syntax: client::gateway:netmask:hostname:device:autoconf):
| |
Use the physical NIC. If the system has a bridge (br0), it does not exist yet in the initramfs: name the interface that is its uplink.
Rebuild and check that everything made it in:
| |
Unlock
| |
Type the passphrase; the session closes by itself and the boot continues. The local keyboard still works in parallel: whichever answers first wins. The first time, compare the host key with the ones in /etc/dropbear/initramfs/dropbear_*_host_key:
| |
3. netconsole: make the crash log survive
A hard freeze gets nothing to disk. netconsole sends kernel messages over UDP to another machine from inside the kernel (netpoll), so they get out even when userspace is already dead.
On the host, through configfs and after the interface exists. The module option form (netconsole=… on the command line) runs before NetworkManager builds a bridge and is useless here:
| |
Put it in a oneshot service with After= and BindsTo= on sys-subsystem-net-devices-br0.device so it is set up on every boot. If the bridge is recreated while the system is up, the target is not re-armed by itself: restart the service.
On the other machine (physical, on the same segment: a VM on the same host goes down with it), a socat receiver that only accepts that host and writes to the journal:
| |
| |
The netconsole: … streaming line marks each boot; what comes before the last marker is the end of the previous boot. Look for Kernel panic, soft lockup, hard LOCKUP, NVRM: Xid, or PCIe/Thunderbolt AER errors.
Test it
| |
The full test, only with someone ready to unlock: echo c > /proc/sysrq-trigger triggers a panic. Its text should reach the receiver, the host reboots after 10 s and waits at the LUKS prompt.
Traps
- The previous kernel has no dropbear.
update-initramfs -uonly rebuilds the running kernel’s initramfs. If you boot the previous kernel from GRUB (the usual way out when a new one fails), its initramfs may predate dropbear: only the keyboard works there. Check withlsinitramfsor rebuild it withupdate-initramfs -u -k <version>. - LAN only. There is no VPN or Tailscale in the initramfs. To unlock from outside, advertise the host’s IP (
/32) from a subnet router that runs on another machine on the LAN. - “Host key changed”. Port 2222 has different keys from the normal sshd; the
known_hostsentry is[192.168.1.20]:2222. - The wrong NIC. If the cable is on a USB adapter or a dock and the IP is on the onboard NIC, the initramfs has no network. At the local console, look for
IP-Config: eno1 …. - netconsole does not show up in the host’s own
tcpdump: netpoll bypasses the capture taps. Look on the receiver. - Only messages below
console_loglevelgo out: with5, warnings and worse, neverinfoordebug. - Watchdog false positives: if systemd goes 60 s without petting it, the box reboots and you type the passphrase again. For kernel debugging, remove the
.confand runsystemctl daemon-reexec. - TPM2/clevis would unlock by itself, but also for anyone who walks off with the machine and powers it on. Here the passphrase over SSH won.