This page is specific to Ubuntu versions ?

If you find this information applicable to additional versions/releases, please edit this page and modify this header to reflect that. Please also include any necessary modifications for this information to apply to the additional versions.


This page will describe how to setup a developement environment for LTSP under Ubuntu. We will see :

  • Setup KVM and virtual private network with NAT
  • Configure dnsmasq, dhcp server and apt-cacher
  • Create a virtual server and client
  • Prepare to build software

You will need a workstation with flag vmx in order to get good performance with KVM.

The virtual private network is bridge br0. Each virtual machine have it's own tap interface, created on the fly and added to the bridge. Here is the network information for the setup. You can change network address to fit your needs.

  • br0 :
  • server :
  • client : dhcp

For the setup, the dhcp server runs on the host and listen on br0. This way, your setup will be useful to run other virtual machines with DHCP, even if the ltsp server is not started.

dnsmasq and apt-cacher are not mandatory, but helpful. dnsmasq is useful to simplify the configuration of DNS in the guests, while apt-cacher will be useful to cache deb packages, that otherwise may be downloaded often.

Host installation

  • Install the latest release of Ubuntu.
  • Create a new /etc/apt/sources.list, update, upgrade and reboot if required

sudo -s
export distro=$(lsb_release -c -s)
cat << EOF > /etc/apt/sources.list
deb $distro main restricted universe multiverse
deb $distro-updates main restricted universe multiverse
deb $distro-security main restricted universe multiverse
apt-get update
apt-get upgrade
  • Install required software :

sudo apt-get install qemu kvm kvm-pxe bridge-utils uml-utilities ubuntu-vm-builder dnsmasq dhcp3-server apt-cacher
  • Configure kvm network script. By default, this script adds the tap interface of the vm to the real gateway interface, but in this setup, we use the bridge br0.

sudo -s
cat << EOF > /etc/kvm/kvm-ifup

/sbin/ip link set dev "$1" up
/usr/sbin/brctl addif ${switch} $1
exit 0

  • Configure dhcp server for the virtual network. dhcp server will be started later.

cat << EOF > /etc/dhcp3/dhcpd.conf
ddns-update-style none;

option domain-name-servers;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;

