Booting a Debian/Ubuntu ISO from an USB drive

At www.debian-administration.org you can find a short how-to on making an USB drive boot a Debian/Ubuntu distro (installer or Live CD) using an official ISO image.
The summary of their instructions is ...

ISO images are a lot more common than images made directly for USB drives, thus the above concept is pretty useful. However if you just want to use a Debian Live system from your USB, you might want to get an USB/HDD image that you can write directly to the USB drive.

For Ubuntu you'll find the required boot image here: http://archive.ubuntu.com/ubuntu/dists/lucid/main/installer-i386/current/images/hd-media/boot.img.gz. Note that URL in case of Ubuntu contains the distribution's name ("lucid" in the example) ... whereas for Debian the URL contained the distro as "stable".

The above method is the easy/fast one. But sometimes using this method the installer will tell you that there're no modules on the CD for the currently running kernel. This can easily happen if no updated boot.img.gz is published at the time, when a new version of the ISO is released.
To compare the kernel versions in boot.img.gz and the ISO image, try the following:
gunzip boot.img.gz
mkdir image
mount -o loop boot.img image
file image/linux
mkdir iso
mount -o loop debian-live-504-i386-gnome-desktop.iso iso
file iso/live/vmlinuz

If the output of the file commands do not contain the kernel version, you should check the modules directory in the ramdisk images:
gunzip -c image/initrd.gz | cpio -it | fgrep 'lib/modules/' | head -n 1
gunzip -c iso/live/initrd.gz | cpio -it | fgrep 'lib/modules/' | head -n 1

If you don't find a boot.img.gz with a kernel matching the ISO, you're out of luck.
There's nothing else to do, then to take the slower path and copy the contents of the ISO to the USB drive directly and make it bootable with syslinux.

The following instructions will show you how to do it with a 64 bit Ubuntu Server installer ISO.
As a special addon, in the example I'll create a disk image that you can copy to an USB drive or even a hard drive.
If you work directly with an USB drive, you should skip the disk image related sections and use the appropriate device names for your USB drive (ie. instead of /dev/loop0 use the device of the USB drive -eg. /dev/sdc- and instead of /dev/loop1 use the device of the first partition on the drive -eg. /dev/sdc1-).
I've marked the optional sections (the ones for working with a disk image) with indentation.
# Download the ISO.
wget --post-data 'distro=server&bits=64' 'http://www.ubuntu.com/start-download'

  # Create a disk image (only if you want to make a disk image instead of
  # working with an USB drive directly).
  # 8225280 is the size of a cylinder with 255 heads, 63 sectors and 512 byte sector size.
  # Define a "count" that will provide the image size (count * 8225280) of your choice.
  # A count=95 will create a 745MB image that is large enough to hold the contents
  # of any CD (ISO image) that you can find nowadays.
  dd if=/dev/zero of=usb.img bs=8225280 count=95
  # Mount the image file as a loop device and print the device name.
  # (Later on I suppose that it's /dev/loop0.)
  losetup -fv usb.img
  # Install an MBR in the disk image.
  # (Syslinux comes with one, but you can use the "install-mbr -f /dev/loop0" command too.)
  dd if=/usr/lib/syslinux/mbr.bin of=/dev/loop0
  # Generate a random disk identifier (not absolutely necessary, but it cannot hurt).
  # The disk identifier (as displayed by fdisk) is a 4 byte value in the MBR
  # -ie. the first 512 bytes of the drive- starting at 0x01B8 and ending at 0x1BB.
  # The disk identifier is stored in reverse byte order, ie. the bytes 0x12 0x34 0x56 0x78
  # are displayed by fdisk as the disk identifier "0x78563412".
  dd if=/dev/urandom of=/dev/loop0 bs=4 count=1 seek=110

# Partition the disk.
# The following command will create a single FAT32 partition spanning through the entire disk.
sfdisk -f -uS /dev/loop0 << EOF
63,,c,*
EOF

  # If you work with a disk image, attach it's first partition to a loop device.
  # The "-o" switch sets the start offset. It is calculated as the product
  # of the starting sector and the sector size, thus 63 * 512 = 32256.
  losetup -fvo 32256 usb.img
  # I'll assume it is /dev/loop1.

# If you work with an USB drive, the safest approach is to unplug it and replug it.
# This way you make sure that the kernel reads a fresh/clean state of the new partition table.

# Format the partition as FAT.
# (mkfs can automatically determine whether a FAT16 or FAT32 is needed.
#  You might want to change the partition type manually if it's a FAT16 or
#  you can force the use of a FAT32 filesystem. I do the latter.)
mkfs -t vfat -F 32 /dev/loop1
# Install syslinux in the partition.
syslinux -s /dev/loop1
# Mount the partition and the ISO image.
mkdir flash iso
mount -o loop ubuntu-10.04.1-server-amd64.iso iso
mount /dev/loop1 flash
# Copy everything that is not a symlink from the ISO to the disk.
cd iso
find . ! -type l | cpio -pdum ../flash
cd ..
# Rename isolinux to syslinux.
mv flash/isolinux flash/syslinux
mv flash/syslinux/isolinux.cfg flash/syslinux/syslinux.cfg
# Inject the "noprompt cdrom-detect/try-usb=true" options in append lines
# in all syslinux config files (most common are adtext.cfg and text.cfg).
cd flash/syslinux
tmpfile=$(mktemp --tmpdir=.)
for i in *.cfg; do
  sed 's/^\([[:space:]]*append\)[[:space:]]*/\1 noprompt cdrom-detect\/try-usb=true /g' "$i" > "$tmpfile"
  if ! cmp "$i" "$tmpfile" > /dev/null 2>&1; then
    cp "$tmpfile" "$i"
  fi
done
rm "$tmpfile"
# Unmount the ISO image.
umount iso
rmdir iso

  # If you work with a disk image, umount it and detach the loop devices.
  umount flash
  rmdir flash
  losetup -d /dev/loop0 /dev/loop1
 
  # To write the image to an USB drive:
  dd if=usb.img of=/dev/sdc bs=1M

Actually USB Creator does pretty much the same thing. It's a supported and easy to use GUI for users without commandline skills.

P.S.: I've found two links quite useful in understanding how things work ... one is "Creating a hard disk image under linux" and the other is "Ubuntu Server Flash Drive Installer".

P.S.: I've created a script based on the above code snippet (see the attached iso2usb.sh). It can convert an ISO image into a disk image that you can write to an USB drive and boot from it.

AttachmentSize
iso2usb.sh10.63 KB