Passphrase-less reboots using kexec under NixOS
Passphrase-less reboots using kexec under NixOS
在 NixOS 下使用 kexec 实现无需密码的重启
Passphrase-less reboots using kexec under NixOS by Dr. Katja Flinzner Wanja Hentze 17 August 2026 在 NixOS 下使用 kexec 实现无需密码的重启 —— 作者:Dr. Katja Flinzner, Wanja Hentze,2026年8月17日
Encrypted hard drives protect data, including in the event of theft. Even if entire racks are carried out of the server room: without the correct passphrase for disk encryption, the hard drives are of little use. So of course we encrypt them. So far, so obvious. 加密硬盘可以保护数据,即使在设备被盗的情况下也是如此。即便整个机架被从机房搬走,如果没有正确的磁盘加密密码,这些硬盘也几乎毫无用处。因此,我们当然会对它们进行加密。到目前为止,这显而易见。
This security, however, comes at a price. Every instance of human intervention during a reboot costs time and increases the risk of errors: if the boot process is interrupted, whether due to distraction or any imaginable incident, the server gets stuck at the password prompt and fails to boot up again. 然而,这种安全性是有代价的。重启过程中每一次的人工干预都会耗费时间并增加出错风险:如果启动过程被中断(无论是由于分心还是任何不可预见的事故),服务器就会卡在密码提示界面,导致无法重新启动。
We sometimes find ourselves needing to reboot servers more frequently. While a lot of software can be updated or reconfigured on the fly, this option stops at the Linux kernel: eventually, a reboot is required. That’s why we wanted a solution that allows us to reboot servers without the need for a manual decryption step. 我们有时发现自己需要更频繁地重启服务器。虽然许多软件可以在运行过程中进行更新或重新配置,但这一方案在 Linux 内核层面就止步了:最终,重启是不可避免的。这就是为什么我们想要一个能够让我们在无需手动解密步骤的情况下重启服务器的解决方案。
Of course, one could try to automate our existing process, letting another computer with access to the passphrase connect to the rebooting server via SSH and decrypt it. However, this type of automation is tricky, because it turns the whole thing into a distributed system, with all the problems that entails. We wanted a solution in NixOS that does not depend on another computer, but retains the security of our existing solution. And that’s what we have achieved using kexec. 当然,人们可以尝试自动化现有的流程,让另一台拥有密码的计算机通过 SSH 连接到正在重启的服务器并进行解密。然而,这种自动化方式很棘手,因为它将整个过程变成了一个分布式系统,并带来了随之而来的所有问题。我们想要的是一种在 NixOS 中不依赖于其他计算机,同时又能保持现有解决方案安全性的方案。而这正是我们通过使用 kexec 所实现的。
Faster reboots with kexec
使用 kexec 加速重启
The kexec mechanism lets the kernel (k) execute another kernel (exec). Which means: The running kernel replaces itself with a new one without the actual server (i.e. the hardware) being shut down and restarted. Only the operating system restarts. kexec 机制允许内核 (k) 执行另一个内核 (exec)。这意味着:正在运行的内核会用一个新的内核替换自己,而无需关闭并重启实际的服务器(即硬件)。只有操作系统会重新启动。
The clever part: the old kernel can make information available in RAM that the new kernel can use. A passphrase for decrypting the hard drive, for example. As a nice side effect, we skip the firmware and bootloader parts of the reboot, saving several minutes of rebooting time, particularly on servers. 巧妙之处在于:旧内核可以将信息保留在内存 (RAM) 中供新内核使用。例如,用于解密硬盘的密码。一个很好的副作用是,我们跳过了重启过程中的固件和引导加载程序部分,从而节省了数分钟的重启时间,这在服务器上尤为明显。
Securely passing passphrases
安全地传递密码
The LUKS passphrase could also be passed by simply writing it into a file before the reboot. But there’s a catch: During a full reboot, the system shuts down completely. For the newly starting kernel to be able to read this file, it would have to be stored unencrypted, which would undermine the security of our hard drive encryption. LUKS 密码也可以通过在重启前将其写入文件来传递。但有一个问题:在完全重启期间,系统会彻底关闭。为了让新启动的内核能够读取该文件,它必须以未加密的形式存储,这会破坏我们硬盘加密的安全性。
With kexec, the data can be passed via the server’s volatile RAM. This is a bit tricky though. In this article, we’ll show you how we implemented it. 使用 kexec,数据可以通过服务器的易失性内存 (RAM) 进行传递。但这有点复杂。在本文中,我们将向您展示我们是如何实现这一点的。
Security and convenience – both is possible
安全与便捷——两者兼得
You can’t have your cake and eat it, too? We simply didn’t want to accept this supposed wisdom for the matter of rebooting our servers. We want all of it: the security of full-disk encryption, of course, but also convenience, speed and reliable reboots. And if there’s one thing we don’t do, it’s giving up quickly just because something doesn’t work straight away. 鱼和熊掌不可兼得?我们根本不想在服务器重启这件事上接受这种所谓的“智慧”。我们全都要:当然包括全盘加密的安全性,但也包括便捷、快速和可靠的重启。如果我们有什么原则,那就是绝不会因为事情没有立即成功就轻易放弃。
So we set out to find a solution and came across two interesting sources with different approaches: A comment in a lobste.rs thread. The blog article “Encrypted NixOS home server with passwordless reboot”. Both approaches have their pros and cons; neither was quite enough for us. That’s why we took the best bits from both and built our own solution. 因此,我们着手寻找解决方案,并发现了两个采用不同方法的有趣来源: lobste.rs 线程中的一条评论。 博客文章《带有无密码重启功能的加密 NixOS 家庭服务器》。 这两种方法各有利弊;但都不完全符合我们的需求。这就是为什么我们汲取了两者之长,构建了自己的解决方案。
Approach No. 1: One-time passphrases
方法一:一次性密码
We generate a temporarily valid passphrase. But we don’t stop there. Because you can manage multiple keyslots in LUKS. So we also create a keyslot, assign this temporary passphrase to it, and delete the keyslot immediately after a successful kexec. This ensures our encryption remains secure even if the temporary passphrase were to be leaked for any reason. 我们生成一个临时有效的密码。但我们不仅限于此。因为你可以在 LUKS 中管理多个密钥槽 (keyslots)。因此,我们还创建了一个密钥槽,将此临时密码分配给它,并在 kexec 成功后立即删除该密钥槽。这确保了即使临时密码因任何原因泄露,我们的加密依然安全。
Approach No. 2: Do not pass the passphrase on the command line
方法二:不在命令行中传递密码
Even though the passphrase is invalidated immediately on the next boot, we want to take extra care to ensure that nobody can read it from the kernel command line, not even in the brief moment it takes us to invalidate the one-time passphrase. We therefore use the technique described in the blog post mentioned above: the one-time passphrase is embedded in a special initramdisk image, which is created specifically just before the kexec reboot. 尽管密码在下次启动时会立即失效,但我们仍希望格外小心,确保没有人能从内核命令行中读取它,即使是在我们使一次性密码失效的那短暂瞬间也不行。因此,我们使用了上述博客文章中描述的技术:将一次性密码嵌入到一个特殊的 initramdisk 镜像中,该镜像是在 kexec 重启前专门创建的。
Our solution for passphrase-less reboots
我们实现无密码重启的方案
And this is our specific solution: We extend systemd.services."prepare-kexec" with the following steps:
这就是我们的具体解决方案:我们通过以下步骤扩展了 systemd.services."prepare-kexec":
- We create a temporary LUKS passphrase in an additional key slot.
- 我们在额外的密钥槽中创建一个临时的 LUKS 密码。
- We create a new initrd image and add a file containing the key (in RAM).
- 我们创建一个新的 initrd 镜像,并添加一个包含该密钥的文件(位于内存中)。
- We configure the use of this key file via the kernel command line and enable a fallback to manual passphrase entry.
- 我们通过内核命令行配置该密钥文件的使用,并启用手动输入密码的备选方案。
- Immediately after mounting the root filesystem, we remove the key slot via a custom systemd unit defined in
boot.initrd.systemd.services. - 在挂载根文件系统后,我们立即通过在
boot.initrd.systemd.services中定义的自定义 systemd 单元删除该密钥槽。
Our uninterrupted 2-minute reboot today
我们如今不间断的 2 分钟重启
Today, our reboot no longer requires any manual intervention. And it now takes just over 2 minutes. A simple systemctl start kexec.target is all that’s needed. Whether triggered manually or automatically, the server comes back up fully functional and ready for use.
如今,我们的重启不再需要任何人工干预。现在只需 2 分多钟即可完成。只需执行简单的 systemctl start kexec.target 即可。无论是手动触发还是自动触发,服务器都能恢复正常运行并随时可用。
Passphrase-less reboots on NixOS to go
NixOS 上的无密码重启方案
Would you like our complete implementation as ready-to-use code? You can find our code in a sample configuration below this article. Enjoy! 您想要我们完整的实现代码吗?您可以在本文下方的示例配置中找到我们的代码。尽情使用吧!
Sample NixOS module:
NixOS 模块示例:
{ config, lib, pkgs, ...}:
let
luksDevice = config.boot.initrd.luks.devices."yourdevice".device;
in {
# Concept:
# To reboot a server using kexec, we need to alter the nixos
# prepare-kexec script, because we use full disk encryption.
# We add a temporary, random key to LUKS keyslot 31. This key is
# also added to the init ram disk image.
# We have to set the keyfile and fallbackToPassword option in the
# luks.device."yourdevice". If the keyfile exists it will be used to
# decrypt the disk, if not it will ask for the passphrase.
# We immediately delete the LUKS slot after mounting.
systemd.services."prepare-kexec" = {
path = with pkgs; [ cpio cryptsetup gzip ];
script = lib.mkForce ''
set -euo pipefail
umask 0077
# Don't load the current