home blog misc about

Rebooting my server via kexec

The server this website is running on is a dedicated server hosted at Strato AG netcup1. While I’m very happy with their services in general, the server apparently spends about 60 seconds in the BIOS boot menu before (re)booting. This became somewhat annoying over time, so I tried something rather outlandish: abusing the kexec feature to reboot my server.

This guide is written with a focus on NixOS, but it can be applied to pretty much any systemd-based distribution.

What is kexec?

kexec is a feature of the Linux kernel that allows you to stop the execution of the current Linux system and start executing a new kernel without rebooting. To use it, the CONFIG_KEXEC kernel option needs to be set, which is usually the case. The userspace tools are packaged in kexec-tools on most distributions.

Using kexec is pretty simple. To load a new kernel into memory, run:

# kexec -l new_kernel_image --initrd=new_initrd --append=new_command_line_options

Stop the current system and run the new one:

# kexec -e

Note that this will effectively crash your current system, so on systemd-based distributions, one should use

# systemctl kexec

to gracefully shut down all services before executing the new kernel.

Integrating this into NixOS

To effectively use this on NixOS, I wrote a simple bash script:

cmdline="init=$(readlink -f /nix/var/nix/profiles/system/init) $(cat /nix/var/nix/profiles/system/kernel-params)"
kexec -l /nix/var/nix/profiles/system/kernel --initrd=/nix/var/nix/profiles/system/initrd --command-line="$cmdline"
systemctl kexec

You can then add this to your configuration via something like:

environment.systemPackages = [ pkgs.writeShellScriptBin "reboot-kexec" (builtins.readFile ./reboot-kexec.sh) ];

This will kexec into the currently selected configuration, which is mainly useful for rebooting after auto-updating the server if kernel modules have changed.

Other distros

Just look up where your distro stores its kernels and initrds, and replace the values in the script above accordingly (and remove the init= cmdline parameter).

Reliability

I’ve been rebooting my server like this for a year now, and nothing bad ever happened ^-^