Running Debian inside of Debian with User-Mode Linux

You can find the newest version of this text on http://www.eggdrop.ch/texts/uml/index.htm.

Update 21.04.13: You can find an updated create_machine script on https://gist.github.com/AVGP/5410903 thanks to Martin N. It uses an updated URL to the Debian tarball (Wheezy) and adds the creation of the root password. His blog post is located at http://ox86.tumblr.com/post/48274682732/lightweight-virtual-containers-with-virtual-networking.

23.07.04: Version 1.0

Introduction

This text describes how to install Debian GNU/Linux (http://www.debian.org) inside of itself with User-Mode Linux (http://user-mode-linux.sourceforge.net/).

Contents:

Preparing the host system

You don't need to download UML from http://user-mode-linux.sourceforge.net/ because it's in APT:

# apt-get install wget user-mode-linux uml-utilities bridge-utils debootstrap realpath

Make sure you have the following options set in the kernel:

CONFIG_TUN
CONFIG_BRIDGE
CONFIG_BLK_DEV_LOOP

Create a new user uml and add it to the group uml-net (the group should be already created). Make sure this user can write to /dev/net/tun:

# adduser uml
# adduser uml uml-net
# chgrp uml-net /dev/net/tun
# chmod 660 /dev/net/tun

You can use the following script to set up networking on the host (download: uml-bridge) - the script is basically from [1]:

#!/bin/sh

# your IP address
HOST_IP="192.168.0.3"

# netmask
HOST_NETMASK="255.255.255.0"

# your internet gateway
HOST_GATEWAY="192.168.0.1"

# internet interface
HOST_IFACE="eth0"

# name of the bridge
UML_BRIDGE="br0"

# the syntax of UML_IFACES is as follows:
# UML_IFACES="<iface1>:<user1>[ <iface2>:<user2>[...]]"
#
# for instance you have two UMLs, the first runs as user 'tom'
# and the second as 'uml':
#      UML_IFACES="tap1:tom tap2:uml"
UML_IFACES="tap1:uml"

###############

if [ "x$1" = "x-v" ]; then
        VERBOSE=1
        shift
else
        VERBOSE=0
fi

e() { test $VERBOSE = 1 && echo $@; $@; }

case "$1" in
        start)
                echo -n "Setting up UML bridge"
                test $VERBOSE = 1 && echo

                # set up the bridge
                e ifconfig $HOST_IFACE 0.0.0.0 promisc up
                e brctl addbr $UML_BRIDGE
                e brctl setfd $UML_BRIDGE 0
                e brctl sethello $UML_BRIDGE 0
                e brctl stp $UML_BRIDGE off

                # add the host interface
                e ifconfig $UML_BRIDGE $HOST_IP netmask $HOST_NETMASK up
                e route add default gw $HOST_GATEWAY
                e brctl addif $UML_BRIDGE $HOST_IFACE

                # and the UML interface(s)
                for ITMP in $UML_IFACES; do
                        IFACE=`echo $ITMP | cut -d ':' -f 1`
                        IUSER=`echo $ITMP | cut -d ':' -f 2`
                        test `echo $ITMP | grep ':'` || IUSER=root
                        e tunctl -u $IUSER -t $IFACE > /dev/null
                        e ifconfig $IFACE 0.0.0.0 promisc up
                        e brctl addif $UML_BRIDGE $IFACE
                        echo -n " $IFACE"
                done

                echo "."
                ;;
        stop)
                echo -n "Removing UML bridge"
                test $VERBOSE = 1 && echo

                e ifconfig $UML_BRIDGE down
                e brctl delif $UML_BRIDGE $HOST_IFACE
                for ITMP in $UML_IFACES; do
                        IFACE=`echo $ITMP | cut -d ':' -f 1`
                        e brctl delif $UML_BRIDGE $IFACE
                        e tunctl -d $IFACE > /dev/null
                        echo -n " $IFACE"
                done
                e brctl delbr $UML_BRIDGE
                e ifconfig $HOST_IFACE $HOST_IP netmask $HOST_NETMASK up
                e route add default gw $HOST_GATEWAY

                echo "."
                ;;
        reload | force-reload | restart)
                $0 stop
                $0 start
                ;;
        *)
                echo "Usage: $0 {start|stop|restart}"