subnet netmask {
  option routers;
  filename "/ltsp/i386/pxelinux.0";
  option root-path "/opt/ltsp/i386";

cat << EOF > /etc/default/dhcp3-server
  • Script to setup virtual network. Run this script before starting any vm. This script ask for the interface name to use for the gateway, setup bridge, NAT and restart dhcp server. Take care, it flushes all iptables rules, so you may have to adapt it to your needs.

cat << EOF > /usr/local/sbin/kvm-net

echo "Setup of networking for vm's"

echo -n "Gateway interface: "
read gw

# Values

echo "Bridge br0 setup"
ip link set dev "$bridge" down
brctl delbr $bridge
sleep 1
brctl addbr $bridge
sleep 1

ip addr add "$LAN_IP/24" dev "$bridge"

echo "Setting up NAT"

echo 1 > /proc/sys/net/ipv4/ip_forward
# flush all rules
iptables -F
iptables -t nat -F

iptables -A FORWARD -j ACCEPT -i $LAN_NIC -s $LAN_IP_NET
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# start dhcp
/etc/init.d/dhcp3-server restart
chmod +x /usr/local/sbin/kvm-net
sudo kvm-net
  • Setup apt-cacher. In this example, the ubuntu repository is cached. Change the parameter path_map :

path_map = ubuntu
  • Restart apt-cacher : /etc/init.d/apt-cacher restart

We are done with the host setup.

Setup virtual machines

First, create a template virtual machine. This way, you will be able to create new virtual machines simply by copying the template.

mkdir ~/vm
cd ~/vm
sudo vmbuilder kvm  ubuntu --suite $(lsb_release -c -s) -o --mirror http://localhost:3142/ubuntu

A new directory that contain the vm image have been created. The script needs some minor modification in order to generate a macaddress on the fly.

cd ubuntu-kvm
cat << EOF >

ranmac=$(echo -n DE:AD:BE:EF ; for i in `seq 1 2` ; \
do echo -n `echo ":$RANDOM$RANDOM" | cut -n -c -3` ;done)

sudo kvm -m 128 -drive file=disk0.qcow2 -net nic,macaddr=$ranmac -net tap
chmod +x

Then, run the script. The virutal machine will boot. Default username and password is "ubuntu".

Copy this vm for the ltsp server, and start it. Then, configure it with theses commands.

sudo -s
export distro=$(lsb_release -c -s)
cat << EOF > /etc/apt/sources.list
deb $distro main restricted universe multiverse
deb $distro-updates main restricted universe multiverse
deb $distro-security main restricted universe multiverse
apt-get update
apt-get upgrade
apt-get install ltsp-server ubuntu-desktop

This may take a while. Then, you can start a thin-client by following these steps :

mkdir thin-client
cd thin-client
cat << EOF >

if [ ! -f terminal.img ]; then
qemu-img create terminal.img 10M

ranmac=$(echo -n DE:AD:BE:EF ; for i in `seq 1 2` ; \
do echo -n `echo ":$RANDOM$RANDOM" | cut -n -c -3` ;done)

sudo kvm -hda terminal.img \
-boot n \
-net nic,macaddr=$ranmac -net tap

chmod +x

Then, execute and a thin-client will run PXE stack and boot. It seems to take few tries to get an ip address.

Setup development environment

In this procedure, we will install needed libraries and tools to start development of ltsp with ubuntu.

Install software for general developement in Ubuntu :

sudo apt-get install bzr dpkg-dev build-essential patch dh-make debhelper devscripts fakeroot gnupg lintian pbuilder debian-policy developers-reference

Using NFS in replacement of NBD

Warning : may need revision

With NBD, every time you change the client root, the squashfs image must be rebuild to apply changes, and the thin-client needs to be rebooted. To speed up development, you can enable NFS root, then changes will be applied immediately.

Here is a script to switch between NFS and NBD :

    echo "usage: $0 [ nbd | nfs ]"

if [ $# -ne 1 ]; then
    echo " Error: this application takes exactly one parameter"
    exit 1
elif [ "$1" != "nbd" ] && [ "$1" != "nfs" ]; then
    exit 1



        mount -t proc none $LTSPROOT/proc
        chroot $LTSPROOT update-initramfs -u
        umount $LTSPROOT/proc

case $1 in
        echo "enabling nbd"
        sed -i 's/root_write_method=\(.*\)/root_write_method="unionfs"/g' $LTSPROOT/etc/default/ltsp-client-setup
        if [ -f $LTSPROOT/etc/initramfs-tools/conf.d/ltsp ]; then
            rm $LTSPROOT/etc/initramfs-tools/conf.d/ltsp
        echo "Clients can now boot by NBD."
        echo "enabling nfs"
        apt-get install nfs-kernel-server
        sed -i 's/root_write_method=\(.*\)/root_write_method="bind_mounts"/g' $LTSPROOT/etc/default/ltsp-client-setup
        cat /etc/exports | grep -v LTSPROOT > /etc/exports.tmp
        mv /etc/exports.tmp /etc/exports
        echo '/opt/ltsp/i386     *(ro,no_subtree_check,no_root_squash) # LTSPROOT' >> /etc/exports
        /etc/init.d/nfs-kernel-server restart
        echo "BOOT=nfs" > $LTSPROOT/etc/initramfs-tools/conf.d/ltsp
        echo "Clients can now boot by NFS."

Using an NBD file-based "partition"

To avoid running ltsp-update-image after each chroot change, you can use the following method instead of switching to NFS:

# Become root
sudo -i

# Delete the old image:
rm -f /opt/ltsp/images/i386.img

# Set up an 1024 Mb file-based "partition"
dd if=/dev/zero of=/opt/ltsp/images/i386.img bs=$((1024*1024)) count=1024
mkfs.btrfs /opt/ltsp/images/i386.img 

# Copy the contents of /opt/ltsp/i386:
mount -o loop,compress /opt/ltsp/i386.img /mnt
rsync -a /opt/ltsp/i386/ /mnt/
umount /mnt

# Move aside the old chroot:
mv /opt/ltsp/i386 /opt/ltsp/i386.original
mkdir /opt/ltsp/i386

That's it, you should be able to boot your clients using your file-based NBD "partition". Every time you want to change something, do:

service nbd-server stop
mount -o loop,compress /opt/ltsp/images/i386.img /opt/ltsp/i386
ltsp-chroot -m
umount /opt/ltsp/i386
service nbd-server start

Remember not to run ltsp-update-image afterwards.

Connect to terminal by SSH

It's realy useful to be able to start a shell on a thin-client when debugging or development.

First, install SSH in the chroot, enable the root account. You will need to rebuild the image if using nbd.

# SSH needs /dev/random and proc interface, so mount them
mount --bind /dev /opt/ltsp/i386/dev
mount -t proc none /opt/ltsp/i386/proc
# Make sure that resolv will work iin chroot
cp /etc/resolv.conf /opt/ltsp/i386/etc/
chroot /opt/ltsp/i386
# Install ssh server
LTSP_HANDLE_DAEMONS=false apt-get install ssh
# Enable root user by setting a password
passwd root
# update image if using nbd

It's also possible to install your public key in $CHROOT/root/.ssh/authorized_keys to connect to the terminal without using the root password.

See the content of the initramfs

To debug initramfs, you may want to see files that it contains. First, copy the initrd.img file to a temp directory. Then, run this command :

zcat initrd.img | cpio -div

Getting the source

Branches are hosted in launchpad :

In order to create a new branch, create an account on launchpad and upload your ssh public key. Then, you will be able to connect to the bazaar server and create your new branch.


HowToSetupLTSPDevelEnvironment (last edited 2012-02-18 19:37:27 by alkisg)