GRUB Bootloader Configuration and Recovery

GRUB2 (GRand Unified Bootloader 2) is the standard bootloader for Linux, responsible for loading the kernel and providing a boot menu for multi-boot systems. This guide covers GRUB2 configuration, menu customization, kernel parameter management, dual-boot setup, password protection, and recovery procedures for corrupted bootloaders on both BIOS and UEFI systems.

Prerequisites

  • Linux system with GRUB2 installed (Ubuntu 20.04+, CentOS/Rocky 8+)
  • Root access
  • Understanding of your partition layout: lsblk and blkid
  • For recovery: bootable live USB

GRUB2 File Locations and Structure

# Main configuration (auto-generated - do not edit directly)
/boot/grub/grub.cfg            # Ubuntu/Debian
/boot/grub2/grub.cfg           # CentOS/Rocky (BIOS)
/boot/efi/EFI/ubuntu/grub.cfg  # Ubuntu UEFI
/boot/efi/EFI/rocky/grub.cfg   # Rocky UEFI

# User-editable settings
/etc/default/grub              # Main settings file

# Custom menu entries and scripts
/etc/grub.d/                   # Scripts run to build grub.cfg
ls /etc/grub.d/
# 00_header        - Global settings
# 05_debian_theme  - Theme (Ubuntu)
# 10_linux         - Linux entries (auto-detected)
# 30_os-prober     - Detects other OSes (Windows, etc.)
# 40_custom        - Your custom entries go here
# View current GRUB config
grep -v "^#" /etc/default/grub | grep -v "^$"

# Regenerate grub.cfg after any change
sudo update-grub              # Ubuntu/Debian
sudo grub2-mkconfig -o /boot/grub2/grub.cfg   # CentOS/Rocky BIOS
sudo grub2-mkconfig -o /boot/efi/EFI/rocky/grub.cfg   # CentOS/Rocky UEFI

Customizing the Boot Menu

Edit /etc/default/grub for basic menu customization:

sudo nano /etc/default/grub
# Seconds to show menu (0=skip, -1=wait indefinitely)
GRUB_TIMEOUT=10

# Default entry (0=first, "saved"=last selected, or exact title)
GRUB_DEFAULT=0

# Save last selection as default
GRUB_SAVEDEFAULT=true

# Show menu even if only one OS (force menu display)
GRUB_TIMEOUT_STYLE=menu

# Disable quiet boot (show kernel messages)
GRUB_CMDLINE_LINUX_DEFAULT=""

# Set screen resolution (list available: videoinfo in GRUB console)
GRUB_GFXMODE=1920x1080
GRUB_GFXPAYLOAD_LINUX=keep
sudo update-grub

Add a custom menu entry:

sudo nano /etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.

# Boot from a specific kernel with custom parameters
menuentry "Ubuntu 22.04 (Debug Mode)" {
    set root=(hd0,gpt2)
    linux /boot/vmlinuz-5.15.0-100-generic root=/dev/sda2 ro debug ignore_loglevel
    initrd /boot/initrd.img-5.15.0-100-generic
}

# Boot memtest86+ for RAM testing
menuentry "Memory Test (memtest86+)" {
    linux16 /boot/memtest86+.bin
}
sudo update-grub

Kernel Parameters

Kernel parameters are passed via the linux line in GRUB. Set them persistently in /etc/default/grub.

sudo nano /etc/default/grub
# GRUB_CMDLINE_LINUX applies to all boots including recovery
# GRUB_CMDLINE_LINUX_DEFAULT only applies to normal boots

# Common parameters:
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"
# net.ifnames=0 biosdevname=0 = use old eth0/eth1 naming

# NVMe performance
GRUB_CMDLINE_LINUX="nvme_core.default_ps_max_latency_us=0"

# Disable spectre/meltdown mitigations for performance (test environments only!)
GRUB_CMDLINE_LINUX="mitigations=off"

# Set kernel console and serial
GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8"

# Memory limit (for testing with limited RAM)
GRUB_CMDLINE_LINUX="mem=4G"

# IOMMU for VMs/PCI passthrough
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"
sudo update-grub
# Reboot to apply
sudo reboot

# Verify parameters after reboot
cat /proc/cmdline

One-time kernel parameter (without saving):

  1. Boot to GRUB menu
  2. Press e to edit the selected entry
  3. Find the linux line, add parameters at end
  4. Press Ctrl+X to boot with those parameters (not saved)

GRUB Password Protection

Protect GRUB from unauthorized editing or booting alternate entries:

# Generate encrypted password hash
grub-mkpasswd-pbkdf2
# Enter password twice
# Copy the resulting "grub.pbkdf2.sha512.10000...." hash
sudo nano /etc/grub.d/01_password
#!/bin/sh
cat << 'EOF'
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.YOURHASHHERE...

# Allow booting the default entry without a password
EOF

To allow specific entries without a password:

sudo nano /etc/grub.d/40_custom
menuentry "Ubuntu 22.04 LTS" --unrestricted {
    # --unrestricted allows this entry to boot without password
    ...
}
sudo chmod +x /etc/grub.d/01_password
sudo update-grub

Dual-Boot Configuration

GRUB auto-detects other operating systems via os-prober:

# Install os-prober
sudo apt install os-prober   # Ubuntu
sudo dnf install os-prober   # CentOS/Rocky

