Ubuntu 16.04: Install PXE Boot server for thin client with NFS

This article will run PXE Boot server with NFS for thin client, and run Ubuntu 16.04 on client which is connected to PXE Boot server via network. You do not need to install Ubuntu 16.04 on client.

1 Install PXE Boot server

The following script will install PXE Boot server. Change the variables to your environment.

  • SERVER_IPADDR is IP adress of PXE Boot server.
  • DHCP_SERVER_INTERFACESv4 is network interface name for DHCP. DHCP will be provided via this network interface.
  • DHCP_SUBNET is network address for DHCP.
  • DHCP_NETMASK is subnet for DHCP.
  • DHCP_DNS is DNS for DHCP.
  • DHCP_ROUTER is gateway for DHCP.
  • DHCP_CLIENT_HOSTNAME is hostname of client.
  • DHCP_CLIENT_IPADDR is IP address of client.
  • DHCP_CLIENT_MACADDR is MAC address of client.

NFS root filesystem is set to the following.

  • root user password is not set. root user is locked.
  • Create user which name is "ubuntu" and password is "ubuntu".
  • Install unity package, ubuntu-desktop package and openssh-server package.
#!/bin/sh

set -e

# Change the following variable to yours.
[ -z "${SERVER_IPADDR}" ] && \
  SERVER_IPADDR=$(hostname -I | awk '{ print $1 }')
[ -z "${DHCP_SERVER_INTERFACESv4}" ] && DHCP_SERVER_INTERFACESv4=ens3
[ -z "${DHCP_SUBNET}" ] && DHCP_SUBNET=192.168.11.0
[ -z "${DHCP_NETMASK}" ] && DHCP_NETMASK=255.255.255.0
[ -z "${DHCP_DOMAIN}" ] && DHCP_DOMAIN=hiroom2.com
[ -z "${DHCP_DNS}" ] && DHCP_DNS="192.168.11.2, 192.168.11.1"
[ -z "${DHCP_ROUTER}" ] && DHCP_ROUTER=192.168.11.1
[ -z "${DHCP_CLIENT_HOSTNAME}" ] && \
  DHCP_CLIENT_HOSTNAME=ubuntu-1604-pxeboot-client
[ -z "${DHCP_CLIENT_IPADDR}" ] && DHCP_CLIENT_IPADDR=192.168.11.254
[ -z "${DHCP_CLIENT_MACADDR}" ] && DHCP_CLIENT_MACADDR=52:54:00:5e:7a:a4

tftpd_hpa_install()
{
  sudo apt install -y tftpd-hpa
  sudo systemctl enable tftpd-hpa
  sudo systemctl restart tftpd-hpa
}

isc_dhcp_server_install()
{
  sudo apt install -y isc-dhcp-server

  sudo sed -e 's/^#DHCPDv4_CONF=/DHCPDv4_CONF=/g' \
       -e 's/^#DHCPDv4_PID=/DHCPDv4_PID=/g' \
       -e "s/INTERFACESv4=\"\"/INTERFACESv4=\"${DHCP_SERVER_INTERFACESv4}\"/g" \
       -i /etc/default/isc-dhcp-server

  cat <<EOF | sudo tee /etc/dhcp/dhcpd.conf
subnet ${DHCP_SUBNET} netmask ${DHCP_NETMASK} {
  option domain-name "${DHCP_DOMAIN}";
  option domain-name-servers ${DHCP_DNS};
  option routers ${DHCP_ROUTER};
  next-server ${SERVER_IPADDR};
  filename "pxelinux.0";
}

host ${DHCP_CLIENT_HOSTNAME} {
  hardware ethernet ${DHCP_CLIENT_MACADDR};
  fixed-address ${DHCP_CLIENT_IPADDR};
}
EOF

  sudo systemctl restart isc-dhcp-server
}

