VMware ESXi and vSphere Cluster Management
GRUB 2: Linux Boot Loader Configuration and Custom Menu Entries
Learn how GRUB 2 builds its boot menu, configure defaults safely, regenerate grub.cfg, and create custom Linux or chainloader entries.
GRUB 2 is a boot loader: software started by system firmware that lets you choose an operating system or kernel and then starts that boot target. It runs after BIOS or UEFI firmware initialization and before the Linux kernel begins running.
GRUB 2 is the second major generation of the GNU GRand Unified Bootloader. It replaced GRUB Legacy on many distributions and is commonly the standard GRUB implementation on modern Linux systems. GRUB 2 supports both traditional BIOS booting and UEFI booting, although installation files, firmware entries, and configuration locations differ between those modes.
Where GRUB 2 fits in the boot process
- BIOS or UEFI firmware initializes hardware and selects a boot device or UEFI boot entry.
- The firmware loads GRUB or a GRUB EFI application.
- GRUB reads its generated configuration and displays boot choices.
- GRUB loads a Linux kernel and its initramfs, or chainloads another boot loader.
- The kernel starts early userspace and eventually the normal operating system userspace.
An initramfs, also called an initrd, is a temporary filesystem loaded with the kernel. It contains early drivers and startup programs needed to find the real root filesystem.
Generated configuration and source files
The active GRUB menu configuration is normally generated. You should usually change the input files and then rebuild the generated configuration instead of editing the generated output directly.
| Location | Purpose | Should it be edited directly? | Distribution notes |
|---|---|---|---|
/etc/default/grub | Global defaults used during generation | Yes, when changing supported settings | Common on Debian, Ubuntu, Fedora, and related systems |
/etc/grub.d/ | Ordered executable scripts that emit menu fragments | Edit or add an appropriate script | Script names and contents vary by distribution |
/boot/grub/grub.cfg | Generated configuration read by GRUB | Normally no | Common on Debian- and Ubuntu-family BIOS installations |
/boot/grub2/grub.cfg | Generated configuration read by GRUB | Normally no | Common on Fedora/RHEL-family systems |
| EFI System Partition GRUB paths | UEFI boot applications and related files | Normally no | Paths may be under a vendor directory; the generated configuration can still be elsewhere |
The exact active path is distribution-dependent. A direct edit to grub.cfg can disappear during a kernel update or the next configuration regeneration.
Global settings in /etc/default/grub
/etc/default/grub is a shell-style defaults file. Distribution scripts read it while producing the final configuration. Availability and exact behavior can vary by release.
| Variable | Typical purpose |
|---|---|
GRUB_DEFAULT | Selects the default menu entry. It may be a numeric index, an exact entry name, or saved. |
GRUB_TIMEOUT | Number of seconds before the default entry starts. A zero value can make selection difficult. |
GRUB_TIMEOUT_STYLE | Controls whether the menu is visible, hidden until requested, or otherwise presented, where supported. |
GRUB_SAVEDEFAULT | Works with saved-entry behavior on systems configured to remember the last selection. |
GRUB_CMDLINE_LINUX_DEFAULT | Additional kernel command-line options commonly applied to normal Linux boots. |
GRUB_CMDLINE_LINUX | Kernel command-line options commonly applied more broadly, including entries generated by the distribution. |
GRUB_GFXMODE | Requests a graphics mode for the GRUB display when supported by firmware and GRUB. |
Choosing the default entry
A numeric default refers to a menu position. This is simple but fragile: installing or removing kernels can change the positions.
GRUB_DEFAULT=0
An exact entry name is more descriptive, but the name must match the generated menu entry exactly and can vary with kernel versions.
GRUB_DEFAULT="Advanced options for GNU/Linux>GNU/Linux, with Linux 6.x.y-generic"
Using saved allows the last selected entry to be remembered when saved-entry support is configured. This is useful for repeatedly selecting a recovery or alternate kernel, but it should be tested so that an unwanted entry does not become persistent.
Timeout, visibility, and appearance
A visible menu with a positive timeout gives a user time to select another entry. A hidden menu may boot automatically while still allowing a key press to reveal choices; the exact keyboard behavior depends on the distribution, firmware, and configuration. A zero timeout starts the default quickly and is unsuitable when manual selection is regularly needed.
Kernel command-line options can change security, hardware, logging, graphics, storage, or recovery behavior. Add them carefully and test them temporarily before making them permanent.
Background images, themes, colors, terminal settings, and graphics settings are not controlled by one universal variable set. Distribution scripts, theme packages, firmware capabilities, and GRUB modules can all affect appearance. A theme-related setting may therefore work on one system and be ignored on another.
How /etc/grub.d/ builds the menu
Executable scripts in /etc/grub.d/ are run in filename sort order. Each script prints GRUB configuration text, and the combined output becomes grub.cfg. A script without its executable permission bit normally does not participate.
| Script | Typical role | Optional or distribution-specific? |
|---|---|---|
00_header | Initializes generated configuration and incorporates global defaults. | Common, but implementation varies |
05_debian_theme | Provides appearance settings on applicable Debian-family systems. | Theme-related and distribution-specific |
10_linux | Finds installed Linux kernels and creates normal and recovery entries where applicable. | Common, with distribution variations |
20_linux_xen | Creates entries for Xen-related Linux boots when Xen support is installed. | Optional |
20_memtest86+ | Adds memory-test entries when the utility is available. | Optional |
30_os-prober | Uses the optional os-prober tool to detect other operating systems. | Optional and sometimes disabled by policy |
40_custom | Conventional location for administrator-defined static entries. | Common convention |
Lower prefixes appear earlier. For example, 07_custom is processed before 10_linux, while 12_custom is processed after it. The ordering is based on filename sorting, so use a numeric prefix deliberately.
Regenerating the boot menu
Changes to source files do nothing until the generated configuration is rebuilt. Review the generator's output for detected kernels, operating systems, warnings, and errors before rebooting.
| Distribution family | Preferred command | Typical output file | Verification step |
|---|---|---|---|
| Debian/Ubuntu | sudo update-grub | Usually /boot/grub/grub.cfg | Read output, then inspect the generated file for the expected entry |
| Fedora/RHEL derivatives | sudo grub2-mkconfig -o /boot/grub2/grub.cfg | Often /boot/grub2/grub.cfg | Confirm the target path and review detected entries and errors |
| Generic GRUB installation | sudo grub-mkconfig -o /boot/grub/grub.cfg | Depends on the installation | Use the actual target path for the distribution and boot mode |
sudo update-grub
# Generic form; verify the output path first
sudo grub-mkconfig -o /boot/grub/grub.cfg
# Common Fedora/RHEL-family form
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
Do not blindly use the same command or output path on every machine. UEFI installations may use a vendor EFI directory and a distribution-specific arrangement that differs from a BIOS installation.
Creating custom menu entries
A custom entry is useful for chainloading another boot loader, booting a manually managed kernel, or supplying special kernel options. Chainloading means starting another boot loader from a GRUB entry.
Using 40_custom
The conventional static location is /etc/grub.d/40_custom. A basic Linux entry contains a human-readable menuentry label, a command that finds the boot partition, a kernel image and its options, and an initramfs image.
#!/bin/sh
exec tail -n +3 "$0"
menuentry 'Manually managed Linux' {
search --no-floppy --fs-uuid --set=root BOOT-FILESYSTEM-UUID
linux /boot/vmlinuz-MANUAL root=UUID=ROOT-FILESYSTEM-UUID ro quiet
initrd /boot/initramfs-MANUAL.img
}
The first two lines are the conventional generator-script header. The exec tail -n +3 "$0" line causes the script to output its literal menu-entry text. This is a simple form of a heredoc-like generator pattern: a shell script emits GRUB syntax rather than executing that syntax as shell commands. Actual kernel and initramfs filenames must match files installed on the machine.
A separate script can make ordering clearer:
sudo install -m 0644 /dev/null /etc/grub.d/12_custom
sudo chmod 755 /etc/grub.d/12_custom
sudoedit /etc/grub.d/12_custom
sudo update-grub
The script's interpreter declaration, shell syntax, error behavior, ownership, and executable permission matter. Use a valid shebang such as #!/bin/sh, keep the file owned by root, and inspect generator errors before rebooting.
GRUB disk and partition notation
GRUB identifies disks and partitions differently from Linux device paths. Disk numbers are zero-based, while partition numbers in GRUB 2 are generally one-based.
| Linux device example | GRUB 2 form | Numbering rule | Reliability note |
|---|---|---|---|
/dev/sda | (hd0) | First disk is number 0 | Disk ordering can change |
/dev/sda1 | Approximately (hd0,1) | First partition is number 1 | Use partition-table-qualified notation when displayed |
| GPT partition | (hd0,gpt1) | GPT partition 1 is explicitly identified | More descriptive than an unqualified number |
| MBR partition | (hd0,msdos1) | MBR partition 1 is explicitly identified | Notation must match the partition table |
| UUID-based discovery | search --fs-uuid --set=root UUID | Does not depend on disk number | Usually more reliable when disks can be reordered |
For example, Linux /dev/sda1 may correspond approximately to (hd0,1), but the modern form may be shown as (hd0,gpt1) or (hd0,msdos1). Prefer UUID-based search commands in custom entries when possible.
BIOS and UEFI considerations
In a BIOS installation, GRUB commonly uses boot-sector code and, on some partition layouts, a dedicated BIOS boot area. In a UEFI installation, firmware loads a GRUB EFI executable from the FAT-formatted EFI System Partition, which stores UEFI boot files.
UEFI systems may have GRUB files below a vendor directory in the EFI System Partition as well as a generated configuration under /boot. Firmware boot entries also identify which EFI application to start. Therefore, do not assume that one file path or one repair command applies to every distribution and firmware mode.
Multi-boot detection with os-prober
os-prober is an optional tool that searches for other installed operating systems. Some distributions install it but disable its use by default. Follow the distribution's policy for installing or enabling it, regenerate the menu, and check the output for detected systems.
Detection can fail when a partition is encrypted, unavailable, hibernated, unsupported, or not mounted in a way the tool can inspect. If automatic detection is unsuitable, a carefully tested custom entry or chainloader entry may be more predictable.
Safe workflow and validation
- Identify the distribution, active GRUB configuration path, firmware mode, and known-working kernel entries.
- Back up
/etc/default/gruband any script you will edit. - Change source files, not the generated
grub.cfg. - Check script ownership, syntax, filename prefix, and executable permission.
- Regenerate the configuration with the distribution-appropriate command.
- Read the command output and inspect the generated file.
- Keep at least one known-working normal kernel and, where available, a recovery entry.
- Reboot only after the expected entry and parameters are present.
Useful checks include:
ls -l /etc/grub.d/
grep -n "menuentry" /boot/grub/grub.cfg
# On systems using the alternative location:
grep -n "menuentry" /boot/grub2/grub.cfg
Before making a permanent kernel-command-line change, select the entry at the GRUB menu and press the commonly documented edit key, often e. Find the line beginning with linux, temporarily add or remove the option, and use the displayed boot key, often Ctrl+x or F10, to boot once. This interactive edit is not persistent and is a lower-risk way to test a parameter.
Troubleshooting
A change disappears
The generated file was probably edited directly. Move the change to /etc/default/grub or an appropriate /etc/grub.d script, then regenerate the configuration.
A custom entry is missing
Check that the script has an executable bit, has a valid filename prefix, contains valid shell syntax, and was followed by a regeneration command. Read generator output and search the generated file for the expected menuentry.
GRUB cannot find the root partition
Hard-coded disk ordering may have changed, or the partition notation may be wrong. Verify the partition table and identifiers, use a UUID-based search command, and confirm whether gpt or msdos notation is required.
Another operating system is missing
Check whether os-prober is installed, enabled according to distribution policy, and able to inspect the target filesystem. Encryption and unsupported layouts can prevent detection. Regenerate after changes or create a tested custom chainloader entry.
The system boots too quickly
A zero timeout, hidden-menu setting, or firmware behavior may suppress selection. Adjust GRUB_TIMEOUT and, where relevant, GRUB_TIMEOUT_STYLE, regenerate the configuration, and test. The key used to reveal a hidden menu varies by firmware and distribution.
A kernel-parameter change prevents booting
Use the GRUB editor to remove the option for one boot, select a known-working or recovery kernel, correct the source configuration, and regenerate only after the change has been validated.
The command writes to the wrong location
Instructions for a different distribution or firmware mode were likely used. Identify the active configuration path and whether the system boots through BIOS or UEFI, then use the matching helper and output target.
For a concise reference, see GRUB 2 configuration and custom entries.