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.
Thank you for this detailed write up, it really helped me setup my USB booted ubuntu server!
Thank you very much for the detailed guide! It really helped me set up a decent base system of Ubuntu on a stick!
Max.
Greatly appreciated! I’m not setting up a Ubuntu server on a stick- but it is exactly what I needed. Easy read-only updatability in a desktop environment. Reduces the wear and tear on the flash drive. I had a different mostly read-only setup that failed on me once. This I’ve verified is 100% read-only when booted in read-only mode.
Thanks for your notes. However, I tried all steps, but the usb only boot at grub prompt.
It cannot boot to right prompt!!! What happen? I did make KARMIC version of ubuntu on the usb. Is it difference?
Wilson, if grub loads but you only see the prompt, it means grub couldn’t read or find a configuration in /boot/grub/menu.lst so double check that and make sure the kernel location is correct.
Thanks Steve.
I have tried (using the same built USB drive) in another machine.
It can boot. What do you think about this? Is that related to the BIOS or motherbroad?
Thanks again.
Wilson, paste your menu.lst in a pastebin like http://pastebin.org
Steve, I have tried several times. I found that if using live-cd to build usb server, at the end, when building GRUB (grub-install), there will miss stage1/stage2 files if no grub installed on the parent system (ie. live-cd boot up). I think that’s the point that after finished all steps you provided, the usb cannot boot up correctly, only go to grub prompt.
You can install grub with all of its stage files in the livecd environment though, just make sure the network is functional, drop to a command line and run “sudo apt-get update && sudo apt-get install grub”. I would think those stage files would be available since you can run the grub installer, but if they are missing that would explain inability to boot the new system.
Leave a comment or question