How to boot Linux from an internal drive

An image of a computer's hard drive.
BlogLink to blog
Blog
5 min read

This blog will show you how to boot a Linux ISO from an internal HDD or SSD instead of a USB drive. Image source: https://pxhere.com/en/photo/669159


Contents


When something goes wrong with a Linux install, having a backup system to boot into is invaluable.

The normal approach is to download an ISO of some Linux distro, write it to a USB drive, and boot from that. But what if you don’t have one on-hand? Or, what if you wanted to choose from multiple different distros without having to constantly erase the drive?

There’s a way to boot into a Linux ISO directly from your computer’s internal drive, and I’ll explain how I did it in this blog.

Step 0: Download the ISO you want to use 

This step should be pretty obvious. Download whatever ISO image you want to boot. I use EndeavourOS, so I grabbed the latest version from here 🔗.

Step 1: Choose a partition for storing the ISO image 

You’ll need to store the ISO image somewhere on your internal drive. The biggest issue is finding a location that not only has enough space to store the full image, but that is also separate from your installation.

Why is that? Well, let’s say the worst comes to pass, and you have to completely reinstall your system. That means wiping out your root partition, your boot partition, and any other partitions your system uses. If you boot into an ISO image, and that ISO image is stored on a partition that you’re about to reformat, Terrible Things™ might happen (or you might just not be allowed to do it at all).

The solution is to create a separate partition that’s just for storing the ISO image(s). Or, if you have two or more drives in your PC, drop the ISO image onto a drive that’s just being used for storage. I primarily use laptops with a single NVMe drive, so this blog is written from the perspective of a single drive.

I recommend creating a blank partition at the end of your drive and name it something like “recovery” and make it 4 - 8 GB. That should give you plenty of room to store even the largest ISO images. I only made mine 2 GB, but if I could do it again, I would’ve made it 2 -3 times as big. Storage is cheap - it’s better to overprovision than underprovision.

sudo fdisk -l       

Disk /dev/nvme0n1: 953.87 GiB, 1024209543168 bytes, 2000409264 sectors
...

Device              Start        End    Sectors   Size Type
/dev/nvme0n1p1         34     616447     616414   301M EFI System
/dev/nvme0n1p2     616448    1640447    1024000   500M Linux filesystem
/dev/nvme0n1p3    1640448 1996214271 1994573824 951.1G Linux filesystem
/dev/nvme0n1p4 1996214272 2000408575    4194304     2G Linux filesystem

Great, so now we have an empty partition. Now what?

If you haven’t already, format this partition with a filesystem. I chose ext4, but you can pick whatever you want. Make sure not to encrypt it or use anything fancy like LVM! We need a plain ol’ partition for this.

sudo mkfs.ext4 /dev/nvme0n1p4

Once you’ve got your fancy new filesystem, mount it to your running system so you can access the filesystem. In this example, the partition will get mounted to /mnt:

sudo mount /dev/nvme0n1p4 /mnt

Step 2: Copy your ISO(s) 

This step is pretty self-explanatory. Copy your ISO image(s) to the new filesystem at /mnt.

Step 3: Create a bootloader entry 

Now we need to tell our bootloader how to boot into this ISO image. I use GRUB 2 🔗, so these instructions will be for GRUB only. You might need to adapt this for your own bootloader if you use something different, like systemd-boot.

We’ll create the entry as a new file in the /etc/grub.d/ directory. We’ll call this file 40_bootable_iso. You can pick whatever name you want. This file has the following contents:

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

# Boot into EndeavourOS Recovery ISO
menuentry "EndeavourOS Cassini Nova 03-2023 ISO" {
   set isofile="/Endeavouros_Cassini_Nova-03-2023_R2.iso"
   set partition="/dev/disk/by-uuid/eb5a221f-6194-4bdb-8510-0d1447116345"
   loopback loop (hd0,4)$isofile
   linux (loop)/arch/boot/x86_64/vmlinuz-linux img_dev=$partition img_loop=$isofile
   initrd (loop)/arch/boot/amd-ucode.img (loop)/arch/boot/x86_64/initramfs-linux.img
}

Let’s break this down:

menuentry "EndeavourOS Cassini Nova 03-2023 ISO" is the name of the entry as it will appear in GRUB when the system boots.

set isofile="/Endeavouros_Cassini_Nova-03-2023_R2.iso" is the path of the ISO file on disk.

“But wait,” you say, “I thought we copied it to /mnt!”

That’s true, but that’s because it was mounted at /mnt. If we just looked at the partition directly, the ISO will appear to be in the root folder. That’s why we use / for the path.

set partition="/dev/disk/by-uuid/eb5a221f-6194-4bdb-8510-0d1447116345" is the UUID of the partition containing the ISO. You can use any other way of identifying partitions like labels, but I personally prefer UUIDs.

loopback loop (hd0,4)$isofile tells GRUB that this entry points to an ISO file which contains its own filesystem. This way, GRUB knows to use the ISO’s filesystem as the boot filesystem. One VERY IMPORTANT thing to note here is hd0,4: this tells GRUB the disk and partition number where the ISO file is. I’m not entirely sure why, but even though we provided the UUID, we still have to provide the partition number here. This is set to 4 because it’s the fourth partition on my first drive, but this could vary on your system. You might need to do some experimentation.

The last two lines tell GRUB where to find the kernel image (vmlinuz-linux) and initial RAM filesystem or initramfs 🔗 (initramfs-linux.img). The second line also describes which CPU microde image to use, which in the case of EndeavourOS, is either intel-ucode.img or amd-ucode.img. These paths will vary depending on your distro and CPU architecture. If you’re unsure, open up the ISO and look at its directory structure to see where it stores the kernel image, CPU microde image, and initramfs.

linux (loop)/arch/boot/x86_64/vmlinuz-linux img_dev=$partition img_loop=$isofile
initrd (loop)/arch/boot/amd-ucode.img (loop)/arch/boot/x86_64/initramfs-linux.img

After you’ve made these edits, save the file.

Step 4: Update GRUB 

Now we need to update GRUB so it captures these entries. On Arch-based distros, run the following command:

sudo grub-mkconfig -o /boot/grub/grub.cfg

Some distros, like Ubuntu, provide an update-grub command that does basically the same thing. In either case, GRUB will read through the new bootloader entry and add it to its configuration file.

Step 5: Reboot your PC 

Now for the moment of truth. Restart your PC, wait for your bootloader to come up, and if you did things right, you should see a new entry pop up in the list. Select it, and you should boot into your ISO!

From here you can do everything you can normally do with a live CD except erase or repartition your drive. You can also download other ISO images to the partition and create additional boot entries if you want, or simply keep this ISO updated with the latest version.

Hope this blog was helpful!

Previous: "What Pride Means to Me"Next: "What the f*#k is a furry?"
atmospheric breaks breakbeat buddhism chicago code disco fiction funk furry house house music kubernetes lgbt linux logseq mastodon mental health movies music nixos obsidian personal philosophy pkm poetry prompt second life social software soul technology writing