# Enable os-prober in GRUB config (disabled by default in newer GRUB)
sudo nano /etc/default/grub
GRUB_DISABLE_OS_PROBER=false
# Run os-prober manually
sudo os-prober
# Output example: /dev/sda1@/EFI/Microsoft/Boot/bootmgfw.efi:Windows:Windows Boot Manager:efi

# Regenerate to include Windows
sudo update-grub

Manual Windows entry (if os-prober doesn't detect it):

sudo nano /etc/grub.d/40_custom
menuentry "Windows 11" {
    insmod part_gpt
    insmod fat
    insmod chain
    set root=(hd0,gpt1)   # EFI system partition
    chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
sudo update-grub

Set Windows as default (if it's entry 2):

# Count from 0; check grub.cfg to find Windows entry number
grep "menuentry" /boot/grub/grub.cfg | cat -n

sudo nano /etc/default/grub
# Set: GRUB_DEFAULT=2  (or the Windows entry number)
sudo update-grub

GRUB Rescue Basics

If GRUB fails to load (shows grub rescue> prompt):

# In grub rescue> prompt:

# List available disks and partitions
ls

# Identify which has Linux boot files
ls (hd0,gpt2)/boot/

# Set root and prefix
set root=(hd0,gpt2)
set prefix=(hd0,gpt2)/boot/grub

# Load normal module
insmod normal
normal

# This brings up the GRUB menu
# Then boot normally and run update-grub to fix permanently

If in grub> prompt (more functionality available):

# List partitions
ls

# Boot Linux manually
set root=(hd0,2)
linux /boot/vmlinuz-5.15.0-100-generic root=/dev/sda2 ro
initrd /boot/initrd.img-5.15.0-100-generic
boot

Reinstalling GRUB

Boot from a live USB to reinstall GRUB on a failed system:

# Boot from Ubuntu live USB or similar

# Identify your partitions
lsblk
sudo blkid

# Mount the installed system
sudo mount /dev/sda2 /mnt          # Root partition
sudo mount /dev/sda1 /mnt/boot     # /boot (if separate)

# Bind mount virtual filesystems
sudo mount --bind /dev /mnt/dev
sudo mount --bind /dev/pts /mnt/dev/pts
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys

# For UEFI: mount ESP
sudo mount /dev/sda1 /mnt/boot/efi   # EFI System Partition

# Chroot into the system
sudo chroot /mnt /bin/bash
# Inside chroot - reinstall GRUB

# BIOS/MBR install
grub-install /dev/sda          # Ubuntu
grub2-install /dev/sda         # CentOS/Rocky
update-grub                    # Ubuntu
grub2-mkconfig -o /boot/grub2/grub.cfg   # CentOS/Rocky

# UEFI install
grub-install --target=x86_64-efi \
  --efi-directory=/boot/efi \
  --bootloader-id=ubuntu        # Ubuntu

grub2-install --target=x86_64-efi \
  --efi-directory=/boot/efi     # CentOS/Rocky

# Regenerate config
update-grub                     # Ubuntu
grub2-mkconfig -o /boot/efi/EFI/rocky/grub.cfg   # CentOS/Rocky

exit
# Back in live environment
sudo umount -R /mnt
sudo reboot

UEFI-Specific Configuration

# List EFI boot entries
sudo efibootmgr -v

# Output example:
# BootOrder: 0000,0001,0002
# Boot0000* ubuntu    HD(1,GPT,...)/.../grubx64.efi

# Set boot order (boot entry 0000 first)
sudo efibootmgr -o 0000,0001,0002

# Delete a boot entry
sudo efibootmgr -b 0002 -B

# Add a new boot entry
sudo efibootmgr --create \
  --disk /dev/sda \
  --part 1 \
  --label "Ubuntu" \
  --loader /EFI/ubuntu/grubx64.efi

# Boot next reboot from specific entry (one-time override)
sudo efibootmgr --bootnext 0001

Secure Boot management:

# Check Secure Boot state
sudo mokutil --sb-state

# List enrolled keys
sudo mokutil --list-enrolled | head -20

# Import a new key (for custom kernel modules)
sudo mokutil --import my-key.der

Troubleshooting

GRUB shows "error: no such device" with UUID:

# UUID in grub.cfg doesn't match your disk
sudo blkid | grep UUID
# Update /etc/fstab and regenerate GRUB:
sudo update-grub

System boots to wrong OS after dual-boot setup:

# Check boot order
sudo efibootmgr   # UEFI
# Set Linux GRUB entry first in boot order
sudo efibootmgr -o 0000  # Replace 0000 with your Linux entry

GRUB menu too brief to select (timeout too short):

sudo nano /etc/default/grub
# Set: GRUB_TIMEOUT=10
# Set: GRUB_TIMEOUT_STYLE=menu
sudo update-grub

"Minimal BASH-like line editing is supported" after install:

# GRUB loaded but can't find config
# In grub> prompt:
ls           # Find partition with /boot/grub/
set root=(hd0,2)
set prefix=(hd0,2)/boot/grub
insmod normal
normal
# Then fix by reinstalling GRUB after booting

GRUB updates break UEFI boot after dist-upgrade:

# Reinstall GRUB to EFI
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --recheck
sudo update-grub

Conclusion

GRUB2 configuration is straightforward once you understand the relationship between /etc/default/grub, the /etc/grub.d/ scripts, and the auto-generated grub.cfg. Always modify settings through the appropriate files and run update-grub or grub2-mkconfig to regenerate the configuration. For recovery scenarios, the combination of the GRUB rescue prompt for temporary boots and a live USB for full reinstallation covers virtually any GRUB failure you'll encounter in production.