Migrating from Grub2 to systemd-boot
I noticed that openSUSE MicroOS (and Aeon which is my daily driver) started supporting systemd-boot in 2024. Because of this I’ve read that systemd-boot is more efficient and faster than grub2 as a bootloader so I decided to migrate my Aeon RC1 to systemd-boot manually. It should be noted that when I installed my version grub2 was the only supported option, the newer RC of Aeon actually offers systemd-boot as an option during the installation process, but still defaults to grub2.
The Setup
I thought this would be an easy process, openSUSE outlines the entire process (even the steps for MicroOS) to perform this migration on there wiki: systemd-boot.
Just a few commands and I should be good!
# create updates in new snapshot
transactional-update --no-selfupdate --continue shell
# nuke grub2
efibootmgr --delete --label opensuse-secureboot
efibootmgr --delete --label "openSUSE Boot Manager"
rm -r /boot/efi/EFI/opensuse
# install systemd-boot utilities and accept removing grub2
zypper in sdbootutil-snapper sdbootutil-rpm-scriptlets
# exit from transactional-update shell and finish up
exit
sdbootutil install
sdbootutil add-all-kernels
# reboot and experience the wonders of systemd-boot
systemctl reboot
The Results
A few simple commands and a reboot later and I ended up with a broken boot partition 🙃. The actual error was the following black screen with the following text:
Invalid image
Failed to read header: Unsupported
Failed to read load image: Unsupported
start_image() returned Unsupported
I had to use a live usb to recover myself and took a few hours of commands and a TON of restarts to figure out how to get systemd-boot working. I’ll be detailing the steps I would recommend taking below because there is safer ways to do this without breaking your boot partition so you can at least boot back into your OS if something goes wrong.
My Migration Guide
Ok, first thing’s first. I have UEFI enabled with Safe Boot disabled, so keep this in mind if your setup is slightly different from mine as these may also not work for you either.
First thing is got ahead and install systemd-boot in a new image and reboot into it (or apply) using tansactional-update.
sudo transactional-update pkg install zypper in sdbootutil-snapper sdbootutil-rpm-scriptlets systemd-boot
sudo systemctl reboot
The first issue I ran into the openSUSE guide was that when I exited the transactional-update shell I did not have the sdbootutil commands available in my current shell, so I could not run them. So to fix this I would recommend you install them and then reboot into the image that contains them.
After you are in the current snapshot with sdbootutil available we can start. First step, ignore the removing grub steps, you can actually install systemd-boot alongside grub and have 2 bootloader entries, this way if systemd-boot does not work, like for me, you can fallback to grub and get back into your system. This way after you get systemd-boot working you can safely remove grub2 without having to use a live cd/usb to rescue your install..
Second, we install systemd-boot using bootctl first to get their .efi files, then we use openSUSE’s sdbootutil to install their setup, followed by overwriting their .efi files to ensure that the boot works properly. This can be done like this:
# install the default, non-snapper supporting systemd-boot for their binaries
bootctl install
# now install openSUSE systemd-boot that does support snapper/btrfs snapshots
sdbootutil install
# now we copy the proper efi binaries to ensure that systemd-boot works properly on next boot
cp /boot/efi/EFI/systemd/systemd-bootx64.efi /boot/efi/EFI/shim.efi
Finally update your MicroOS to support systemd-boot instead of grub when creating snapper snapshots during updates. This is in the /etc/sysconfig/bootloader file
## Path: System/Bootloader
## Description: Bootloader configuration
## Type: list(grub,grub2,grub2-efi,none)
## Default: grub2
#
# Type of bootloader in use.
# For making the change effect run bootloader configuration tool
# and configure newly selected bootloader
#
#
LOADER_TYPE="systemd-boot"
## Path: System/Bootloader
## Description: Bootloader configuration
## Type: yesno
## Default: "no"
#
# Enable Secure Boot support
# Only available on UEFI systems and IBM z15+.
#
#
SECURE_BOOT="no"
## Path: System/Bootloader
## Description: Bootloader configuration
## Type: yesno
## Default: "no"
#
# Enable Trusted Boot support
# Only available on hardware with a Trusted Platform Module.
#
TRUSTED_BOOT="no"
## Path: System/Bootloader
## Description: Bootloader configuration
## Type: yesno
## Default: "yes"
#
# Update nvram boot settings (UEFI, OF)
# Unset to preserve specific settings or workaround firmware issues.
#
UPDATE_NVRAM="yes"
For this to work for me, ensure that SECURE_BOOT="no" and LOADER_TYPE="systemd-boot". If you are using Secure Boot, enable SECURE_BOOT and if you want to keep your keys in TPM use TRUSTED_BOOT="yes". Once again these are the settings that worked for me.
Finally now that you have your items completed run the following sdbootutil commands to generate your systemd-boot entries:
sdbootutil add-all-kernels
sdbootutil mkinitrd
sdbootutil update
These commands will do the following:
- Add all available kernels as entries in the bootloader
- Re-generates the initrd files that are used, this may be unnecessary but I did it
- Updates the bootloader entry files, this will update the entry to use the new initrd you generated in step 2.
Finally figure out your latest snapper snapshot and make sure the entry is pointing to that:
# find the latest snapper snapshot, this is the highest number
snapper list
# edit this file to ensure it's using the latest snapshot
vim /boot/efi/loader/entries/{machine-uuid}-{kernel version}-default-{snapshot number from list above}.conf
Ensure the following before restarting:
- options has the subvolume pointed at the correct snapshot in the filename and the latest one from
snapper list - ensure the linux and initrd are pointed to the correct files and that they exist (/boot/efi/{machine-uuid}/{kernel version}/linux-{uuid} and /boot/efi/{machine-uuid}/{kernel version}/initrd-{uuid})
After you’ve confirmed this go ahead and reboot systemctl reboot and when your machine is rebooting smash whatever key your UEFI/BIOS config key is (F2, DEL, Enter, etc.) and select your new entry from the boot menu. Mine is “openSUSE Boot Manager (systemd-boot)”, so select the one that likely has systemd-boot in the name. For me my grub entry is named “opensuse” (used to be opensuse-secureboot for some reason).
There are 3 things that could happen to you:
- systemd-boot works and you are dropped into your distro (Hopefully this happens to you)
- You are greeted with the same error as me “Invalid image” and you will have to reset and use your old grub bootloader to get back into your system
- Your screen briefly flashes black and then returns back to the UEFI boot selection. You will have to do what you did in step 2, reset and choose your old grub entry to get back into your system
If you have 2 or 3 happen to you, double check that you didn’t miss any steps or you didn’t misspell anything in your configs. Otherwise you may have to troubleshoot further yourself. But you can still get into your system using your old grub2 entry because we didn’t delete it before installing systemd-boot.
If you have 1 happen to you, congratulations! You have a fully functioning systemd-boot setup, feel free to remove the grub2 package and delete your efi boot options using the efibootmgr commands above.
Outcomes and lessons learned
The major thing that I learned was to keep grub2 installed throughout the entire process. The openSUSE documentation has you delete this first thing and you will be forced to use a live cd/usb to fix any issues (which they conviently included in the documentation as well). This was a majority of my time as I had to boot into this recovery environment multiple times with takes a while and the chroot process is sort of cumbersome.
The other thing I learned is that, for some reason, sdbootutil will attempt to install and use a shim.efi file even if you have Secure Boot disabled in the /etc/sysconfig/bootloader file and in the UEFI. This was the primary issue that was causing my “Invalid image” problem above. I got around this by directly loading the systemd-boot efi image vs the shim.efi as I don’t need the shim since Secure Boot is disabled. I’m not entirely sure if sdbootutil just doesn’t support Safe Boot being disabled or if there’s some weird bug in their script or my system that makes it think Secure Boot is enabled and it attempts to use the shim method to get my boot to work.
The other thing is the shim may just be broken? There is a GitHub issue that has this same thing happening in (Ventoy)[https://github.com/ventoy/Ventoy/issues/1735]. I know microsoft recently revoked some trusted keys that 3rd party OSes used for their UEFI Secure Boot signed keys.
Final Words
I am going to see if I can submit some changes to the openSUSE Wiki page to make removing GRUB last. That way people won’t have to suffer with the recovery method (in my case multiple times) to get a bootable system again. In addition I may also dig into their sdbootutil script to see why my Secure Boot being disable was not being detected. I’m still confused as to why a shim was attempted to be used when it was not necessary since Secure Boot was disabled. Finally I hope that my changes to this process make things work for anyone that is attempting this, but running into issues like I was during the process. This process is very straight forward for those not using btrfs or snapshots to manage their OS since the generated boot entry is basically static the entire time, where as using snapper requires you to update them every time you use a new snapshot to ensure you have the latest version.