esac

Remember to adjust the settings at the beginning of the script. Put the script into /etc/init.d/uml-bridge or something similar and run it:

# /etc/init.d/uml-bridge start
Setting up UML bridge tap1.

If you get some errors, try to run the script with the -v option.

To set up the bridge automatically at startup, you have to create some symlinks:

ln -s /etc/init.d/uml-bridge /etc/rc0.d/K99uml-bridge
ln -s /etc/init.d/uml-bridge /etc/rc1.d/K99uml-bridge
ln -s /etc/init.d/uml-bridge /etc/rc2.d/S99uml-bridge
ln -s /etc/init.d/uml-bridge /etc/rc3.d/S99uml-bridge
ln -s /etc/init.d/uml-bridge /etc/rc4.d/S99uml-bridge
ln -s /etc/init.d/uml-bridge /etc/rc5.d/S99uml-bridge
ln -s /etc/init.d/uml-bridge /etc/rc6.d/K99uml-bridge

Creating the UML machine

Now let's create a UML machine. I made the following shell script (download: create_uml):

#!/bin/sh

### functions

f() { echo "Failed."; exit; }

setup_net()
{
  echo "Configuring network"
  while :; do
    echo -n "IP address of the UML machine (e.g. 192.168.0.100) > "
    read nw_ip
    if [ "x$nw_ip" != "x" ]; then
      break
    fi
  done
  while :; do
    echo -n "Network (e.g. 192.168.0.0) > "
    read nw_network
    if [ "x$nw_network" != "x" ]; then
      break
    fi
  done
  while :; do
    echo -n "Broadcast address (e.g. 192.168.0.255) > "
    read nw_bcast
    if [ "x$nw_bcast" != "x" ]; then
      break
    fi
  done
  while :; do
    echo -n "Netmask (e.g. 255.255.255.0) > "
    read nw_netmask
    if [ "x$nw_netmask" != "x" ]; then
      break
    fi
  done
  while :; do
    echo -n "Your internet gateway (e.g. 192.168.0.1) > "
    read nw_gw
    if [ "x$nw_gw" != "x" ]; then
      break
    fi
  done
  while :; do
    echo -n "Host interface (e.g. tap1) > "
    read nw_if
    if [ "x$nw_if" != "x" ]; then
      break
    fi
  done

  echo ""
  echo "You entered:"
  echo "  IP address:        $nw_ip"
  echo "  Network:           $nw_network"
  echo "  Broadcast address: $nw_bcast"
  echo "  Netmask:           $nw_netmask"
  echo "  Gateway:           $nw_gw"
  echo "  Host interface:    $nw_if"

  while :; do
    echo -n "Is this correct? [y/n]: "
    read nw_ok
  
    case "$nw_ok" in
      y | yes)
        break
        ;;
      n | no)
        setup_net
        return
        break
        ;;
      *)
        echo "Please enter 'y' or 'n'"
    esac
  done
}

### our script begins here

if [ "`id -u`" != "0" ]; then
  echo "I won't run as user. I need root."
  exit 1
fi

if [ "x$1" = "x" ]; then
  echo "Enter the name of the UML machine or press CTRL+C to abort:"
  echo -n "> "
  read name
fi

if [ "x$name" = "x" ]; then
  echo "Aborting."
  exit 1
fi 

echo
echo ==============================
echo Downloading Debian base system
echo ==============================
echo
if [ -f "basedebs.tar" ]; then
  echo "The base system seems to be already downloaded. Skipping."
else
  wget --passive-ftp ftp://ftp.debian.org/debian/dists/woody/main/disks-i386/base-images-current/basedebs.tar || f
fi

echo
echo ==============================
echo Creating file system
echo ==============================
echo
if [ "x$1" = "x" ]; then
  echo "Enter the size of your root partition in MB"
  echo -n "> "
  read size
fi
if [ "x$size" = "x" ]; then
  echo "Aborting."
  exit 1
fi 
mkdir $name || f
# print this so the user does not think that the script is hanging
echo dd if=/dev/zero of=$name/root_fs count=$size bs=1M
dd if=/dev/zero of=$name/root_fs count=$size bs=1M || f
/sbin/mke2fs -F $name/root_fs || f
mkdir $name/install || f
mount -o loop $name/root_fs $name/install || f

