From FAIWiki
Revision as of 15:30, 12 July 2009 by RobertMarkula (talk | contribs) (Some minor corrections, clarification about debian NFSroot, more information on a multi-distribution setup)
Jump to: navigation, search


Goal: Using FAI to install ubuntu 9.04 'Jaunty Jackalope' (heck, any other distribution). I'm assuming that you want to run FAI server on an ubuntu 9.04 server, however, the procedures are very similiar if you want to use debian on the server side.

Since I know how frustrating it can be for a novice user to try to understand the many bits and pieces of this powerful technology, the intention of this howto is to get you quickly to a working basic FAI configuration on which you can build up your knowledge. It is intentionally very verbose, describing and explaining *every* step necessary to reach this goal. So don't be put off by the length of this howto; you should be up&running fairly quickly.

Feel free to edit this article as you see fit, after all, it's a wiki!

Credits go, among many others, to Henning Glawe, Richard Grant and Henning Sprang, who helped me figuring out my way to this solution. Thanks for your friendly support!

Note: Before we dive into the subject, please note that due to a current lack of physical machines, all my testing was done in a VirtualBox environment, with both the ubuntu server and the target client in a vm on the same host. The steps described here should work no matter what, but please keep these special circumstances in mind should something not work as expected.

Disclaimer: You use this howto on your own risk! I don't and can't take any responsibility in case your whole IT blows up!

Now, I'll walk you step-by-step to setting up a complete FAI infrastructure from ground up. This means, some of the steps may already be implemented in your network, such as a DHCP server, but you may still want to check your existing configuration to see if it corresponds to the config described here.


I assume that you are building a separate testing environment to follow the procedures below. That's not a bad idea for the first time anyway, and a very good way to do this is installing both the ubuntu server as well as the target clients in a VirtualBox (or any other VM) environment.

Edit the virtual machine settings as follows:

  • ubuntu server
    • At least 5 GB of disk space
    • NIC 1 (aka eth0): Connected to: Bridged mode, Name: [name of your physical network adapter, e.g. 'eth0' or 'wlan0']
    • NIC 2 (aka eth1): Connected to: Internal network, Name: intnet
  • ubuntu client
    • NIC 1 (aka eth0): Connected to: Internal network, Name: intnet, MAC: 112233445566

Then you'll have a separate network for your FAI testing:

  • ubuntu server will have the IP and act as a router to the outside world (i.e. the rest of the network).
  • the ubuntu example client we are going to install will have the IP
  • All other clients will be assigned an IP from the range -

ubuntu Server installation

First things first. Remember, this is a ground-up tutorial, so let's make sure we use the same environment.

