Installing Kubuntu 14.04 on a USB Drive with Debootstrap

We will install Ubuntu on a USB drive without leaving our current Ubuntu installation.

Your Skills

  • You can partition a hard drive and
  • you can install packages and
  • you like the command line.

Prerequisites

Get debootstrap (see Wajig (Package Management)):

wajig install debootstrap

Get admin rights to eliminate the need of typing sudo before every command:

sudo -i

My USB drive is /dev/sdc and I create the chroot directory at $chroot_dir:

usb_drive=/dev/sdc
chroot_dir=/tmp/target
mkdir -p $chroot_dir

Partitioning

Create the following partitions:

device mount point size
/dev/sdc1 /boot 150M
/dev/sdc2 / Rest

Remember to make /dev/sdc1 bootable!

Using parted:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
parted $usb_drive p
parted $usb_drive << EOF
rm 1
mkpart primary ext4 0% 150M
mkpart primary ext4 150M 100%
align-check opt 1
align-check opt 2
set 1 boot on
EOF
fdisk -l $usb_drive

Remember both partitions:

boot_device=${usb_drive}1
root_device=${usb_drive}2
ls $boot_device $root_device

Formatting

mkfs.ext4 -L boot $boot_device
mkfs.ext4 -L root $root_device

Tune2fs

You could disable file system checks if you wanted to:

tune2fs -c 0 -i 0 $boot_device
tune2fs -c 0 -i 0 $root_device

Check Partitions and get UUIDs

parted $usb_drive p
boot_uuid=$(blkid -o value -s UUID $boot_device)
root_uuid=$(blkid -o value -s UUID $root_device)
[[ -n $boot_uuid && -n $root_uuid ]] || echo 'Both must be set'

Mounting and Unmounting

Create and run the Bash script mountall:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
cat > mountall << EOF
mkdir -p $chroot_dir
mount /dev/disk/by-uuid/$root_uuid $chroot_dir

mkdir -p $chroot_dir/boot
mount /dev/disk/by-uuid/$boot_uuid $chroot_dir/boot

mkdir -p $chroot_dir/{dev,proc,run,sys}
mount -B /dev $chroot_dir/dev
mount -B /dev/pts $chroot_dir/dev/pts
mount -t proc proc $chroot_dir/proc  # for bash completion
mount -B /run $chroot_dir/run
mount -B /sys $chroot_dir/sys
EOF

chmod +x mountall
./mountall

Create the Bash script umountall for later use:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
cat > umountall << EOF
umount $chroot_dir/run
umount $chroot_dir/sys
umount $chroot_dir/dev/pts
umount $chroot_dir/dev
umount $chroot_dir/proc

umount $chroot_dir/boot
umount $chroot_dir/
EOF

chmod +x umountall

Check that everything is mounted:

mount | grep $usb_drive

Debootstrap

Choose a fast mirror and a target architecture to increase debootstrap’s download speed and install the base system:

release=precise
target=$chroot_dir
mirror=http://de.archive.ubuntu.com/ubuntu/
target_arch=amd64

debootstrap --arch $target_arch $release $target $mirror

Note

It is important to choose the right architecture in the next step. You probably want i386 or amd64. For a full list of supported architectures see http://archive.ubuntu.com/ubuntu/dists/precise/Release

New Hostname

new_hostname=port
cat > $chroot_dir/etc/hostname << EOF
$new_hostname
EOF
cat > $chroot_dir/etc/hosts <<EOF
127.0.0.1       localhost
127.0.0.1       $new_hostname
EOF

Fstab

fstab (the indentation will be proper after uuid substitution):

cat > $chroot_dir/etc/fstab <<EOF
# device                                                mount  type  options            freq  passno
UUID=$root_uuid  /      ext4  errors=remount-ro  0     1
UUID=$boot_uuid  /boot  ext4  errors=remount-ro  0     1
EOF

Root UUID

We’ll need root_uuid in the chroot environment:

mkdir -p $chroot_dir/tmp
echo $root_uuid > $chroot_dir/tmp/root_uuid

Chrooting

chroot $chroot_dir

Locale:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cat <<EOF > /etc/default/locale
LANG="en_US.UTF-8"
LANGUAGE=en_US:en
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
EOF
locale-gen en_US.UTF-8 de_DE.UTF-8
dpkg-reconfigure locales

Set the time zone and update the system:

cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime

# add universe repository for wajig and python-optcomplete
echo `cat /etc/apt/sources.list` universe > /etc/apt/sources.list

apt-get update
apt-get dist-upgrade

Install the kernel, GRUB 2, completion tools and the terminal mouse server:

apt-get install -y initramfs-tools grub-pc

apt-get install -y linux-image-generic \
    vim bash-completion wajig python-optcomplete gpm

Enable root login:

passwd

Configuring the Boot Loader

You can edit /etc/default/grub if you want, but the defaults work. Afterwards:

update-grub

Exit the chroot:

exit

Making It Bootable

MBR:

grub-install --root-directory=$chroot_dir --no-floppy --recheck $usb_drive

Unmount:

./umountall

That’s it! Exit the “sudo bash”:

exit

Troubleshooting

GRUB

See also http://www.gnu.org/software/grub/manual/grub.html#Troubleshooting.

15 : File not found

  • Check if vmlinuz-<kernel-version> exists in /boot
  • Check kernel line. Should be kernel /vmlinuz-<kernel-version> root=UUID=<root_uuid> vga=791, because /boot has it’s own partition. If it is just a directory under /, it should read kernel /boot/vmlinuz-<kernel-version> root=UUID=<root_uuid> vga=791.

17 : Cannot mount selected partition

Play with root (hd<disk-number>,<partition-number>. GRUB will show you 21 : Selected disk does not exist or 22 : No such partition when you try a disk/partition that does not exist.

Ramdisk Image

thanks, skrewz [3]:

kernel_version=2.6.28-11-generic
cd /tmp && rm -Rf w; mkdir w && cd w && cp $chroot_dir/boot/initrd.img-$kernel_version i.cpio.gz && gunzip i.cpio.gz && cpio --extract --file=i.cpio && rm i.cpio
ls

Notes

  • 2013-12-31 I had to use UUIDs only (in chroot fstab and from the outside). Else I would get the error:

    /usr/sbin/grub-probe: error: cannot find a GRUB drive for /dev/sdc1.  Check
    your device.map.
    Auto-detection of a filesystem of /dev/sdc1 failed.
    Try with --recheck.
    If the problem persists please report this together with the output of
    "/usr/sbin/grub-probe --device-map="/tmp/target/boot/grub/device.map"
    --target=fs -v /tmp/target/boot/grub" to <bug-grub@gnu.org>