OK, here is how I went about network booting Fedora 8. I'll be booting my machine from a Solaris box, but any reasonable NFS server should do.

First, fire up VMWare, and do a basic install of Fedora 8. You can choose whatever packages you want (I suggest a minimal install plus "Software Development", since you can add extra stuff later). We will be using this machine to give us a tarball of the Fedora root filesystem, plus a platform to build the initrd.

Once your Fedora 8 VM is installed, log in and run the updater (theres no point in making an image thats out of date, otherwise you will have to update every other image you create). Once thats done, take a tarball of the root filesystem and /nooy. Assuming you've gone with a default install of Fedora, all the other filesystems are ephermeral, and will be recreated on boot. In the example below, I've assumed that /mnt contains some additional space (NFS, another virtual hard drive, whatever).

tar jcvf /mnt/root.tbz --one-file-system -C / .
tar jcvf /mnt/boot.tbz --one-file-system -C /boot .

tar jcvf /mnt/dev.tbz -C /dev console initctl MAKEDEV mapper null

Now, Fedora depends heavily on kernel modules, rather than building the various bits and pieces into the kernel. This means that when the computer boots, it needs to have available the kernel modules required to access the root filesystem (be it a SCSI controller, or in our case, a network controller). Once it has access to the root filesystem, it can load whatever it wants. The way to make these drivers available to the kernel at boot time is to package them into a cpio archive called an initrd.

The initrd contains a filesystem, with utilities, modules and scripts required to bootstrap the system. Unfortunately, the "mkinitrd" script supplied with Fedora does not generate a suitable initrd for an NFS root filesystem, mostly due to the braindead inadequacies of nash. To fix this, we will have to roll own, and we will build it around the BusyBox set of utilities. To do this, start by extracting the attached file somewhere sensible (like /usr/src).

In your Linux virtual machine, extract and build the latest stable version of BusyBox - you can download it from http://www.busybox.net. When configuring BusyBox, ensure you request static binaries (so you don't have to package a seperate C runtime). Under the installation options, link the applets as soft-links, tick the "Don't use /usr" box, and set the installation prefix to the "root" subdirectory of initrd (which you extracted above). When building, read the warning about static linking glibc, follow the link and understand it, then ignore it.

If you are going to be using bridging in your machine (eg, to run Xen or VMWare), you will also want to build brctl. You can download the bridge-utils package from sourceforge, then do the following to build it:

  • autoconf
  • ./configure
  • edit brctl/Makefile, and change: LIBS to "../libbridge/libbridge.a", LDFLAGS to "-static"
  • go back to the top level directory and run make
  • strip brctl/brctl then copy it to initrd/root/bin

Now, edit the root/init script, and tailor it to your needs. If you aren't going to be using bridging, you can comment out the bridge commands (don't forget to update $nfsdev to your real ethernet interface). Add in whatever modules are required you get your network interfaces up, as well as NFS. These should be done before the "modprobe bridge" line. Note that modules have dependancies, and modprobe will automatically try to load the dependancies for you. To identify what modules you require, you can look at the output of "lsmod" - the left side shows the module name, the right side shows which modules depend on it. You can also look in /lib/modules/`uname -r`/modules.dep. At a minimum, these are the modules you need:

  • nfs
  • lockd
  • nfs_acl
  • sunrpc
  • bridge (if you require bridging)
  • whatever you require for your network card

Once you have identified the required modules, and updated the init script, copy the appropriate modules from /lib/modules/`uname -r`/kernel to initrd/root/lib/modules. The following are the modules I needed:

  • net/bridge/bridge.ko
  • drivers/net/e1000/e1000.ko
  • drivers/net/r8169.ko
  • fs/nfs/nfs.ko
  • fs/nfs_common/nfs_acl.ko
  • fs/lockd/lockd.ko
  • net/sunrpc/sunrpc.ko
  • drivers/usb/host/ehci-hcd.ko
  • drivers/usb/host/uhci-hcd.ko
  • drivers/usb/host/ohci-hcd.ko
  • modules.dep

You can now run the build script in initrd to generate the initrd. Copy the new initrd and the kernel (from /boot) into the root of your tftp server, extract the root tarball into your NFS server, then configure the following files in the extracted root:

  • /etc/fstab
  • rename /etc/sysconfig/network-scripts/ifdown-eth to /etc/sysconfig/network-scripts/disabled.ifdown-eth
  • rename /etc/sysconfig/network-scripts/ifcfg-eth0 to /etc/sysconfig/network-scripts/disabled.ifcfg-eth0
  • edit /etc/sysconfig/network and comment out the HOSTNAME line (it will clobber your hostname from DHCP)
  • extract dev.tbz into the /dev directory of your new nfsroot

So far, you should have created a root filesystem that is exported via NFS and an initrd which will mount the root filesystem from NFS. Now, we will configure pxelinux to boot the kernel and initrd you have chosen.

First, grab the SYSLINUX source from http://syslinux.zytor.com/ and build PXELINUX. Copy the pxelinux binary into your tftp root, and then configure your DHCP server to direct clients to boot from that image. For ISC DHCPD, I used the following directives:

filename "pxelinux";
next-server tftpserver.your.domain;

Now, configure pxelinux to boot the kernel and initrd you have created. In your tftp root, create a directory called pxelinux.cfg, then create a file called default, with the following content:

DEFAULT F8
PROMPT 1
TIMEOUT 50

LABEL F8
kernel vmlinuz-2.6.23.1-49.fc8
append initrd=initrd-2.6.23.1-49.fc8

Your machine should now be able to boot from the network, and mount its root filesystem via NFS.