Enter the ubuntu install CD into the ubuntu server and start the install. During install, answer the question as follows (in this tutorial I'll assume a german setup. Why? Because I want to point out how to get the german keyboard layout working on the client console, which is a bit tricky. The same principles apply for any language other than en_US. If you want to use the default en_US setup, just don't use the LANG_GERMAN class and you're on your way).

  • Choose Language
    • Wählen Sie ein Land oder Gebiet: Deutschland
  • ubuntu-Installer-Hauptmenü
    • Tastaturmodell erkennen: Nein
    • Herkunft der Tastatur: Germany
    • Tastenbelegung: Germany
  • Netzwerk einrichten
    • Primäre Netzwerk-Schnittstelle: eth0
    • Rechnername: vm-ubuntuserver
  • Festplatten partitionieren
    • Partitionsmethode: Geführt - gesamte Platte verwenden und LVM einrichten
    • Wählen Sie die zu partitionierende Festplatte: SCSI2 (0,0,0) (sda)
    • Änderungen auf die Speichergeräte schreiben und LVM einrichten: Ja
    • Amount of volume group to use for guided partitioning: 4.0 GB
    • Änderungen auf die Festplatten schreiben: Ja
  • Benutzer und Passwörter einrichten
    • Voller Name des neuen Benutzers: John Doe
    • Benutzername für Ihr Konto: john
    • Wählen Sie ein Passwort für den neuen Benutzer: [Enter password]
    • Ihren persönlichen Ordner verschlüsseln: Nein
  • Den Paketmanager konfigurieren
    • HTTP-Proxy-Daten:
  • Software auswählen und installieren
    • Wie möchten Sie Aktualisierungen auf diesem System verwalten: Keine automatischen Aktualisierungen
  • Softwareauswahl
    • Welche Software soll installiert werden:
      • [ ] DNS server
      • [ ] LAMP server
      • [ ] Mail server
      • [*] OpenSSH server
      • [ ] PostgreSQL database
      • [ ] Print server
      • [ ] Samba file server
      • [ ] Tomcat Java server
      • [ ] Virtual Machine host
      • [ ] Manual package selection

Now reboot the machine.

Configure your ubuntu server

Log in with your username and change to user root:

sudo su

Configuring the network

I assume the ubuntu server has two NICs, eth0 with contact to the outside world, and eth1 with contact to the internal network. Edit the following file:

vi /etc/network/interfaces

and replace the content with the following lines:

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
# The external network
auto eth0
iface eth0 inet static

# The internal network
auto eth1
iface eth1 inet static

Restart the server. If you use ubuntu server in a VM, it may be practical to create a snapshot now. Once restarted, log in with your username and change to user root as before:

sudo su

Install apt-proxy

You'll need quite a few packages for your server and clients. Let's be clever and use a proxy which caches the packages for you so they don't have to be downloaded from the internet each time, thus speeding up the process to a great extend.

Install apt-proxy:

apt-get -y install apt-proxy

Open the following file:

vi /etc/apt-proxy/apt-proxy-v2.conf

and replace the line:

;dynamic_backends = on

with the following line:

dynamic_backends = on

Restart apt-proxy:

/etc/init.d/apt-proxy restart

Change your sources.list, so it uses the apt-proxy you've installed earlier:

vi /etc/apt/sources.list

and replace the content with the following lines (where is the IP of your apt-proxy):

## Main Repositories 
deb jaunty main restricted 
deb-src jaunty main restricted 

## Major bug fix updates produced after the final release of the 
## distribution. 
deb jaunty-updates main restricted 
deb-src jaunty-updates main restricted 

## Universe Repositories 
deb jaunty universe 
deb-src jaunty universe 
deb jaunty-updates universe 
deb-src jaunty-updates universe 

## Multiverse Repositories 
deb jaunty multiverse 
deb-src jaunty multiverse 
deb jaunty-updates multiverse 
deb-src jaunty-updates multiverse 

## Security Updates 
deb jaunty-security main restricted 
deb-src jaunty-security main restricted 
deb jaunty-security universe 
deb-src jaunty-security universe 
deb jaunty-security multiverse 
deb-src jaunty-security multiverse

# FAI Repository 
deb lenny koeln

Import the GPG-key of the FAI repository:

apt-key adv --recv-keys --keyserver keyserver.ubuntu.com AB9B66FD

Update the sources and install any security fixes that might be out there:

apt-get update && apt-get -y upgrade

Installing and configuring DHCP

Now it's time to install a DHCP server:

apt-get -y install dhcp3-server

The DHCP server should only listen to the internal network interface in order to not interfere with the external's network DHCP server (e.g. your internet router). To accomplish this, open the following file:

vi /etc/default/dhcp3-server

and replace the content with the following line:


Configure your new DHCP server:

vi /etc/dhcp3/dhcpd.conf

and replace the content with the following lines:

# Do not attempt tu do a DNS update when a lease is confirmed
ddns-update-style none;

# DNS server
option domain-name-servers;

# Other global options
default-lease-time 42300;
max-lease-time 84600;

# This DHCP server is the official DHCP server for
# the local network

# Send DHCP log messages to a different log file
log-facility local7;

# Declare the subnets
subnet netmask {

	# The Domain name
	option domain-name "domainname.local";
	# The DHCP range
	# Subnet mask
	option subnet-mask;
	# The Gateway (i.e. internet router)
	option routers;
	# Broadcast address
	option broadcast-address;
	# NTP server
	option ntp-servers;

	# TFTP-Server for PXE-Boot
	filename "pxelinux.0";

	# Set the hostnames globally
	use-host-decl-names on;
	# Assign this client a specific IP
	host vm-ubuntu904 {
		# Define the MAC-Address of the client
		hardware ethernet 11:22:33:44:55:66;
		# Assign the static IP

The lines next-server; and filename "pxelinux.0"; point to your FAI-Server which will get the IP The option use-host-decl-names on; specifies that the host vm-ubuntu904 statement sets the hostname for your clients. Setting the correct hostnames is very important in your FAI environment, because the classes depend on the hostname!

Restart the DHCP daemon:

/etc/init.d/dhcp3-server restart

Installing DNS

In order for your clients to use DNS (e.g. resolving google.com), you need to install a DNS server:

apt-get -y install bind9

Activate routing (optional)

If you install the ubuntu server on your existing network (with both the FAI server and the target clients on the same subnet as the rest of the network), you can safely skip this step.

However, if you want to have a safe testing environment with the ubuntu server and FAI in a separate subnet (say, running them in virtual machines), you'll need to activate routing on the ubuntu server, because all network connections from your testing network will go over the ubuntu server.

Activating IP-Forwarding:

sysctl -w net.ipv4.ip_forward=1

Activating IP-Masquerading:

apt-get -y install ipmasq

Restart IPmasq:

/etc/init.d/ipmasq restart

Installing and configuring a TFTP server

For PXE boot you'll need a TFTP server.

apt-get -y install tftpd-hpa

To teach the TFTP server to start as a daemon, edit the following file:

vi /etc/default/tftpd-hpa

and replace the content with the following lines:

# Defaults for tftpd-hpa
OPTIONS="-l -s /srv/tftp/fai"

Then, edit this file:

vi /etc/inetd.conf

and comment out the following line (=put a hash sign # in front of the line):

tftp dgram udp wait root /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /var/lib/tftpboot

Restart the TFTP-server:

/etc/init.d/tftpd-hpa restart

Setting up FAI

Congratulations, if you've made it this far, all the boring basic task are mastered. Let's get on with the really exciting stuff, that is, installing and configuring FAI!

Install FAI:

apt-get -y install fai-server fai-doc syslinux

Open the FAI config file:

vi /etc/fai/fai.conf

and replace the content with the following lines:

# an account on the install server which saves all log-files
# and which can change the kernel that is booted via network.

# set protocol type for saving logs. Values: ssh, rsh, ftp

# the install server

# the configuration space on the install server

# access the config space on the specified install server
# using NFS

# mount point where the mirror will be mounted

# the local configuration directory on the install client

Open the nfsroot config file:

vi /etc/fai/make-fai-nfsroot.conf

and replace the content with the following lines:

# the directory on the install server which contains
# the nfsroot

# TFTP root directory

# Where to get the packages needed to build the
# nfsroot
FAI_DEBOOTSTRAP="lenny http://ftp.debian.org/debian"

# the encrypted (with md5 or crypt) root password on all install clients during
# installation process; used when log in via ssh; default pw is: fai

# following lines should be read only for most of you

We purposely create a Debian NFSroot here, so it is important to leave the line FAI_DEBOOTSTRAP as in the example above!

If you look careful enough, you'll note that I didn't use our apt-proxy for the FAI_DEBOOTSTRAP option. This is because I had problems building the nfsroot if an apt-proxy was specified. Not using the apt-proxy here won't hurt much anyway, because the nfsroot has to be built only once - no matter how many distributions you are going to install afterwards.

Correct the owner settings of the directory /var/log/fai (the logs will be written to this directory):

chown -R fai /var/log/fai

It's time to run fai-setup for the first (and hopefully the only) time. Get yourself a nice cup of coffee and relax, as this will take a while (for troubleshooting purposes run fai-setup -v to get a verbose output):


After this is finished, make sure you see both the following messages in the log:

make-fai-nfsroot finished properly.
FAI setup finished.

Also, check the log for any other suspicious messages.

fai-setup was so friendly to setup our NFS exports for us. However, you might want to double-check if the exports are correct for your network implementation. Example given, in our environment we have to change the exports to fit our network structure. Open the following file:

vi /etc/exports

uncomment the following lines:


and add the following lines below:

# NFS3 exports for FAI and PXE boot

Re-read the exports file:

exportfs -rv

Building your configspace

As already mentioned, this howto tries to accomplish three things:

  1. Getting FAI up&running fairly quickly
  2. Being client distribution agnostic (in this specific case, installing ubuntu 9.04 on the clients; in more general terms, installing any other distribution on the clients - keyword multi-distribution)
  3. Using german keyboard layout on the client's console

You can of course adapt the settings to your specific setup, which I encourage you to do anyway. There's no better learning than hands-on experience!

Creating the directory structure

The first, and most important step is to configure your configspace. Prepare your configspace by creating the following directories in /srv/fai/config/ (I can post a tar.gz file with all the files as described below if someone offers a serious, permanent public hosting for this file):

cd /srv/fai/config/
mkdir basefiles && mkdir class && mkdir debconf && mkdir disk_config && mkdir -p files/etc/apt/secring.gpg && mkdir files/etc/apt/sources.list && mkdir files/etc/apt/trustdb.gpg && mkdir files/etc/apt/trusted.gpg && mkdir -p files/etc/default/console-setup && mkdir files/etc/default/locale && mkdir -p files/etc/network/interfaces && mkdir hooks && mkdir package_config && mkdir -p scripts/BC_BASE && mkdir scripts/GRUB && mkdir scripts/LAST

This will give you the following directory strucure:

|-- basefiles
|-- class
|-- debconf
|-- disk_config
|-- files
|   `-- etc
|       |-- apt
|       |   |-- secring.gpg
|       |   |-- sources.list
|       |   |-- trustdb.gpg
|       |   `-- trusted.gpg
|       |-- default
|       |   |-- console-setup
|       |   `-- locale
|       `-- network
|           `-- interfaces
|-- hooks
|-- package_config
`-- scripts
    |-- BC_BASE
    |-- GRUB
    `-- LAST

Creating files in the configspace

We have the directory structure set up, let's fill it with life!

The basefiles directory:

  • We'll leave this empty for now; later the base.tar.gz file of each client distribution is copied in here

The class directory:

  • vi class/10-base-classes

Paste the following lines:

#! /bin/bash

# Echo architecture and OS name in uppercase. Do NOT remove these two lines.
uname -s | tr '[:lower:]' '[:upper:]'
[ -x "`which dpkg`" ] && dpkg --print-installation-architecture | tr a-z A-Z

[ -f /etc/RUNNING_FROM_FAICD ] && echo "FAICD"
exit 0
  • vi class/20-hwdetect.source

Paste the following lines:

#! /bin/bash

# (c) Thomas Lange, 2002-2008, lange@informatik.uni-koeln.de

# NOTE: Files named *.source will be evaluated, but their output ignored. Instead
# the contents of $newclasses will be added to the list of defined classes.

[ "$action" = "dirinstall" ] && return 0 # Do not execute when doing dirinstall

echo 0 > /proc/sys/kernel/printk

# load all IDE drivers

# DMA does not work if we load all modules in drivers/ide, so only try pci modules
mod=$(find /lib/modules/$(uname -r)/kernel/drivers/ide/pci -type f | sed 's/\.o$//' | sed 's/\.ko$//' | sed 's/.*\///')
for i in $mod; do
    modprobe $i 1>/dev/null 2>&1
# Booting from CD does not always enable DMA.
for d in $( echo /proc/ide/hd[a-z] 2>/dev/null); do
    [ -d $d ] && echo "using_dma:1" > $d/settings

# load additional kernel modules (from old 11modules.source)
# this order should also enable DMA for all IDE drives
kernelmodules="usbkbd ide-disk ide-cd"
case $(uname -r) in
    2.6*) kernelmodules="$kernelmodules ohci-hcd usbhid usbmouse ide-generic mptspi ata_piix dm-mod md-mod aes dm-crypt" ;;

for mod in $kernelmodules; do
    [ "$verbose" ] && echo loading kernel module $mod
    modprobe -a $mod 1>/dev/null 2>&1

# let discover do most of the job
#[ -x /sbin/discover-modprobe ] && /sbin/discover-modprobe

# now we can mount the USB filesystem
mount -t usbfs  usbfs /proc/bus/usb

modprobe -a sd_mod sr_mod

echo $printk > /proc/sys/kernel/printk

set_disk_info  # calculate number of available disks
save_dmesg     # save new boot messages (from loading modules)

  • vi class/50-host-classes

Paste the following lines:

#! /bin/bash

# assign classes hosts

# use a list of classes for our demo machine
case $HOSTNAME in

(ifclass I386 || ifclass AMD64) && echo GRUB 
exit 0
  • vi class/BC_BASE.var

Paste the following lines:

# Base class which is shared among clients (which includes servers)
# may be overridden with custom *.var files

# allow installation of packages from unsigned repositories


# set UTC=yes if your system clock is set to UTC (GMT), and UTC=no if not.

# root password for the new installed linux system; md5 and crypt are possible
# pw is "fai"

# MODULESLIST contains modules that will be loaded by the new system,
# not during installation these modules will be written to /etc/modules
# If you need a module during installation, add it to $kernelmodules
# in 20-hwdetect.source. But discover should do most of this job
MODULESLIST="usbkbd ehci-hcd ohci-hcd uhci-hcd usbhid psmouse"

# erros in tasks greater than this value will cause the installation to stop


# use the new partitioning tool

# limit the number of packages install added to apt-get or aptitude

# if fai is usded to do softupdates, any local changes on the
# install clients are lost. However, fai makes backup copies of
# locally changed files; by default, they are written to the same
# directory as the original file, with .pre_fcopy appended.
# If you wish to save them together with the logfiles, this will
# do the job:

# if log files are saved via FTP on the server, this specifies the
# path to save logfiles to. Not needed if $FAI_LOGPROTO in file
# fai.conf is set to 'ssh'.


The debconf directory:

  • vi debconf/LANG_GERMAN

Paste the following lines:

locales		locales/default_environment_locale select de_DE.UTF-8
locales		locales/locales_to_be_generated multiselect de_DE.UTF-8 UTF-8
xserver-xorg	xserver-xorg/config/inputdevice/keyboard/layout	string	de
xserver-xorg	xserver-xorg/config/inputdevice/keyboard/model	string	pc105
xserver-xorg	xserver-xorg/config/inputdevice/keyboard/options	string	lv3:ralt_switch
xserver-xorg    xserver-xorg/autodetect_monitor         boolean false
xserver-xorg    xserver-xorg/autodetect_keyboard        boolean true
xserver-xorg    xserver-xorg/autodetect_mouse           boolean true
xserver-xorg    xserver-xorg/autodetect_video_card      boolean true
console-setup	console-setup/variant	select	Germany
console-setup	console-setup/charmap	select	UTF-8
console-setup	console-setup/layoutcode	string	de
console-setup	console-setup/compose	select	No compose key
console-setup	console-setup/fontsize-text	select	16
console-setup	console-setup/optionscode	string	lv3:ralt_switch
console-setup	console-setup/layout	select	Germany
console-setup	console-setup/detected	note	
console-setup	console-setup/variantcode	string	
console-setup	console-setup/codesetcode	string	Lat15
console-setup	console-setup/modelcode	string	pc105
console-setup	console-setup/ask_detect	boolean	false
console-setup	console-setup/altgr	select	Right Alt
console-setup	console-setup/ttys	string	/dev/tty[1-6]
console-setup	console-setup/model	select	Generic 105-key (Intl) PC
console-setup	console-setup/fontsize-fb	select	16
console-setup	console-setup/switch	select	No temporary switch
console-setup	console-setup/codeset	select	# Latin1 and Latin5 - western Europe and Turkic languages
console-setup	console-setup/toggle	select	No toggling
console-setup	console-setup/fontface	select	VGA
console-setup	console-setup/fontsize	string	16

The disk_config directory:

  • vi disk_config/HDD_SINGLE

Paste the following lines:

# Standard client formatting using setup-storage
# <type> <mountpoint> <size> <fs type> <mount options> <misc options>
disk_config disk1 disklabel:msdos

primary		/	4G	ext3	rw,relatime,errors=remount-ro
primary		-	1G	swap	sw

The files directory:

  • files/etc/apt/*: You have to copy the files from the /etc/apt/-directory from an existing reference client with the desired distribution version to this directory. Let's say, you want to use this FAI configuration to install ubuntu 9.04 on the client. Then you boot to a reference client (a live CD will suffice) and copy the following files from the reference client to this directory:
    • secring.gpg
    • sources.list
    • trustdb.gpg
    • trusted.gpg
  • Don't forget to rename the files accordingly. E.g. secring.gpg will be files/etc/apt/secring.gpg/OS_UBUNTU_904_X32!

However, you might want to edit the apt/sources.list (vi files/etc/apt/sources.list/OS_UBUNTU_904_X32) so it points to your apt-proxy. If you've followed the steps above, you will be already familiar with that. In the case of ubuntu 9.04 you paste the following lines:

deb jaunty main restricted 
deb-src jaunty main restricted 

deb jaunty-updates main restricted 
deb-src jaunty-updates main restricted 

deb jaunty universe 
deb-src jaunty universe 
deb jaunty-updates universe 
deb-src jaunty-updates universe 

deb jaunty multiverse 
deb-src jaunty multiverse 
deb jaunty-updates multiverse 
deb-src jaunty-updates multiverse 

deb jaunty-security main restricted 
deb-src jaunty-security main restricted 
deb jaunty-security universe 
deb-src jaunty-security universe 
deb jaunty-security multiverse 
deb-src jaunty-security multiverse

# FAI Repository
deb lenny koeln

All other files in the files/etc/apt/-directory are binaries!

  • vi files/etc/default/console-setup/LANG_GERMAN

Paste the following lines:

# A configuration file for setupcon

# Change to "yes" and setupcon will explain what is being doing

# Setup these consoles.  Most people do not need to change this.

# Put here your encoding.  Valid charmaps are: UTF-8 ARMSCII-8 CP1251
# ISO-8859-1 ISO-8859-2 ISO-8859-3 ISO-8859-4 ISO-8859-5 ISO-8859-6
# ISO-8859-7 ISO-8859-8 ISO-8859-9 ISO-8859-10 ISO-8859-11 ISO-8859-13
# ISO-8859-14 ISO-8859-15 ISO-8859-16 KOI8-R KOI8-U TIS-620 VISCII

# The codeset determines which symbols are supported by the font.
# Valid codesets are: Arabic Armenian CyrAsia CyrKoi CyrSlav Ethiopian
# Georgian Greek Hebrew Lao Lat15 Lat2 Lat38 Lat7 Thai Uni1 Uni2 Uni3
# Vietnamese.  Read README.fonts for explanation.

# Valid font faces are: VGA (sizes 8, 14 and 16), Terminus (sizes
# 12x6, 14, 16, 20x10, 24x12, 28x14 and 32x16), TerminusBold (sizes
# 14, 16, 20x10, 24x12, 28x14 and 32x16), TerminusBoldVGA (sizes 14
# and 16), Fixed (sizes 13, 14, 15, 16 and 18), Goha (sizes 12, 14 and
# 16), GohaClassic (sizes 12, 14 and 16).

# You can also directly specify nonstandard font and ACM to load:
# FONT=/usr/local/share/funnyfonts/sarge16.psf
# ACM=/usr/local/share/consoletrans/my_special_encoding.acm

# The following variables describe your keyboard and can have the same
# values as the XkbModel, XkbLayout, XkbVariant and XkbOptions options
# in /etc/X11/xorg.conf.

# Do not update the following md5 sum if you change
# /etc/console-setup/boottime.kmap.gz and Debconf will not overwrite
# your custom keymap.  Do not update it even if you want to make
# Debconf overwrite it.  Instead simply specify the empty string as
# a md5 sum.

  • vi files/etc/default/locale/LANG_GERMAN

Paste the following lines:

  • vi files/etc/ntework/interfaces/NW_DHCP

Paste the following lines:

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet dhcp

The hooks directory:

  • vi hooks/savelog.LAST.source

Paste the following lines:

#! /bin/bash

# parse all log files for error messages
# print errors and warnings found to error.log
# WARNING: This will only work with english error messages!


# Define grep patterns. Do not start or end with an empty line!
no space
Couldn't stat
Cannot access
is bigger than the limit
did not exist
non existent
not found
E: Sorry, broken packages
operator expected
ambiguous redirect
No previous regular expression
No such
Device or resource busy
unknown option
No candidate version found
Couldn't find any package whose name or description matched
cannot create
The following packages have unmet dependencies"

:+ error=0
:+ trap error=
[RT]X packets:
WARNING: unexpected IO-APIC
warned about = ( )
Expect some cache
no error
RPC call returned error 101
(floppy), sector 0
mount version older than kernel
Can't locate module 
Warning only 896MB will be used.
hostname: Host name lookup failure
I can't tell the difference.
warning, not much extra random data, consider using the -rand option
Warning: 3 database(s) sources
were not found, (but were created)
removing exim
The home dir you specified already exists.
No Rule for /usr/lib/ispell/default.hash.
/usr/sbin/update-fonts-.\+: warning: absolute path
hostname: Unknown server error
EXT2-fs warning: checktime reached
RPC: sendmsg returned error 101
can't print them to stdout. Define these classes
warning: downgrading
suppress emacs errors
echo Error: 
Can't open dependencies file
documents in /usr/doc are no longer supported
if you have both a SCSI and an IDE CD-ROM
Warning: /proc/ide/hd?/settings interface is obsolete, and will be removed soon
Monitoring disabled
Error: only one processor found.
Error Recovery Strategy:
sector 0 does not have an
syslogin_perform_logout: logout() returned an error
grub is not in an XFS filesystem.
is harmless
not updating .\+ font directory data.
register_serial(): autoconfig failed
Fontconfig error: Cannot load default config file
asking for cache data failed
However, I can not read the target:
fai-kernels/modules.dep: No such file
Warning: The partition table looks like it was made
^info: Trying to set 
warning: /usr/lib/X11/fonts
can't read /etc/udev/rules.d/z25_persistent-net.rules
/cow': No such file or directory
Dummy start-stop-daemon called
cdrom: open failed."

# add pattern on some conditions
if [ -n $FAI_ALLOW_UNSIGNED ] ; then
WARNING: untrusted versions
Ignoring these trust violations"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Here you can define your own patterns. Put one pattern in a line,
# do not create empty lines.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# The main routine

cd $LOGDIR || exit 3
if [ -s $errfile ]; then
    echo "Errorfile already exists. Aborting."

grep -i "$errorpatterns" *.log | grep -vi "$ignorepatterns" > $errfile
if [ "$verbose" ]; then
    egrep -v '^software.log:' $errfile > $LOGDIR/tempfile
    mv $LOGDIR/tempfile $errfile

if [ -s $errfile ]; then
   echo "ERRORS found in log files. See $errfile"
   echo "Congratulations! No errors found in log files."
   export flag_reboot=1
  • vi hooks/updatebase.OS_UBUNTU_904_X32

Paste the following lines:

#! /bin/bash
# Import custom apt sources.list and apt keys.

echo "Preparing apt"
fcopy -v /etc/apt/secring.gpg
fcopy -v /etc/apt/sources.list
fcopy -v /etc/apt/trustdb.gpg
fcopy -v /etc/apt/trusted.gpg

# Initialize apt-key before apt is called the first time
if [ -x $target/usr/bin/apt-key ]; then
  echo "Apt: list of keys"
  $ROOTCMD /usr/bin/apt-key list

# Copy the console-setup file early to avoid unnecessary
# error messages
fcopy -v /etc/default/console-setup

The package_config directory:

  • vi package_config/BC_BASE

Paste the following lines:

PACKAGES aptitude
  • vi package_config/LANG_GERMAN

Paste the following lines:

PACKAGES aptitude
  • vi package_config/OS_UBUNTU_904_X32

Paste the following lines:

PACKAGES aptitude

The scripts directory:

  • vi scripts/BC_BASE/10-misc

Paste the following lines:

#! /bin/bash

# (c) Thomas Lange, 2001-2008, lange@debian.org

error=0 ; trap "error=$((error|1))" ERR

# a list of modules which are loaded at boot time
fcopy -i /etc/modules
for module in $MODULESLIST; do
    ainsl -a $target/etc/modules "^$module$"

fcopy /etc/hostname || echo $HOSTNAME     > $target/etc/hostname
echo $TIMEZONE    > $target/etc/timezone
ln -fs /usr/share/zoneinfo/${TIMEZONE} $target/etc/localtime

fcopy -iM /etc/hosts /etc/motd

# set root password
echo "root:$ROOTPW" | $ROOTCMD chpasswd --encrypted
# make /root accessible only by root
chmod 0700 $target/root
chown root:root $target/root
# copy default dotfiles for root account
fcopy -ir /root

exit $error
  • vi scripts/BC_BASE/20-fcopy

Paste the following lines:

#! /bin/bash

# Copy files from $FAI/files
fcopy -v /etc/network/interfaces
fcopy -v /etc/ssh_known_hosts
fcopy -v /etc/default/locale
  • vi scripts/GRUB/10-setup

Paste the following lines:

#! /bin/bash

error=0 ; trap "error=$((error|1))" ERR

# Eventual source the disk_var.sh just in case 
# variables are overwritten
[ -r /tmp/fai/disk_var.sh ] && . /tmp/fai/disk_var.sh


[ -z "$BOOT_DEVICE" ]    && exit 701
[ -z "$BOOT_PARTITION" ] && exit 702

# call grub-install from ubuntu
$target/usr/sbin/grub-install --no-floppy --root-directory=/$target $BOOT_DEVICE

# call update-grub inside ubuntu chroot with special "no user questions" flag
$ROOTCMD /usr/sbin/update-grub -y

exit $error
  • vi scripts/GRUB/20-initramfs

Paste the following lines:

#! /bin/bash

error=0 ; trap "error=$((error|1))" ERR

not_up2date() {
  if [ $# -eq 0 ] ; then
    echo "No package name given!"
    return 127

  egrep -q "(^Unpacking $1 |^Unpacking replacement $1 )" $LOGDIR/*.log
  return $?

if [ `not_up2date lvm2` -o `not_up2date mdadm` ] ; then
  $ROOTCMD update-initramfs -k all -u

exit $error
  • vi scripts/LAST/50-misc

Paste the following lines:

#! /bin/bash

# copyright Thomas Lange 2001-2007, lange@debian.org

error=0 ; trap "error=$((error|1))" ERR

# remove backup files from cfengine
dirs="root etc var"
for path in $dirs; do
    find $target/$path -maxdepth 20 -name \*.cfedited -o -name \*.cfsaved | xargs -r rm

[ "$FAI_DEBMIRROR" ] && 
echo "#$FAI_DEBMIRROR $MNTPOINT nfs ro 0 0" >> $target/etc/fstab

# set bios clock
if [ $do_init_tasks -eq 1 ] ; then
    case "$UTC" in
       no|"") hwopt="--localtime" ;;
       yes)   hwopt="--utc"       ;;
    $ROOTCMD hwclock $hwopt --systohc || true

# Make sure everything is configured properly
echo "Running \"apt-get -f install\" for the last time."
$ROOTCMD apt-get -f install

lskernels=$(echo $target/boot/vmlinu*)
[ -f ${lskernels%% *} ] || echo "ERROR: No kernel was installed. Have a look at shell.log"

exit $error

Whew! That was a lot of copy&pasting! After making the scripts executable by issuing

chmod -R 755 /srv/fai/config

it's time to create our distribution-specific base.tar.gz.

Create a custom base.tgz

For each distribution that you want to roll out with FAI, you have to create a separate base.tgz. This is the most critical part in order for FAI to go multi-distribution!

First off, you have to boot into the exact distribution with the exact same version that you want to roll out on your clients. If you want to roll out ubuntu 9.04, you have to boot into an ubuntu 9.04 environment.

Once you've booted to your selected distribution, switch to root first:

sudo su

and update the distribution to be sure you use the most up-to-date packages (you might want to edit the distributions /etc/apt/sources.list first to use your apt-proxy; see above):

apt-get update && apt-get -y upgrade

Now install pbuilder and debootstrap. You'll need these two for creating your base.tgz.

apt-get -y install pbuilder debootstrap

You have to modify these packages a bit. Open the file:

vi /etc/pbuilder/pbuilderrc

and change the following two lines (note that we'll use our apt-proxy):


Copy needed files from /etc/apt to your pBuilder-directory:

mkdir /etc/pbuilder/apt.config/
cp -ar /etc/apt/* /etc/pbuilder/apt.config/

It is important to make sure that the file 99update-notifier is not contained in the folder /etc/pbuilder/apt.config/apt.conf.d/. This file could complicate things later on. So do a:

rm /etc/pbuilder/apt.config/apt.conf.d/99update-notifier

Open this file:

vi /etc/pbuilder/apt.config/apt.conf.d/allow-unauthenticated

and add the following line:

APT::Get::AllowUnauthenticated 1;

With the following command the chroot-environment will be created:

pbuilder create

Time for another coffee.

Once finished, the base-image is created in /var/cache/pbuilder/base.tgz. This file has to be copied to the $FAI/config/basefiles/-dir we created above above, e.g.:

scp /var/cache/pbuilder/base.tgz root@

What happened here? Well, if you want to roll out multiple distributions with FAI, how does FAI know which distribution to apply to which client? The answer is simple: by applying a class. Say, you want to roll out Ubuntu 9.04 x32 and Debian Lenny x32. Then you could name your classes e.g. OS_UBUNTU_904_X32 and OS_DEBIAN_LENNY_X32 and apply them to your hosts in the 50-host-classes file. Upon installation, FAI looks for base.tgz files named OS_UBUNTU_904_X32.tar.gz and OS_DEBIAN_LENNY_X32.tar.gz See the connection? So a client with the class OS_UBUNTU_904_X32 will be served the base.tgz named OS_UBUNTU_904_X32.tar.gz. Thus, you have to rename your base.tgz-file to the name of your class (which is what we already did within the scp-command above).

The basic process should be the same for other distributions as well; that is, creating a base.tgz file with pbuilder and copy this file to $FAI/basefiles/OS_DEBIAN_LENNY_X64.tar.gz. Just make sure you specify and apply the needed classes.

Let's roll!

Tired eyes and many sore fingers later, we are finally finished!

All that is left to do is to tell FAI which clients should be used for installation. You do this with this command:

fai-chboot -IB

Where is the IP address of the target client. You can assign a client a specific IP by using its NIC's MAC address in the DHCP config. See the appropriate chapter in this howto for how it is done.

Should you experience problems at this point, e.g. the client not finding the TFTP server, restart the ubuntu server and try again. More than once, this worked wonders for me.

I recommend to use a test client for testing. If no physical client is available, you could use VirtualBox or any other virtualization product.

Now, when the target client is booted the next time, make sure it is set to boot from the network (either with a setting in its BIOS or by temporarily selecting a boot device if your client supports this). WARNING: All the client's data - that is, the whole hard disk - will be erased in the process! Make sure you are fully aware of the consequences!

If everything went well, once the client is installed, you can log in with username root' and password fai. Check the logs at /var/log/fai/vm-ubuntu904/last/error.log for any errors.

Congratulations! You've completed your first FAI install!

Thanks for reading!

Comments and feedback are always welcome (please see my profile for contact information), however, please direct any technical questions or comments to the mailinglist.