Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save sanketsudake/9e44f7d2fa71efd2bc25cb08d1382488 to your computer and use it in GitHub Desktop.

Select an option

Save sanketsudake/9e44f7d2fa71efd2bc25cb08d1382488 to your computer and use it in GitHub Desktop.
How to enable Secure Boot on Omarchy / Arch Linux with Limine + sbctl: convert legacy BIOS MBR to UEFI GPT without reinstalling, signed UKIs, Limine config enrollment, LUKS + btrfs snapshots

How to Enable Secure Boot on Omarchy (Arch Linux) with Limine and sbctl, Including Legacy BIOS/MBR to UEFI/GPT Conversion Without Reinstalling

A tested, step-by-step guide to enabling UEFI Secure Boot on Omarchy (the Arch Linux + Hyprland setup) that uses the Limine bootloader, sbctl custom keys, signed Unified Kernel Images (UKIs) and Limine config enrollment (BLAKE2B checksum), with LUKS full-disk encryption and btrfs + Snapper snapshots kept working.

It also covers a case most Secure Boot guides skip: Omarchy installed in legacy BIOS mode on an MBR (dos) disk. Secure Boot needs UEFI, so the guide first converts the install to UEFI on GPT in place, without reinstalling or losing data.

Builds on the community guide in omacom/omarchy discussion #2296, which assumes you already boot in UEFI mode.

Tested on: Acer Swift 3 SF314-52 (Insyde H2O firmware) · Omarchy · Limine 12.8 · limine-mkinitcpio-hook 1.38 · limine-snapper-sync 1.31 · sbctl · LUKS2 + btrfs · linux-omarchy kernel. The Limine/sbctl parts apply to any Arch Linux system using limine-entry-tool; the firmware menu names are Acer-specific but similar on most laptops.

⚠️ Warning: rewriting a partition table and firmware Secure Boot keys can make a machine unbootable. Back up your data and LUKS header, and keep a bootable Omarchy/Arch USB nearby.


Contents


Is this guide for you? (symptoms)

You're in the right place if you want Secure Boot on Omarchy / Arch Linux with Limine and any of these apply:

  • bootctl status prints Not booted with EFI
  • /sys/firmware/efi does not exist
  • lsblk -o NAME,PTTYPE shows dos (MBR) instead of gpt
  • /proc/cmdline contains cryptdevice=PARTUUID=xxxxxxxx-02 (an MBR-style partition ID)
  • /etc/default/limine contains ENABLE_UKI=no
  • sbctl status fails or shows nothing useful because the system isn't booted via UEFI

If you already boot in UEFI mode on GPT, skip to Step 5.

Overview

Phase What happens Reboot?
0–1 Back up, remove dependency on MBR PARTUUID ✅ test boot (still legacy)
2–3 Verify UEFI loader, convert MBR → GPT in place ✅ into firmware
4 Firmware: Legacy → UEFI, register Limine in NVRAM ✅
5 Switch to Unified Kernel Images ✅ test UKI boot
6 sbctl keys, Limine config enrollment, signing, fallback hook –
7 Firmware: Setup Mode, enroll custom + Microsoft keys ✅ into firmware
8 Secure Boot enforced, verify ✅ done

Step 0: Check your system and back up

ls /sys/firmware/efi                     # "No such file or directory" → legacy BIOS boot
lsblk -o NAME,SIZE,FSTYPE,PTTYPE,PARTTYPENAME
cat /proc/cmdline

For an in-place MBR → GPT conversion you need:

  • An EFI System Partition (ESP) already mounted at /boot as vfat. Omarchy creates one even on BIOS installs.
  • At least 33 free sectors at the end of the disk for the backup GPT header:
DISK=sda
echo "disk sectors: $(cat /sys/block/$DISK/size)"
for p in /sys/block/$DISK/$DISK*; do echo "$(basename $p) ends at $(( $(cat $p/start) + $(cat $p/size) ))"; done

Back up the LUKS header to external storage. A copy stored on the encrypted disk itself won't help if that disk is damaged:

sudo cryptsetup luksHeaderBackup /dev/sda2 --header-backup-file /run/media/$USER/<usb-label>/luks-header.img
sha256sum /run/media/$USER/<usb-label>/luks-header.img
sudo sfdisk -d /dev/sda > sda-mbr-layout.txt   # copy this to the USB too, for rollback

Step 1: Replace PARTUUID with the LUKS UUID

Converting a disk from MBR to GPT changes every PARTUUID. If your kernel command line unlocks the disk with cryptdevice=PARTUUID=…, the next boot can't find the root device. The LUKS UUID is stored inside the LUKS header, so the conversion doesn't change it:

