Install and Remove Linux Kernels Safely with kernel-install
You will use systemd's kernel-install to see where a kernel would be installed, add a kernel and initrd to the boot partition, check the resulting inventory, and remove an old version when you no longer need it. The examples target the systemd 255 interface shipped by Ubuntu 24.04 on the machine used for this guide. Allow 10 to 20 minutes for a normal install, plus time to confirm that the new entry is visible before rebooting.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
You need a root shell or sudo, a kernel image, any initrd files it needs, and a working boot partition. Do not run add or remove on a production machine until you have identified the exact kernel version. Adding files changes the boot path; removing a version can make it unavailable at the next boot.
The kernel image is normally expected at /usr/lib/modules/KERNEL_VERSION/vmlinuz. Distribution packaging may instead leave it under /boot, so check rather than guessing.
uname -r
ls -l /usr/lib/modules/"$(uname -r)"/vmlinuz /boot/vmlinuz-"$(uname -r)" 2>/dev/null
kernel-install --version
On the reference system, the version check reports systemd 255. Features used below include inspect from systemd 251 and list from systemd 255. Older releases may not have those commands.
Checkpoint 1: inspect the installation inputs
Start with inspect. It shows the paths and KERNEL_INSTALL_* values that would be passed to plugins. If the default image path is absent or unreadable, give the kernel image and initrd paths explicitly. The inspection does not add or remove a boot entry.
sudo kernel-install --no-pager inspect --json=pretty \
KERNEL_VERSION \
/path/to/vmlinuz-KERNEL_VERSION \
/path/to/initrd.img-KERNEL_VERSION
Replace each placeholder, including KERNEL_VERSION, with a real value. The command can also be run without sudo when the files are readable, but privileged access is often needed for images in /boot. A common failure is an error saying that the image is not installed at the default /usr/lib/modules/.../vmlinuz; that means you need the explicit image argument, not that the boot entry has already been changed.
Check the output for the boot root, entry token and layout. The boot root is usually /boot or an EFI-mounted path. The default layout is automatic: systemd selects the Unified Kernel Image layout for a UKI, the Boot Loader Specification Type 1 layout when its markers are present, and otherwise an external layout. Do not assume that every machine uses systemd-boot.
Checkpoint 2: understand the name and title
Entries are grouped under an entry token. With the default --entry-token=auto, /etc/kernel/entry-token is used when present; otherwise systemd prefers the machine ID, then IMAGE_ID, then ID from os-release, with a generated fallback. The token is not the same thing as the kernel version.
That distinction matters when checking the filesystem. For a Type 1 entry, the default loader plugin places the kernel and initrds below $BOOT/ENTRY_TOKEN/KERNEL_VERSION/ and writes a loader entry below $BOOT/loader/entries/. For a UKI, it places the image below $BOOT/EFI/Linux/. The boot menu title comes from PRETTY_NAME in /etc/os-release, falling back to Linux KERNEL_VERSION.
os-release is a shell-compatible set of assignments, not a general shell script. /etc/os-release takes precedence over /usr/lib/os-release, and readers should use one file only. For example, this safely displays the value without sourcing vendor data into your shell:
grep -E '^(PRETTY_NAME|ID|IMAGE_ID)=' /etc/os-release /usr/lib/os-release 2>/dev/null
Checkpoint 3: add the kernel
Once the version and files are confirmed, run add as root. Pass initrds in the order required by your boot process. If microcode must precede the main initrd, follow your distribution's documented ordering.
sudo kernel-install --no-pager add \
KERNEL_VERSION \
/path/to/vmlinuz-KERNEL_VERSION \
/path/to/initrd.img-KERNEL_VERSION
The command invokes executable .install plugins from /usr/lib/kernel/install.d/ and /etc/kernel/install.d/, sorted together lexically. A same-named file in /etc replaces the vendor file in /usr/lib. The standard plugins may run depmod, create the entry directory, copy the kernel and initrd, or copy a UKI. A plugin returning 77 stops later plugins while the overall operation is still considered successful; any other non-zero failure is an error.
Do not edit the generated loader file by hand to repair an installation. Fix the input path, layout or plugin configuration, then repeat the operation after checking the failure.
Checkpoint 4: verify before rebooting
Use list to see the kernel directories under /usr/lib/modules and whether each has a kernel image. This command is available from systemd 255.
kernel-install --no-pager list
sudo kernel-install --no-pager inspect --json=pretty \
KERNEL_VERSION \
/path/to/vmlinuz-KERNEL_VERSION \
/path/to/initrd.img-KERNEL_VERSION
A useful check is that the requested version appears in the inventory and that inspection now resolves the same boot root and entry token as before. Also inspect the relevant generated path under /boot or the mounted EFI/XBOOTLDR filesystem. Only reboot after the new files and loader entry are present and you have a fallback kernel available.
Remove an old kernel
Removal is destructive to that installed boot entry. Record the exact version first and keep the currently running version until another entry has booted successfully. Then run:
uname -r
kernel-install --no-pager list
sudo kernel-install --no-pager remove OLD_KERNEL_VERSION
The remove plugins delete generated dependency data and the loader entry, after which kernel-install removes the version's entry directory if it exists. Verify that the target version has gone, while the version reported by uname -r remains available. If you removed the wrong entry, reinstall it with the distribution package that owns the kernel and initrd, then run kernel-install add again with the correct paths. Do not reconstruct a missing initrd by copying a random file from another version.
Done means
inspectidentified the intended boot root, entry token and layout.addcompleted for the exact kernel version and its intended initrds.listand a secondinspectshow the expected installed version.- You have not removed the running or only known-good fallback kernel.
- For removal, the old entry is absent and a known-good entry remains.