First you will need a working DHCP and TFTP server setup. Make it so. You will now need to get a PXE boot working. Maybe get something like the Debian Installer and put it in your TFTP server root: http://www.us.debian.org/devel/debian-installer/ (look for "other images (netboot, usb stick, floppy, etc)") or directly: http://people.debian.org/~joeyh/d-i/images/daily/netboot/netboot.tar.gz You will need to let DHCP know to tell the machine to get the PXE image. My dhcpd.conf conatins this: host santos { hardware ethernet 00:0c:29:b6:e5:3b; fixed-address santos; next-server moleman; filename "pxelinux.0"; } Create a file to use as the block device. eg. a 4Gb file: dd if=/dev/zero bs=1k count=1 seek=`expr 1024 \* 4096` of=vblade-0.0 Serve the file with vblade (The Coraid ATAoE demo tool - there's a vblade package in Debian): vblade 0 0 eth0 vblade-0.0 Boot up ubuntu from the "alternate" cd (haven't got Ubuntu to boot the installer over the network yet. Debian installer works great though). When you get to setting the hostname, pause and get a console (alt-f2): modprobe aoe There should now be devices under /dev/etherd/ we need to make the installer aware of them - there might be a better way, but a crude way is to make symlinks from what would be a normal disk to the devices. The installer will actually pick up the real device path, so there's no need to modify fstab later. Here we asume the aoe devices are around e0.0 and we are going to make them look like sda. cd /dev ln -s etherd/e0.0 sda Use fdisk (fdisk /dev/sda) to create a disk label. Write it out. Use fdisk again, create a single primary partition that covers the whole disk. ln -s etherd/e0.0p1 sda1 Go back to the installer and partition the disk manually when requested. Just change the options on the partition to your filesystem of choice and make it root. Do the install as usual. Tell it you don't want swap space (if you really did want swap space then you should make partitions for that too - i imagine it will all work fine - just rather slowly :). wget the aoe script (inluded below) from somewhere. As soon as the base system completes copy it to /target/usr/share/initramfs-tools/scripts/aoe You need to do this before the installer creates the initrd image otherwise it won't get included. Don't know when this is, but it must be towards the end of the installation process. Wait for installation to finish. Grub will fail. Ignore it and continue without a boot loader. Power the machine off when it tries to reboot. When the machine has shutdown, mount the new filesystem (/dev/etherd/e0.0p1) on another machine (remember to load the aoe module - best to have aoe-tools installed too - probably best to mount read-only too), copy the initrd and kernel images (vmlinuz-2.6.20-15-generic and initrd.img-2.6.20-15-generic or similar) from the boot directory. put them in your tftp server directory. REMEMBER TO UNMOUNT THE FILESYSTEM! Modify your pxelinux.cfg/* file like so, adjusting for your kernel version, filesystem type, etc: DEFAULT vmlinuz-2.6.20-15-generic LABEL vmlinuz-2.6.20-15-generic kernel vmlinuz-2.6.20-15-generic append vga=normal initrd=initrd.img-2.6.20-15-generic ro ip=dhcp root=/dev/etherd/e0.0p1 rootfstype=ext3 boot=aoe -- Boot your machine. It gets the pxelinux.0 binary and the config file, reads the kernel and initrd images, starts booting, runs the aoe script to load the aoe module and mount the root filesystem and should work as normal. Hurrah! If the kernel is upgraded you will need to copy out the kernel and initrd files as before and update your pxelinux.cfg file to serve the new files. -- aoe script --------------------8<-- cut here --8<-------------------- # AOE filesystem mounting -*- shell-script -*- # FIXME This needs error checking retry_nr=0 # parse aoe bootargs + launch ipconfig and smount do_aoemount() { sleep 3 # support ip options see linux sources Documentation/nfsroot.txt case ${IPOPTS} in none|off) # Do nothing ;; ""|on|any) # Bring up device ipconfig ${DEVICE} ;; dhcp|bootp|rarp|both) ipconfig -c ${IPOPTS} -d ${DEVICE} ;; *) ipconfig -d $IPOPTS # grab device entry from ip option NEW_DEVICE=${IPOPTS#*:*:*:*:*:*} if [ "${NEW_DEVICE}" != "${IPOPTS}" ]; then NEW_DEVICE=${NEW_DEVICE%:*} else # wrong parse, possibly only a partial string NEW_DEVICE= fi if [ -n "${NEW_DEVICE}" ]; then DEVICE="${NEW_DEVICE}" fi ;; esac # # source relevant ipconfig output # . /tmp/net-${DEVICE}.conf # # get nfs root from dhcp # if [ "x${NFSROOT}" = "xauto" ]; then # NFSROOT=${ROOTSERVER}:${ROOTPATH} # # nfsroot=[:][,] # elif [ -n "${NFSROOT}" ]; then # # nfs options are an optional arg # if [ "${NFSROOT#*,}" != "${NFSROOT}" ]; then # NFSOPTS="-o ${NFSROOT#*,}" # fi # NFSROOT=${NFSROOT%%,*} # if [ "${NFSROOT#*:}" = "$NFSROOT" ]; then # NFSROOT=${ROOTSERVER}:${NFSROOT} # fi # fi # if [ -z "${NFSOPTS}" ]; then # NFSOPTS="-o retrans=10" # fi # [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/nfs-premount" # run_scripts /scripts/nfs-premount # [ "$quiet" != "y" ] && log_end_msg if [ ${readonly} = y ]; then roflag="-o ro" else roflag="-o rw" fi echo discovering aoe devices echo 1 > /dev/discover sleep 3 echo mount ${roflag} -t ${ROOTFSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt} sleep 3 mount ${roflag} -t ${ROOTFSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt} # drop to a shell if that failed if [ $? != 0 ]; then sh; fi } # AOE root mounting mountroot() { [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/aoe-top" run_scripts /scripts/aoe-top [ "$quiet" != "y" ] && log_end_msg modprobe -q aoe # For DHCP modprobe -q af_packet # Default delay is around 180s # FIXME: add usplash_write info if [ -z "${ROOTDELAY}" ]; then delay=180 else delay=${ROOTDELAY} fi # loop until aoemount succeds while [ ${retry_nr} -lt ${delay} ] && [ ! -e ${rootmnt}${init} ]; do [ ${retry_nr} -gt 0 ] && \ [ "$quiet" != "y" ] && log_begin_msg "Retrying aoe mount" do_aoemount retry_nr=$(( ${retry_nr} + 1 )) [ ! -e ${rootmnt}${init} ] && /bin/sleep 1 [ ${retry_nr} -gt 0 ] && [ "$quiet" != "y" ] && log_end_msg done [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/aoe-bottom" run_scripts /scripts/aoe-bottom [ "$quiet" != "y" ] && log_end_msg }