Jan 24th, 2010: Some time at the end of last year, a wordpress plugin severely corrupted some of the code examples below, but it has been fixed. Sorry.

UPDATED: see the end for an update on locales

I had been using a LiveUSB setup made from the official desktop ISO release, but got tired of being unable to really customize it and update it, i didn’t really want a desktop i wanted a very slim purpose built linux installation that would fit in under a few hundred megabytes. You can make a persistent squashfs based setup with a variety of available tools, however to update it all updates must be written to the persistent partition which slowly fills up. The original filesystem is truly read only and compressed and no matter what you remove or change it will always take the same ~700mb of space. That means even updates start to use duplicate space, if you install a new kernel you now have the space taken by the old kernel as well as the new kernel.

So i decided to build an Ubuntu system from scratch using a tool called debootstrap. It is very simple, could not be any easier especially compared to similar tools i have used on OpenSUSE and other distributions.

To start with, this system is going to be living on a 2GB Lexar Firefly USB stick, they are very tiny but fast enough for a server root filesystem. It needs to be barebones to start with so debootstrap is perfect, it only installs the bare minimum you would expect an Ubuntu system to have, no X11 of any kind, no high level libraries, no printer or file sharing support, just a kernel, some core libraries and utilities. To give you some idea of how small this core system is, once it is installed on the drive it takes up 374MB of space.

First i boot into an existing linux system or a livecd and install debootstrap:


root@live:/# sudo apt-get install debootstrap

Then I figure out which block device on the system is my USB stick, it is 2GB so i issue a cat /proc/partitions to find it:


root@live:~$ cat /proc/part*
major minor  #blocks  name

   8        0  976762584 sda
   8       16  976762584 sdb
   8       32   78150744 sdc
   8       33   78148161 sdc1
   8       48    2076383 sdd

I notice sdd has a 1k block count of 1,966,080 (just under 2000MB), so that has to be it. Because there is already a partition covering the whole disk i don’t need to change that, but if you do just use parted or another linux partitioning tool to create one single partition on the stick. I do however format it as ext3:


root@live:/# sudo mkfs.ext3 /dev/sdd1

Then i make a mountpoint for the drive on my filesystem and mount it:


root@live:/# sudo mkdir /stick
root@live:/# sudo mount /dev/sdd1 /stick

Now is the easy part, you just issue the debootstrap command (change to hardy if you are using 8.04LTS):


root@live:/# sudo debootstrap intrepid /stick

It should download the right packages and unpack them on to your USB stick, it may take a while. When it is done you simply get a new bash prompt. Now you will want to copy some files, make some symbolic links and edit the fstab file on the new filesystem.


root@live:/# sudo cp /etc/hosts /stick/etc/ 
root@live:/# sudo cp /etc/network/interfaces /stick/etc/network/ 
root@live:/# sudo cp /etc/bash_completion /stick/etc/ 
root@live:/# sudo cp /etc/bash.bashrc /stick/etc/ 

Now you will want to get the UUID for the filesystem on your usb stick and copy that into the fstab file (replace drive device with your own):


root@live:/# sudo echo "UUID=`vol_id /dev/sdd1 | grep ID_FS_UUID_ENC | awk '{sub(/ID_FS_UUID_ENC=/,"");print}'`      /     ext3 relatime 0 1" > /stick/etc/fstab

root@live:/# sudo echo  "proc          /proc proc defaults 0 0" >> /stick/etc/fstab

Make sure you get that long line right and replace the device listed with your own. If you can’t copy that correctly, obtain your UUID with the following command:


root@live:/# vol_id /dev/sdd1 | grep ID_FS_UUID_ENC

Then just manually edit /stick/etc/fstab so it looks like this but with your own UUID obtained with the vol_id command:


proc          /proc proc defaults 0 0
UUID=6a96f671-a7b0-4954-bd48-f9d739730b3a     /     ext3 relatime 0 1

Once that is done you will want to chroot into your new filesystem but mount some critical filesystems inside it first:


root@live:/# sudo mount -t sysfs sysfs /stick/sys
root@live:/# sudo mount --bind /dev /stick/dev
root@live:/# sudo mount -t proc proc /stick/proc
root@live:/# sudo su -c 'chroot /stick'

From now on you are root because sudo is not yet setup in the chroot

Now you will want to copy your local timezone into /etc:


root@live:/# sudo cp /usr/share/zoneinfo/America/New_York /etc/localtime

New york is used here, you can also issue an ls -l /usr/share/zoneinfo/ to see other time zones.

Now you will want to install an editor, i use nano the most:


root@live:/# apt-get install nano

Now it is time to update apt and get the repositories going, so add these to /etc/apt/sources.list with nano. Make sure each line starts with “deb”:


deb http://archive.ubuntu.com/ubuntu intrepid main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu intrepid-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu intrepid-security main restricted universe multiverse

Then update the package database and update the system, then run passwd to set the root password, and finally add a user (your own name), make an admin group, add yourself to it, and setup sudo so that members of the admin group have sudo privileges. You may get perl locale errors when running apt, you can ignore them. There is a package that needs to be installed to fix that but i can’t quite remember what it was, i will update it when i find out:


root@live:/# apt-get update
root@live:/# apt-get dist-upgrade
root@live:/# passwd
root@live:/# adduser steve
root@live:/# addgroup admin
root@live:/# adduser steve admin
root@live:/# echo "%admin ALL=(ALL) ALL" >> /etc/sudoers

Now we are going to install the server kernel along with grub as a bootloader, and set it up to boot correctly:


root@live:/min# apt-get install linux-image-server grub
root@live:/min# mkdir /boot/grub
root@live:/min# update-grub
root@live:/min# update-initramfs -u

Now we leave the chroot and install grub to the USB stick:


root@live:/# exit
root@live:/# grub-install --root-directory=/stick --no-floppy --recheck /dev/sda

If all goes well it will spit out some messages but it will correctly install grub to the device and you can reboot into your new USB stick. At this point it is not read only yet but we will cover that in part 2. If it doesn’t boot check your bios settings and try to reinstall grub using the ubuntu livecd or the super grub cd.

UPDATE: to fix the locale messages, have a look in /usr/share/i18n/SUPPORTED, pick the locale (i use en_US.UTF-8 UTF-8) and add it to /var/lib/locales/supported.d/local, then run “dpkg-reconfigure locales” and it should correctly set the locale and get rid of those annoying messages when you upgrade packages or install things.