nfs_kernel_server_install()
{
  # Set NFS server.
  sudo apt install -y nfs-kernel-server debootstrap systemd-container
  sudo mkdir /var/lib/nfsroot
  echo "/var/lib/nfsroot *(rw,sync,no_root_squash,no_subtree_check)" | \
    sudo tee /etc/exports
  sudo exportfs -ra

  # Create root filesystem.
  URL=$(grep "^deb .* xenial main" /etc/apt/sources.list | awk '{ print $2 }')
  sudo debootstrap xenial /var/lib/nfsroot "${URL}"

  # Get debconf from server for locale and keyboard.
  sudo apt install -y debconf-utils systemd-container
  sudo debconf-get-selections | grep locale | \
    sudo tee /var/lib/nfsroot/debconf.txt
  sudo debconf-get-selections | grep keyboard-configuration | \
    sudo tee -a /var/lib/nfsroot/debconf.txt
  sudo cp /etc/locale* /var/lib/nfsroot/etc/
  sudo cp /etc/default/locale /var/lib/nfsroot/etc/default/

  # resolv.conf is not updated by systemd-nspawn.
  sudo cp /etc/resolv.conf /var/lib/nfsroot/etc/resolv.conf.server

  sudo systemd-nspawn -D /var/lib/nfsroot sh -c "
set -e

# Use server resolv.conf.
rm -f /etc/resolv.conf
mv /etc/resolv.conf.server /etc/resolv.conf

apt update -y
apt upgrade -y

# Set debconf to client for locale and keyboard.
cat debconf.txt | debconf-set-selections
apt install --reinstall -y locales keyboard-configuration
rm -f debconf.txt

# Install kernel and create initrd.
apt install -y initramfs-tools linux-image-generic
cat <<EOF > /etc/initramfs-tools/initramfs.conf
MODULES=netboot
BUSYBOX=auto
KEYMAP=n
COMPRESS=gzip
DEVICE=
NFSROOT=${SERVER_IPADDR}:/var/lib/nfsroot
BOOT=nfs
EOF
update-initramfs -tu

# Install Unity and OpenSSH server.
apt install -y ubuntu-desktop unity openssh-server

# Set root password and create user.
useradd -m -s /bin/bash ubuntu
yes ubuntu | passwd ubuntu
gpasswd -a ubuntu sudo

# systemd needs /etc/fstab entry too while using nfsroot.
echo '${SERVER_IPADDR}:/var/lib/nfsroot / nfs defaults 0 0' > /etc/fstab

sudo sed -e 's/^dns=dnsmasq/#dns=dnsmasq/g' \
     -i /etc/NetworkManager/NetworkManager.conf

# Generate /etc/resolv.conf with dhclient.
rm -f /etc/resolv.conf
ln -s /run/resolvconf/resolv.conf /etc/resolv.conf
echo dhclient > /etc/rc.local
"
}

pxelinux_install()
{
  cd /var/lib/tftpboot

  sudo apt install -y pxelinux syslinux
  sudo cp -a /usr/lib/syslinux/modules/bios .
  sudo cp /usr/lib/PXELINUX/pxelinux.0 .
  sudo cp /usr/lib/syslinux/modules/bios/ldlinux.c32 .
  sudo cp /var/lib/nfsroot/vmlinuz .
  sudo chmod 744 vmlinuz
  sudo cp /var/lib/nfsroot/initrd.img .
  sudo chmod 744 initrd.img

  sudo mkdir pxelinux.cfg
  cat <<EOF | sudo tee pxelinux.cfg/default
path bios
include menu.cfg
default bios/vesamenu.c32
prompt 0
timeout 10
EOF

  cat <<EOF | sudo tee menu.cfg
menu hshift 13
menu width 49
menu margin 8
menu tabmsg

menu title Thin client boot menu
label ubuntu-1604-thin-client
  menu label ^Ubuntu 16.04 thin client
  kernel vmlinuz
  append vga=788 initrd=initrd.img ip=dhcp nfsroot=${SERVER_IPADDR}:/var/lib/nfsroot rw
menu end
EOF
}

pxeboot_main()
{
  tftpd_hpa_install
  isc_dhcp_server_install
  nfs_kernel_server_install
  pxelinux_install
}

pxeboot_main

2 Run Ubuntu 16.04 thin client with NFS

This article runs Ubuntu 16.04 thin client on virtual machine on KVM. Virtual machine on VirtualBox and real machine too can run Ubuntu 16.04

thin client with enabling network boot. Please check your BIOS setting.

Enable "NIC" of "Boot device order" and make it top of order with virt-manager.

0001_BootDeviceOrder.png

iPXE sends DHCP requests, receives DHCP response from PXE Boot server, download and run boot image.

0002_iPXE.png

syslinux's menu is displayed. After 1 second, "Ubuntu 16.04 thin client" will be selected automatically.

0003_syslinux.png

Ubuntu 16.04 thin client is started.

0004_BootUbuntu.png

Login is displayed.

0005_Login.png