echo
echo ==============================
echo Installing the base system
echo ==============================
echo 
debootstrap --unpack-tarball `realpath basedebs.tar` woody $name/install || f

echo
echo ==============================
echo Configuring the base system
echo ==============================
echo 

echo '# /etc/fstab: static file system information.
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/ubd0        /             ext2    defaults                 0    0
proc             /proc         proc    defaults                 0    0' \
> $name/install/etc/fstab


echo '# /etc/inittab: init(8) configuration.
# $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $

# The default runlevel.
id:2:initdefault:

# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS

# What to do in single-user mode.
~~:S:wait:/sbin/sulogin

# /etc/init.d executes the S and K scripts upon change
# of runlevel.
#
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.

l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin

# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

# Action on special keypress (ALT-UpArrow).
#kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work."

# What to do when the power fails/returns.
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop

# /sbin/getty invocations for the runlevels.
#
# The "id" field MUST be the same as the last
# characters of the device (after "tty").
#
# Format:
#  <id>:<runlevels>:<action>:<process>
#
# Note that on most Debian systems tty7 is used by the X Window System,
# so if you want to add more getty'\''s go ahead but skip tty7 if you run X.
#
0:1235:respawn:/sbin/getty 38400 console linux
#1:2345:respawn:/sbin/getty 38400 tty1
#2:23:respawn:/sbin/getty 38400 tty2
#3:23:respawn:/sbin/getty 38400 tty3
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6

# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100

# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3' > $name/install/etc/inittab

echo $name > $name/install/etc/hostname

# set up apt
cp /etc/apt/sources.list $name/install/etc/apt/sources.list || f


# install SSH
while :; do
  echo -n "Do you want to install SSH? [y/n]: "
  read nw_config

  case "$nw_config" in
    y | yes)
      chroot $name/install apt-get -y update || f
      chroot $name/install apt-get -y install ssh || f
      break
      ;;
    n | no)
      break
      ;;
    *)
      echo "Please enter 'y' or 'n'"
  esac
done

# network
while :; do
  echo -n "Do you want to configure the network? [y/n]: "
  read nw_config

  case "$nw_config" in
    y | yes)
      nw_config=1
      break
      ;;
    n | no)
      nw_config=0
      break
      ;;
    *)
      echo "Please enter 'y' or 'n'"
  esac
done
  
if [ "$nw_config" = "1" ]; then
  setup_net
  echo '# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or
# /usr/share/doc/ifupdown/examples for more information.
auto lo
iface lo inet loopback

# eth0
auto eth0
iface eth0 inet static
   address '$nw_ip'
   netmask '$nw_netmask'
   network '$nw_network'
   broadcast '$nw_bcast'
   gateway '$nw_gw > $name/install/etc/network/interfaces
fi

# clean up
umount $name/install
rmdir $name/install

echo
echo ==============================
echo Creating start script
echo ==============================
echo 

while :; do
  echo -n "Enter the amount of memory for the UML machine in MB: "
  read mem
  test $mem && break
done

if [ "$nw_config" = "1" ]; then
echo '#!/bin/sh

MEMORY="'$mem'M"
HOST_IFACE="'$nw_if'"

linux mem=$MEMORY eth0=tuntap,$HOST_IFACE' > $name/run
else
echo '#!/bin/sh

MEMORY="'$mem'M"

linux mem=$MEMORY' > $name/run
fi

chmod +x $name/run

echo
echo ==============================
echo Finished
echo ==============================
echo 
echo To launch UML, type:
echo   cd $name
echo   ./run
echo
echo Have a lot of fun!
echo

Run this script as root and follow the instructions (or type in the commands by hand: see [2], how to create the image). You need at least ~ 150 MB space for the root partition.

After launching the UML (cd <name> && ./run), it should be possible to log in through SSH:

ssh root@ip.address.of.uml

If you have any problems, try to search the internet.

Have a lot of fun!

Links

Here are some useful links:


Zurück zu www.eggdrop.ch | Back to www.eggdrop.ch

Last update: 23.07.04

Copyright (C) 2004 by Thomas "tom" S. <tom at eggdrop.ch>
Valid HTML 4.0!

Creative Commons License This work belongs to http://www.eggdrop.ch/ and is licensed under a Creative Commons License.