sudo blkid -s UUID -o value /dev/sda2     # → <LUKS-UUID>
sudo cp -a /etc/default/limine /etc/default/limine.bak
sudo sed -i 's|cryptdevice=PARTUUID=<OLD-PARTUUID>:root|cryptdevice=UUID=<LUKS-UUID>:root|' /etc/default/limine
sudo limine-update

Gotcha: Snapper snapshot boot entries keep the old PARTUUID

limine-snapper-sync rebuilds snapshot entries from limine_history/snapshots.json, so editing only limine.conf gets reverted. Patch both:

H=/boot/$(cat /etc/machine-id)/limine_history
sudo sed -i 's|cryptdevice=PARTUUID=<OLD-PARTUUID>:root|cryptdevice=UUID=<LUKS-UUID>:root|g' "$H/snapshots.json" /boot/limine.conf
sudo limine-snapper-sync
sudo grep -c 'PARTUUID' /boot/limine.conf        # expect 0
grep -E 'PARTUUID' /etc/fstab /etc/crypttab      # expect nothing; fstab should use UUID=

Reboot now, still in legacy mode, and confirm the system boots and unlocks.

Step 2: Make sure the Limine UEFI loader is on the ESP

sudo ls -l /boot/EFI/BOOT/BOOTX64.EFI /boot/EFI/limine/limine_x64.efi
sudo cmp /usr/share/limine/BOOTX64.EFI /boot/EFI/BOOT/BOOTX64.EFI && echo OK || sudo limine-install

When run from a legacy boot, limine-install copies Limine to the UEFI fallback path EFI/BOOT/BOOTX64.EFI, which any UEFI firmware can boot without an NVRAM entry.

Step 3: Convert MBR to GPT without data loss

sudo pacman -S --needed gptfdisk
sudo sgdisk -p /dev/sda        # read-only preview: "converting MBR to GPT format in memory"

Check that the preview shows the same start and end sectors for every partition, with the ESP as type EF00 and Linux as 8300. Then write it:

sudo sgdisk -g /dev/sda && sync
sudo sgdisk -v /dev/sda        # expect: "No problems found."

Warning: The kernel is still using the old partition table. is expected on a mounted disk and harmless.

After this step legacy BIOS boot stops working. Reboot straight into the firmware.

Step 4: Switch firmware from Legacy to UEFI

Reboot and press F2 (Acer; other vendors use F2, F10, F12, Del or Esc):

  1. Security → Set Supervisor Password. On Acer, Secure Boot options are hidden until one is set. Write it down.
  2. Boot → Boot Mode: UEFI, and Secure Boot: Disabled for now.
  3. F10 to save and exit.
  4. If you get "No Bootable Device": F2 → Security → Select an UEFI file as trusted for executing → HDD0 → EFI → BOOT → BOOTX64.EFI, then save.

Once Omarchy boots, verify UEFI and register Limine as a proper NVRAM boot entry:

ls /sys/firmware/efi && cat /sys/firmware/efi/fw_platform_size   # 64
bootctl status | grep -E 'Firmware Arch|Secure Boot|Product'
sudo limine-install            # "EFI boot entry 'Limine' ... added successfully."
efibootmgr

Step 5: Enable Unified Kernel Images (UKI)

Firmware can verify a UKI (kernel + initramfs + stub in one PE file) as a single signed binary. Omarchy enables UKIs in /etc/limine-entry-tool.d/, but a legacy BIOS install writes ENABLE_UKI=no and ENABLE_LIMINE_FALLBACK=no into /etc/default/limine, which is loaded last and overrides it.

