This document describes how you can recreate PXE Imager from the beginning. This serves both as documentation for myself, and as a guide for others who wish to create a stripped down version of Debian. PXE Imager is a tool that boots a system over the network, then presents a menu of preconfigured disk images to be installed, and then installs them. It is composed of a stripped down Debian disk image and a Python program that does the dirty work. To create it, you need root access to a Linux system. The first step is to create a Debian root filesystem. The debootstrap
tool in Debian is used to do this, with the following command.
debootstrap sarge rootdir [Mirror URL]
This will download all the files in the release sarge
into rootdir
. However, nothing is configured. We will need to fix that. First, create the /etc/fstab
file. The following works for PXE booting, since it uses a RAM disk as root.
# /etc/fstab: static file system information. # <file system> <mount point> <type> <options> <dump> <pass> /dev/ram0 / ext2 defaults 0 0 proc /proc proc defaults 0 1 tmpfs /tmp tmpfs defaults 0 1
Next, we need to configure the locale for the keyboard with the following command. I selected "keep kernel keymap." You will get a bunch of errors, since it won't work in the chroot, but it should work when you boot. Also, you probably want to configure debconf to use "readline" for configuring packages, so that it works on a serial console.
dpkg-reconfigure console-data dpkg-reconfigure debconf
Network Configuration
First, create a /etc/hosts
file (easy way: cp /etc/hosts rootdir/etc/hosts
). Since we are using PXE boot, we know that the system has an Ethernet card. Assuming that it is found during the boot process, use the following for /etc/network/interfaces
, as it will automatically bring up eth0
using DHCP.
# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or # /usr/share/doc/ifupdown/examples for more information. # The loopback network interface auto lo iface lo inet loopback # The primary network interface auto eth0 iface eth0 inet dhcp
Configure your hostname:
echo pxeboot > rootdir/etc/hostname
Edit /etc/inittab
to run bash instead of presenting a login prompt. This allows us to remove a bunch of packages related to logging in, which won't be needed anyway.
1:2345:respawn:/bin/bash #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
Remove Useless Packages
Since we want to put this image in RAM, we need to remove all the useless stuff. To remove packages, run chroot rootdir dpkg --purge [package names]
. Here is a list that I removed:
ppp pppconfig pppoe pppoeconf whiptail libnewt0.51 libpcap0.7 logrotate libpopt0 at sysklogd klogd iptables ipchains wget telnet cron exim4 exim4-base exim4-config exim4-daemon-light mailx base-config adduser makedev apt apt-utils base-config aptitude tasksel gettext-base nano nvi ed man-db manpages groff-base info pciutils bsdmainutils fdutils cpio modutils console-tools console-common console-data libconsole # --force-depends needed to remove the following: tcpd libwrap0 netkit-inetd iputils-ping # Finally, libraries libsigc++-1.2-5c102 libtextwrap1 liblockfile1 libssl0.9.7 libdb4.2 libpcre3 libgnutls11 libtasn1-2 liblzo1 libopencdk8 libgcrypt11 libgpg-error0 # Need --force-depends, or to install debconf-english libtext-wrapi18n-perl libgdbm3 libtext-iconv-perl liblocale-gettext-perl libtext-charwidth-perl
Then install the following packages:
# replaces debconf-i18n, which is much larger debconf-english # Small vi clone elvis-tiny # Automatic hardware detection discover discover-data libdiscover2 libexpat1 # Needed for 2.6 kernel modules module-init-tools # For TFTP transfers atftp libncurses5 # For the "pxeimager.py" script (use --force-depends to install) python2.3
/dev Devices
Modern Linux distributions use tools like udev
to create devices in /dev
as needed. Those tools are great, but take up too much space for our stripped down image. I just created them the old fashioned way. You can use the MAKEDEV
script to create devices for you, but I find it creates far too many. I simply used the /dev
directory from Pebble Linux.
Kernel
Since this image is going to be booted over the network, the kernel configuration is a bit unconventional. The only files we need on the actual system are the modules, since the kernel itself is downloaded over the network. I unpack the kernel package, and then manually install the modules. Also, you will need the kernel on your TFTP server (/boot/vmlinuz-*
), so be sure to copy it to your /tftpboot
directory.
dpkg-deb -x [kernel image] [temp dir] mv [temp dir]/lib/modules/* rootdir/lib/modules cp [temp dir]/boot/vmlinuz-* /tftpboot
At this point, we have a basic usable Debian system. To make life easier, I like to package up the root at this point as rootdir.tar
.
pxeimager.py
To present a nice menu at boot, copy the pxeimager.py
script to rootdir
. You will then need to modify the /etc/inittab
file to start it on the first console:
Stripping Down the Image
Now we need to remove a bunch of stuff in order to save disk space, to make this actually bootable over the network. My approach is to remove a bunch of Debian packages which are considered "essential" but we won't use, and then manually delete a bunch of files. To make this easier, I've created a script called shrink.sh
that does all the deleting. It is included in the PXE Imager source distribution.
Creating a Disk Image
You can either use ext2 or CramFS. CramFS makes a slightly larger image, but it is much faster to boot since it does not need to be decompressed in memory. However, its filesystems are read-only. Since it is easier to deal with a writeable root, I use ext2. The shrink.sh
script includes the following commands for creating the disk image:
dd if=/dev/zero of=pxeimager.img bs=1k count=32000 mke2fs -F pxeimager.img tune2fs -c 0 -i 0 pxeimager.img mount pxeimager.img /mnt -t ext2 -o loop cp -ar rootdir.shrink/* /mnt umount /mnt gzip pxeimager.img