Create Linux and Unix bootable USB flash drive in Linux with command line

In this tutorial we will create a Linux bootable USB drive in Linux via command line with two methods, in the first method we will use the dd command, a byte by byte copying tool available on Unix-like operating systems. In the second method, we will create it manually. Root permission is required.

Test environment: Debian 9.3 with mkfs.vfat 4.1
Test files: Debian 9.3 (ISOHybrid, Method 1) and KNOPPIX 7.7 (ISO9660, Method 2)

First, identify the USB drive, in my example the device is /dev/sdx (Kingston DT microDuo 3.0 16G).
Warning: All the data on the USB drive will be destroyed without warning! Make sure you selected the correct drive or you will destroy a wrong disk!

lsblk -S
NAME HCTL       TYPE VENDOR   MODEL             REV TRAN
sda  0:0:0:0    disk ATA      Samsung SSD 850  1B6Q sata
sdx  6:0:0:0    disk Kingston DT microDuo 3.0  PMAP usb
fdisk -l /dev/sdx
Disk /dev/sdx: 14.4 GiB, 15502147584 bytes, 30277632 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x28853db5

Device     Boot Start      End  Sectors  Size Id Type
/dev/sdx1  *     2048 30277631 30275584 14.4G  c W95 FAT32 (LBA)

Method 1 – using dd (Data Duplicator)

The dd command will create an exact copy of the ISO file, the content will be copied byte by byte onto the USB drive. The file must be an ISOHybrid image and obviously must be smaller than the USB drive’s capacity.

The big advantage of using this method is that it’s fast and easy, you don’t need to worry about partitioning, formatting and installing the bootloader, but there are disadvantages too.

With this method you won’t be able to use the entire capacity of the USB drive and operating systems like Microsoft Windows or macOS will not recognize it. The third disadvantage is that you cannot add or modify files even if you manage to access the content, because you won’t have enough free space or the file system is read only (see ISO9660).

Most of the Linux distributions uses ISOHybrid images while Unix BSD operating systems offers you separate image files (FreeBSD *memstick.img or OpenBSD install*.fs).

1. Check if the file is an ISOHybrid image, it must contain an MBR while the ISO9660 doesn’t. You can use the file command or hexdump the first 512 bytes.

a.) As you see the file command does not detect the MBR or hexdump shows just zeros, if you write this image it will not boot, it’s an ISO9660 image.

file KNOPPIX_V7.7.1DVD-2016-10-22-EN.iso
KNOPPIX_V7.7.1DVD-2016-10-22-EN.iso: ISO 9660 CD-ROM filesystem data 'KNOPPIX' (bootable)
hexdump -n 512 KNOPPIX_V7.7.1DVD-2016-10-22-EN.iso
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0000200

b.) The file command detected the MBR, this is what we need to use the dd command, it’s an ISOHybrid image.

file debian-9.3.0-amd64-xfce-CD-1.iso
debian-9.3.0-amd64-xfce-CD-1.iso: DOS/MBR boot sector; partition 2 : ID=0xef, start-CHS (0x3ff,254,63), end-CHS (0x3ff,254,63), startsector 7348, 832 sectors
hexdump -n 512 debian-9.3.0-amd64-xfce-CD-1.iso
...
00001b0 1ff4 0000 0000 0000 7fe7 5398 0000 0080
00001c0 0001 3f00 86a0 0000 0000 3800 0014 fe00
00001d0 ffff feef ffff 1cb4 0000 0340 0000 0000
00001e0 0000 0000 0000 0000 0000 0000 0000 0000
00001f0 0000 0000 0000 0000 0000 0000 0000 aa55
0000200

2. Write the ISOHybrid image to the USB drive. All data on /dev/sdx will be destroyed!

dd if=debian-9.3.0-amd64-xfce-CD-1.iso of=/dev/sdx bs=5M status=progress
587202560 bytes (587 MB, 560 MiB) copied, 5.02833 s, 117 MB/s
129+1 records in
129+1 records out
678428672 bytes (678 MB, 647 MiB) copied, 69.5308 s, 9.8 MB/s

Method 2 – manually (MBR partitioning scheme)

Install requirements:

apt-get install dosfstools
apt-get build-dep syslinux

1. Delete partitions by clearing the Master Boot Record, the following command will write 0x00 to the first 512 bytes. All data on /dev/sdx will be destroyed!

dd if=/dev/zero of=/dev/sdx bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.00290024 s, 177 kB/s

2. Create one big partition with boot flag on.

echo ',,c;*' | sfdisk /dev/sdx
New situation:
Device     Boot Start      End  Sectors  Size Id Type
/dev/sdx1  *     2048 30277631 30275584 14.4G  c W95 FAT32 (LBA)

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

3. Format the created partition /dev/sdx1 as FAT32 with the label “LINUX”.

mkfs.vfat -F32 /dev/sdx1 -n "LINUX"
mkfs.fat 4.1 (2017-01-24)

4. Mount the Linux ISO image for this example we will use KNOPPIX.

mkdir /mnt/iso
mount KNOPPIX_V7.7.1DVD-2016-10-22-EN.iso /mnt/iso

5. Search for isolinux.bin and check the version, download the same syslinux version and extract the archive.

find /mnt/iso -name "isolinux.bin" | xargs strings | grep -i isolinux
ISOLINUX 6.03 20171018
isolinux:
wget https://www.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz
tar -zxvf syslinux-6.03.tar.gz

6. Write the bootstrap code (mbr.bin) to the MBR of /dev/sdx. In syslinux version 6 the file path is bios/mbr/mbr.bin while in version 4 and 5 is mbr/mbr.bin.

dd if=syslinux-6.03/bios/mbr/mbr.bin of=/dev/sdx bs=440 count=1

7. Install syslinux, this will alter the boot sector and copy ldlinux.sys into the root directory. In syslinux version 6 the file path is bios/linux/syslinux while in version 4 and 5 is linux/syslinux.

syslinux-6.03/bios/linux/syslinux -i /dev/sdx1

8. Mount the USB drive and create syslinux.cfg.

mkdir /mnt/usb
mount /dev/sdx1 /mnt/usb/
echo -e "DEFAULT boot\nLABEL boot\n" > /mnt/usb/syslinux.cfg
find /mnt/iso/ -name isolinux.cfg | awk -F "/mnt/iso|isolinux.cfg" '{print "CONFIG " $2 "isolinux.cfg\nAPPEND " $2}' >> /mnt/usb/syslinux.cfg

9. Copy the Linux installation files to the USB drive, it might take a few minutes.

cp -rTv /mnt/iso/ /mnt/usb/

10. Unmount the USB drive. Don’t skip this step! Is needed to complete all pending writes.

umount /dev/sdx1

Finally

It should work on most of Linux distros, but there are exceptions.
Fedora and CentOS will mount the file system by LABEL, for example in CentOS 7 the LABEL must be CentOS\x207\x20x86_64. Bad for us because FAT32 supports a maximum of 11 characters, you must change the LABEL in isolinux.cfg and grub.cfg in multiple places.

/mnt/usb/isolinux/isolinux.cfg

..
  append initrd=initrd.img inst.stage2=hd:LABEL=CentOS\x207\x20x86_64 quiet
..

/mnt/usb/EFI/BOOT/grub.cfg

..
search --no-floppy --set=root -l 'CentOS 7 x86_64'

### BEGIN /etc/grub.d/10_linux ###
menuentry 'Install CentOS 7' --class fedora --class gnu-linux --class gnu --class os {
	linuxefi /images/pxeboot/vmlinuz inst.stage2=hd:LABEL=CentOS\x207\x20x86_64 quiet
	initrdefi /images/pxeboot/initrd.img
}
..

Leave a Reply

Your email address will not be published. Required fields are marked *