Config load order used by limine-entry-tool: /usr/share/limine-entry-tool.d/*.conf → /etc/limine-entry-tool.conf → /etc/limine-entry-tool.d/*.conf → /etc/default/limine (wins)

sudo sed -i -e '/^ENABLE_UKI=no$/d' -e '/^ENABLE_LIMINE_FALLBACK=no$/d' /etc/default/limine
sudo limine-update
ls /boot/EFI/Linux/                         # e.g. omarchy_linux-omarchy.efi
sudo grep -E 'protocol:|path:' /boot/limine.conf | head -4   # protocol: efi

Reboot and confirm you booted the UKI:

bootctl status | grep -E 'Stub:|Measured UKI'

Step 6: Create sbctl keys, enroll Limine config, sign everything

sudo pacman -S sbctl
sudo sbctl create-keys

Enable Limine config enrollment. This embeds the BLAKE2B hash of limine.conf in the Limine binary, so an edited config (for example init=/bin/sh) won't boot. This option is only honored in /etc/default/limine:

echo 'ENABLE_ENROLL_LIMINE_CONFIG=yes' | sudo tee -a /etc/default/limine
sudo limine-update
sudo sbctl verify

With sbctl installed and keys created, limine-update automatically:

  • signs every UKI through sbctl's mkinitcpio post hook,
  • enrolls the limine.conf hash into EFI/limine/limine_x64.efi and signs it (/etc/boot/hooks/post.d/90-limine-enroll-config).

❗ Don't run sbctl sign on limine_history/vmlinuz_* snapshot kernels. Limine verifies them against the hashes in the enrolled limine.conf. Signing changes the file, breaks the hash, and stops that snapshot from booting.

Gotcha: the UEFI fallback BOOTX64.EFI is unsigned and unenrolled

EFI/BOOT/BOOTX64.EFI is a plain copy of stock Limine. That causes one of two problems:

  • Unsigned: firmware that boots the fallback path fails under Secure Boot.
  • Signed but unenrolled: anyone can edit limine.conf and get around Secure Boot.

Many firmwares (Acer/Insyde included) reorder BootOrder and put the HDD0 fallback entry first after key changes. The robust fix is a post-hook that keeps the fallback identical to the signed and enrolled binary:

sudo tee /etc/boot/hooks/post.d/92-limine-signed-fallback >/dev/null <<'EOF'
#!/usr/bin/env bash

### Post-hook: Keep the UEFI fallback loader (EFI/BOOT/BOOTX64.EFI) identical to the
### config-enrolled and Secure Boot signed Limine binary (EFI/limine/limine_x64.efi).
### Runs after 90-limine-enroll-config, which enrolls the limine.conf hash and signs it.

esp_path=""
for p in /efi /boot /boot/efi /limine; do
	mountpoint -q "$p" 2>/dev/null && {
		esp_path="$p"
		break
	}
done
[[ -n $esp_path ]] || exit 1

src="$esp_path/EFI/limine/limine_x64.efi"
dst="$esp_path/EFI/BOOT/BOOTX64.EFI"

[[ -f $src && -d ${dst%/*} ]] || exit 0
cmp -s "$src" "$dst" && exit 0

if ! cp -f "$src" "$dst"; then
	echo "ERROR: Failed to copy '$src' to '$dst'" >&2
	exit 2
fi
sync -f "$dst"
echo "Synced signed Limine to fallback: $dst"
exit 0
EOF
sudo chmod 755 /etc/boot/hooks/post.d/92-limine-signed-fallback
sudo limine-update
sudo sbctl verify

Expected: BOOTX64.EFI, limine_x64.efi and all EFI/Linux/*.efi are signed ✓. The only unsigned files should be the limine_history snapshot kernels, which is fine.

Step 7: Enter Setup Mode and enroll keys

systemctl reboot --firmware-setup

In the Acer firmware:

  1. Boot → Secure Boot: Enabled. The key management options only appear once it's on.
  2. Security → Erase all Secure Boot Settings → confirm. This clears PK/KEK/db and enters Setup Mode.
  3. F10 to save. The system still boots, because Setup Mode doesn't enforce signatures.

Back in Omarchy:

sudo sbctl status          # Setup Mode: ✗ Enabled · Vendor Keys: none
sudo efibootmgr            # note if the firmware reordered BootOrder (fine with the Step 6 hook)
sudo sbctl enroll-keys -m  # -m also enrolls Microsoft keys, needed by firmware option ROMs (GPU, NVMe, etc.)
sudo sbctl status          # Setup Mode: ✓ Disabled · Vendor Keys: microsoft
sudo sbctl list-enrolled-keys

If enroll-keys fails with an "immutable" error, run sudo chattr -i /sys/firmware/efi/efivars/{PK,KEK,db}-* and retry. On MSI boards, turn off "Provision Factory Default keys" first, or the firmware re-adds its keys.

Step 8: Enable Secure Boot and verify

Reboot. If you enabled Secure Boot in Step 7, it's enforced now.

bootctl status | grep 'Secure Boot'          # Secure Boot: enabled (user)
sudo sbctl status                            # Secure Boot: ✓ Enabled
cat /sys/kernel/security/lockdown            # [none] integrity confidentiality
journalctl -k -b | grep -i 'secure boot'     # kernel: Secure boot enabled

🎉 The whole chain is now verified: firmware → signed Limine (enrolled config) → signed UKI → LUKS unlock.


Keeping Secure Boot working after updates

  • Kernel and Limine package updates: the pacman hooks rebuild and sign UKIs and re-enroll and re-sign Limine, and the fallback hook copies the result to BOOTX64.EFI. Nothing to do manually.
  • Hand-editing /boot/limine.conf: run sudo limine-enroll-config afterwards, or Limine refuses to boot. Prefer editing /etc/default/limine and running sudo limine-update.
  • Check any time: sudo sbctl verify
  • Keys are in /var/lib/sbctl/keys. Back them up only to encrypted storage, because anyone holding them can sign code your machine will trust.

Troubleshooting and recovery

Problem Fix
System won't boot after enabling Secure Boot Firmware → Boot → Secure Boot: Disabled (needs supervisor password). Boot, run sudo sbctl verify, sign what's missing, re-enable.
"No Bootable Device" after switching to UEFI Firmware → Security → Select an UEFI file as trusted for executing → EFI/BOOT/BOOTX64.EFI
Limine stops with a config checksum/hash error limine.conf changed without re-enrolling. Disable Secure Boot, boot, sudo limine-enroll-config.
Boots via fallback instead of "Limine" entry Normal on Acer/Insyde after key changes. The Step 6 hook keeps the fallback signed. Optional: sudo efibootmgr -o <Limine>,<others>
Snapshot entries fail to unlock after GPT conversion They still use PARTUUID; see the snapshot gotcha. Boot the main entry and patch snapshots.json.
Want the factory keys back Firmware → Restore Secure Boot to Factory Default
Partition table conversion went wrong Boot installer USB → sfdisk /dev/sda < sda-mbr-layout.txt → unlock, mount, arch-chroot → limine bios-install /dev/sda
LUKS header damaged cryptsetup luksHeaderRestore /dev/sda2 --header-backup-file luks-header.img from the installer USB
Running these steps from a script/AI agent: sudo: a terminal is required to read the password Use a SUDO_ASKPASS helper, e.g. one that pipes GETPIN into pinentry-gnome3, and call sudo -A

FAQ

Can I enable Secure Boot on Omarchy without reinstalling? Yes. Even if Omarchy was installed in legacy BIOS mode on an MBR disk, you can convert in place: switch the cmdline to the LUKS UUID, run sgdisk -g, set firmware to UEFI, then follow the sbctl steps.

Does converting MBR to GPT with sgdisk -g erase data? No, as long as there are at least 33 free sectors at the end of the disk. It rewrites only the partition table, and the partitions keep the same start and end sectors. Always preview with sgdisk -p and back up first.

Why use UKIs instead of vmlinuz + initramfs? Firmware verifies a UKI as one signed image, and systemd-stub measures it into the TPM. Limine can still hash-check plain kernels through an enrolled config, but a signed UKI is simpler and stronger.

What does ENABLE_ENROLL_LIMINE_CONFIG do? It embeds the BLAKE2B checksum of limine.conf into the Limine EFI binary before signing it. Without it, anyone with physical access could edit limine.conf (for example to add init=/bin/sh) and a signed Limine would boot it anyway.

Do I need sbctl enroll-keys -m (Microsoft keys)? It's strongly recommended on laptops and desktops. Option ROMs (GPU, NVMe, network) and firmware drivers are signed by Microsoft; leaving those keys out can leave you with a black screen or a missing boot device. It also keeps Windows dual boot working.

Does this work with dual boot Windows? Yes. Keep -m, and Limine can list Windows with FIND_BOOTLOADERS=yes / sudo limine-scan. BitLocker may ask for its recovery key once after the key changes.

Will anti-cheat that requires Secure Boot accept this? Some anti-cheats (e.g. FACEIT) check for a Microsoft-signed boot chain and may reject self-signed bootloaders, even with Secure Boot enabled.

Does this apply to plain Arch Linux, CachyOS or EndeavourOS with Limine? Yes. Anything using limine-mkinitcpio-hook / limine-entry-tool and sbctl works the same; only the Omarchy-specific drop-in file names differ.


Keywords: Omarchy secure boot, Arch Linux secure boot Limine, sbctl Limine, Limine enroll-config, limine-entry-tool secure boot, convert MBR to GPT without data loss, legacy BIOS to UEFI Arch Linux, Unified Kernel Image secure boot, LUKS btrfs snapper secure boot, Acer Swift 3 secure boot Linux, Insyde BIOS secure boot custom keys, Not booted with EFI.

If this helped you, ⭐ the gist or leave a comment with your hardware so others know it works there too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment