====== Diskless PXE boot on NFS root ======
When you have a whole rack of machines and don't want to install and manage separate OS installs on all of them, setting up to boot via PXE with a shared NFS root can be a major time-saver. Here are some notes on how to set up both a host machine to act as the DHCP, TFTP, and NFS server, as well as how to set up the PXE-booted image. In this configuration, the control server will also act as a gateway machine for the PXE booted hosts.
===== Control host =====
Set up ubuntu as a net boot source (for ubuntu) (ref: [[https://help.ubuntu.com/community/DisklessUbuntuHowto]])
Install ubuntu
Install necessary packages
# apt install isc-dhcp-server tftpd-hpa pxelinux nfs-kernel-server debootstrap
Configure network interface (ref: [[https://help.ubuntu.com/lts/serverguide/network-configuration.html.en]]). In this case, eno1 is the external interface (facing the internet) and eno2 is the internal interface (facing the PXE booted hosts).
Edit ''/etc/netplan/99_config.yaml''
network:
version: 2
renderer: networkd
ethernets:
eno1:
dhcp4: true
eno2:
addresses:
- 10.144.0.1/16
Configure DHCP (ref: [[https://help.ubuntu.com/community/isc-dhcp-server]])
Edit ''/etc/dhcp/dhcpd.conf''
option domain-name "your-domain-name";
option domain-name-servers 8.8.8.8, 9.9.9.9;
default-lease-time 600;
max-lease-time 7200;
subnet 10.144.0.0 netmask 255.255.0.0 {
option routers 10.144.0.1;
option broadcast-address 10.144.255.255;
option ntp-servers 1.2.3.4;
}
include "/etc/dhcp/reactor-host-dhcp.conf";
include "/etc/dhcp/reactor-ilo-dhcp.conf";
Edit ''/etc/dhcp/reactor-host-dhcp.conf''
host reactor0 {
hardware ethernet de:ad:be:ef:ca:fe;
fixed-address 10.144.0.100;
option host-name "reactor0";
filename "/pxelinux.0";
next-server 10.144.0.1;
}
# etc.
Edit ''/etc/dhcp/reactor-ilo-dhcp.conf''
host reactor0-mgt {
hardware ethernet de:ad:be:ef:ca:fe;
fixed-address 10.144.1.100;
option host-name "reactor0-mgt";
}
# etc.
Edit ''/etc/default/isc-dhcp-server''
INTERFACESv4="eno2"
Start DHCP server
Run ''systemctl enable --now isc-dhcp-server''
Configure TFTP
Should be good to go already once tftpd-hpa is installed
Configure PXE
# mkdir /srv/nfs/ubuntu
# cd /var/lib/tftpboot
# mkdir pxelinux.cfg boot
# cp /usr/lib/PXELINUX/pxelinux.0 /var/lib/tftpboot
# cp -r /usr/lib/syslinux/modules/bios /var/lib/tftpboot/boot/isolinux
Edit ''/var/lib/tftpboot/pxelinux.cfg/default''
SERIAL 1 115200
UI menu.c32
TIMEOUT 100
ONTIMEOUT linux
LABEL linux
MENU LABEL Ubuntu Linux
KERNEL ubuntu/vmlinuz
APPEND root=/dev/nfs initrd=ubuntu/initrd.img nfsroot=10.144.0.1:/srv/nfs/ubuntu ip=dhcp rw console=ttyS1 console=tty0
LABEL memtest
MENU LABEL Memtest86+
KERNEL memtest
LABEL memtest-console
MENU LABEL Memtest86+ (serial console)
KERNEL memtest
APPEND console=ttyS1,115200n8
# mkdir ubuntu
# mount --bind /srv/nfs/ubuntu ubuntu
Edit ''/etc/fstab'' to append
# tftp doesn't follow symlinks
/srv/nfs/ubuntu /var/lib/tftpboot/ubuntu none bind 0 0
Configure NFS
(ref:[[ https://help.ubuntu.com/community/SettingUpNFSHowTo]])
Export install and required mounts
Edit ''/etc/exports''
/home 10.144.0.0/24(rw,no_root_squash,async,insecure)
/opt 10.144.0.0/24(rw,no_root_squash,async,insecure)
/srv/nfs/ubuntu 10.144.0.0/24(rw,no_root_squash,async,insecure)
Run ''exportfs -rv''
===== Client hosts =====
Install ubuntu for net boot clients (ref: [[https://help.ubuntu.com/community/Installation/OnNFSDrive]])
# mkdir /srv/nfs
# cd /srv/nfs
Edit ''run_debootstrap.sh''
#!/bin/sh
debootstrap --arch amd64 bionic /srv/nfs/ubuntu/ http://archive.ubuntu.com/ubuntu
Run ''bash run_debootstrap.sh''
Do not set /srv/nfs/ubuntu/etc/hostname, hostname will come from DHCP
# mount --bind /proc ubuntu/proc
# chroot ubuntu
Set up locales
Edit ''/etc/locale.gen'', uncomment locale (en_US.UTF-8)
Run ''locale-gen''
Install kernel, nfs-common, and SSH server
Do not install grub if prompted to do so
# apt install linux-image-generic nfs-common openssh-server
# chmod a+r /boot/vmlinuz*
# systemctl enable ssh
Enable serial console by running ''systemctl enable getty@ttyS1''
Set up fstab
Edit ''/etc/fstab''
# /etc/fstab: static file system information.
#
#
proc /proc proc defaults 0 0
/dev/nfs / nfs defaults 1 1
none /tmp tmpfs defaults 0 0
none /var/tmp tmpfs defaults 0 0
10.144.0.1:/home /home nfs defaults 0 0
10.144.0.1:/opt /opt nfs defaults 0 0
Workaround for unreadable kernel image
Edit ''/etc/kernel/postinst.d/chmod-vmlinuz''
#!/bin/sh -e
chmod 0644 /boot/vmlinuz-*
Run ''chmod a+x /etc/kernel/postinst.d/chmod-vmlinuz''
Edit initramfs settings for NFS boot
Edit ''/etc/initramfs-tools/initramfs.conf''
MODULES=netboot
Regenerate initramfs by running ''update-initramfs -u''
Set root password and/or add users, install packages, etc. Then:
# exit
# umount ubuntu/proc
At this point, it should be possible to boot a system over the network.
===== NAT configuration =====
(ref: [[https://help.ubuntu.com/lts/serverguide/firewall.html#ip-masquerading]])
Note: make sure console is accessable over iLO just in case networking gets broken
Edit ''/etc/default/ufw''
DEFAULT_FORWARD_POLICY="ACCEPT"
Edit ''/etc/ufw/sysctl.conf''
net/ipv4/ip_forward=1
Edit ''/etc/ufw/before.rules''
[place immediately after header comment]
# nat Table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Forward traffic from eno2 through eno1.
-A POSTROUTING -s 10.144.0.0/16 -o eno1 -j MASQUERADE
# don't delete the 'COMMIT' line or these nat table rules won't be processed
COMMIT
# ufw allow ssh
# ufw allow in on eno2
# ufw enable