Table of Contents
Introduction
PXE Boot Server (Preboot Execution Environment) or we can call it as Network Boot installation.
Let’s walk through a simple guide to make our life easier while installing and configuring a huge number of Linux servers. It can be physical or virtual, all the installation process can be automated by hitting a single key (F12, F11 or F10) from your keyboard.
To have a working PXE environment first we should need a DHCP, TFTP, FTP or HTTP server. In our guide, we will stick with HTTP. Once our PXE Boot Server is ready it will push the boot loader files into Linux clients by assigning random IP or a static IP, Then the kickstart file will be read by the installer and remaining installation process will be automated. Thus the PXE will help us to perform an unattended Operating System installation on massive numbers of Virtual or Physical servers.
The below guide will work on RHEL 8, CentOS 8 and Oracle Linux 8 as well.
Our Server Setup
The server specification we are using is
1 vCPU
2 GB minimum Memory
40 GB minimum disk space
1 Interface (NIC)
The base operating System we are using in our PXE boot server is CentOS 8.2 Linux.
[root@pxe ~]# cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
[root@pxe ~]#
The IP address used for PXE Boot Server is 192.168.0.51 resolving to pxe.linuxsysadmins.local
Publishing Repo Content
This is a separate filesystem created on top of a logical volume. If you are looking to set up one using Logical volume have a look into LVM guide.
[root@pxe ~]# df -hP /webdata/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg_webdata-lv_webdata 40G 2.0G 38G 5% /webdata
[root@pxe ~]#
If you don’t need a LVM setup just create a directory to copy our Installation media files.
# mkdir /webdata
Restore the SELinux context for newly created directory.
[root@pxe ~]# restorecon -Rv /webdata/
Relabeled /webdata from system_u:object_r:unlabeled_t:s0 to system_u:object_r:default_t:s0
[root@pxe ~]#
Set the web server context for the newly created directory
# semanage fcontext -a -t httpd_sys_content_t "/webdata(/.*)?"
Once again restore the context to verify whether the Web server context in place.
[root@pxe ~]# restorecon -Rv /webdata/
Relabeled /webdata from system_u:object_r:default_t:s0 to system_u:object_r:httpd_sys_content_t:s0
[root@pxe ~]#
Install Apache Web Server
Install apache web server to distribute the installation files.
# dnf install httpd -y
We should get similar to below at the end of the installation.
Installed:
httpd-2.4.37-21.module_el8.2.0+494+1df74eae.x86_64
apr-util-bdb-1.6.1-6.el8.x86_64
apr-util-openssl-1.6.1-6.el8.x86_64
apr-1.6.3-9.el8.x86_64
apr-util-1.6.1-6.el8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+494+1df74eae.noarch
httpd-tools-2.4.37-21.module_el8.2.0+494+1df74eae.x86_64
mod_http2-1.11.3-3.module_el8.2.0+486+c01050f0.1.x86_64
centos-logos-httpd-80.5-2.el8.noarch
mailcap-2.1.48-3.el8.noarch
Complete!
[root@pxe ~]#
Enable the service to start persistently.
# systemctl enable httpd
Allow http traffic by running firewalld command.
# firewall-cmd --add-service=http --permanent
# firewall-cmd --reload
Make sure to reload the firewalld.
Configure Apache Web Server
Create a custom apache Virtual Host entry for installation content.
Disable the Apache Welcome Page.
# mv /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/welcome.conf_backup
By following, copy the sample virtual host entry and do the required changes.
# cp /usr/share/doc/httpd/httpd-vhosts.conf /etc/httpd/conf.d/pxe.conf
Edit with anyone of your favorite editor.
# vim /etc/httpd/conf.d/pxe.conf
The finalized virtual host entry for our setup is below.
<VirtualHost *:80> ServerAdmin admin@linuxsysadmins.local DocumentRoot /webdata/ ServerName pxe.linuxsysadmins.local ServerAlias pxe ErrorLog "/var/log/httpd/pxe-error_log" CustomLog "/var/log/httpd/pxe-access_log" common <Directory /webdata/> Options +Indexes AllowOverride None Require all granted </Directory> </VirtualHost>
Finally, Restart the apache service.
# systemctl restart httpd
# systemctl status httpd
Copying Installation Media
In my case, My PXE server setup in on a virtual machine, so I have a CentOS 8.2 ISO file attached to the PXE Virtual machine.
# mount /dev/sr0 /mnt
In future, I have an idea to add more OS in PXE boot, so let me create a separate directory for CentOS 8 and copy the content to it.
# mkdir /webdata/centos8
# rsync -avz --progress /mnt/* /webdata/centos8/
Now you should able to browse the files from anyone of web browser.
Create a KickStart file
To avoid manual intervention while performing the installation, we have come up with the unattended method of installation. To do so, we are about to use the kickstart file. It will automate the installation process by reading the kickstart file.
Let’s create a separate directory to store our kick start file under /webdata`
# mkdir /webdata/ks_files
Create the kickstart file or use the existing one from any server, it can be found under the /root. I have copied an existing kickstart file from the PXE server and modified to match my requirement.
# cat /root/anaconda-ks.cfg > /webdata/ks_files/centos8-ks.cfg
#version=RHEL8
ignoredisk --only-use=sda
autopart --type=lvm
# Partition clearing information
clearpart --all --initlabel
zerombr
# Use graphical install
graphical
# Use Network installation method
url --url="http://pxe.linuxsysadmins.local/centos8/BaseOS"
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8
# Network information
network --bootproto=dhcp
network --hostname=localhost.localdomain
# Root password
rootpw --iscrypted $6$x2KEcFpCRhtXlXeL$fc.Q8qqD7rLNiF.ocm/esbZAIXlevNujQskP4hzcPhtL0
# Run the Setup Agent on first boot
firstboot --enable
# Do not configure the X Window System
skipx
# System services
services --disabled="chronyd"
# System timezone
timezone Asia/Dubai --isUtc --nontp
user --groups=wheel --name=sysadmins --password=$6$WS5ANJJ57zt/ --iscrypted --gecos="sysadmins"
%packages
@^minimal-environment
kexec-tools
%end
%addon com_redhat_kdump --enable --reserve-mb='160M'
%end
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
reboot
Now try to access the kickstart file from anyone of the web browser to make sure you are able to read the file.
http://pxe.linuxsysadmins.local
Get into the ks_file
directory and click the centos8-ks.cfg
file. If you get any forbidden error or permission issue then you might done some misconfiguration in your apache Virtual host entry.
http://pxe.linuxsysadmins.local/ks_files/centos8-ks.cfg
We have done with the kickstart file part.
Install DHCP Server
Let’s start with installing and configuring DHCP server.
# dnf install dhcp-server -y
Upgraded:
bind-export-libs-32:9.11.13-6.el8_2.1.x86_64
dhcp-client-12:4.3.6-40.el8.x86_64
dhcp-common-12:4.3.6-40.el8.noarch
dhcp-libs-12:4.3.6-40.el8.x86_64
Installed:
dhcp-server-12:4.3.6-40.el8.x86_64
Complete!
[root@pxe ~]#
Exclude DHCP traffic by allowing through firewall.
# firewall-cmd --add-service=dhcp --permanent
# firewall-cmd --reload
Configure DHCP Server
Configure DHCP for PXE Boot Server, The sample config files can be found under /usr/share/doc/dhcp-server/
copy the sample file and make the necessary changes.
# cp /usr/share/doc/dhcp-server/dhcpd.conf.example /etc/dhcp/dhcpd.conf
Use anyone of your favorite editor
# vi /etc/dhcp/dhcpd.conf
Change the values for your setup. You need to have a Valid DNS server, if you don’t have an existing DNS follow this guide to setup one.
Setup an Identity Management server in Linux using IPA
I have few of Physical nodes in my home lab, so let me put those MAC address to get the static IP for them. Remaining virtual machines will get a random IP from the defined DHCP range.
# dhcpd.conf
# option definitions common to all supported networks...
option domain-name "linuxsysadmins.local";
option domain-name-servers idm1.linuxsysadmins.local, idm2.linuxsysadmins.local;
default-lease-time 600;
max-lease-time 7200;
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
# PXE configs
option space pxelinux;
option pxelinux.magic code 208 = string;
option pxelinux.configfile code 209 = text;
option pxelinux.pathprefix code 210 = text;
option pxelinux.reboottime code 211 = unsigned integer 32;
option architecture-type code 93 = unsigned integer 16;
# This declaration allows BOOTP clients to get dynamic addresses,
subnet 192.168.0.0 netmask 255.255.255.0 {
range dynamic-bootp 192.168.0.200 192.168.0.254;
option broadcast-address 192.168.0.255;
option routers 192.168.0.1;
}
# Static IP for clients
host pve2 {
option host-name "pve2.linuxsysadmins.local";
hardware ethernet 1C:55:6A:60:12:57;
fixed-address 192.168.0.12;
filename "pxelinux.0";
}
host pve3 {
option host-name "pve3.linuxsysadmins.local";
hardware ethernet 1C:49:6A:60:6H:75;
fixed-address 192.168.0.13;
filename "pxelinux.0";
}
host pve4 {
option host-name "pve4.linuxsysadmins.local";
hardware ethernet 1C:49:7H:60:R4:9B;
fixed-address 192.168.0.14;
filename "pxelinux.0";
}
# You can declare a class of clients and then do address allocation
# based on that. The example below shows a case where all clients
# in a certain class get addresses on the 10.17.224/24 subnet, and all
# other clients get addresses on the 10.0.29/24 subnet.
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
# PXE server hostname or IP
next-server pxe.linuxsysadmins.local;
if option architecture-type = 00:07 {
filename "BOOTX64.EFI";
}
else {
filename "pxelinux.0";
}
}
#### ----End of Config---- ####
Once we have a DNS and DHCP the IP assignment will be handled by DHCP and the hostname will be resolved from the DNS server.
Enable the DHCPD service persistently to start during the reboot, then start the service.
# systemctl enable dhcpd
# systemctl start dhcpd
We have done with the DHCP part.
Install TFTP Server
Let’s start to install the required packages for TFTP server setup.
# dnf install tftp-server -y
Running transaction
Preparing : 1/1
Installing : tftp-server-5.2-24.el8.x86_64 1/1
Running scriptlet: tftp-server-5.2-24.el8.x86_64 1/1
Verifying : tftp-server-5.2-24.el8.x86_64 1/1
Installed:
tftp-server-5.2-24.el8.x86_64
Complete!
[root@pxe ~]#
Right after installing the TFTP we need to start with configuring PXE boot.
Configure PXE
The first steps is to install the syslinux package, this is a suite of bootloaders.
# dnf install syslinux -y
Running transaction
Preparing : 1/1
Installing : mtools-4.0.18-14.el8.x86_64 1/3
Running scriptlet: mtools-4.0.18-14.el8.x86_64 1/3
Installing : syslinux-nonlinux-6.04-4.el8.noarch 2/3
Installing : syslinux-6.04-4.el8.x86_64 3/3
Running scriptlet: syslinux-6.04-4.el8.x86_64 3/3
Verifying : mtools-4.0.18-14.el8.x86_64 1/3
Verifying : syslinux-6.04-4.el8.x86_64 2/3
Verifying : syslinux-nonlinux-6.04-4.el8.noarch 3/3
Installed:
syslinux-6.04-4.el8.x86_64
mtools-4.0.18-14.el8.x86_64
syslinux-nonlinux-6.04-4.el8.noarch
Complete!
[root@pxe ~]#
Once we install the syslinux package we will get the boot image file pxelinux.0, copy it under the /var/lib/tftpboot
# cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/
Create a separate directory for CentOS 8 under the tftp home directory
# mkdir /var/lib/tftpboot/centos8
Copy the required file from mounted ISO file to newly created centos8 directory
# cp -v /mnt/images/pxeboot/{vmlinuz,initrd.img} /var/lib/tftpboot/centos8/
[root@pxe ~]# ls -lthr /var/lib/tftpboot/centos8/
total 71M
-r-xr-xr-x. 1 root root 8.6M Nov 20 10:14 vmlinuz
-r--r--r--. 1 root root 63M Nov 20 10:14 initrd.img
[root@pxe ~]#
Copy the menu files generated by syslinux package to tftpboot home directory
# cp -v /usr/share/syslinux/{menu.c32,vesamenu.c32,ldlinux.c32,libcom32.c32,libutil.c32} /var/lib/tftpboot/
[root@pxe ~]# cp -v /usr/share/syslinux/{menu.c32,vesamenu.c32,ldlinux.c32,libcom32.c32,libutil.c32} /var/lib/tftpboot/
'/usr/share/syslinux/menu.c32' -> '/var/lib/tftpboot/menu.c32'
'/usr/share/syslinux/vesamenu.c32' -> '/var/lib/tftpboot/vesamenu.c32'
'/usr/share/syslinux/ldlinux.c32' -> '/var/lib/tftpboot/ldlinux.c32'
'/usr/share/syslinux/libcom32.c32' -> '/var/lib/tftpboot/libcom32.c32'
'/usr/share/syslinux/libutil.c32' -> '/var/lib/tftpboot/libutil.c32'
[root@pxe ~]#
Create the boot menu
# mkdir /var/lib/tftpboot/pxelinux.cfg
# vim /var/lib/tftpboot/pxelinux.cfg/default
Append menu content to /var/lib/tftpboot/pxelinux.cfg/default
file.
default vesamenu.c32
prompt 1
timeout 60
display boot.msg
label linux
menu label ^Install CentOS 8 in Graphical Mode
menu default
kernel centos8/vmlinuz
append initrd=centos8/initrd.img ip=dhcp inst.repo=http://pxe.linuxsysadmins.local/centos8 ks=http://pxe.linuxsysadmins.local/ks_files/centos8-ks.cfg
label vesa
menu label Install CentOS 8 with ^basic video driver
kernel centos8/vmlinuz
append initrd=centos8/initrd.img ip=dhcp inst.xdriver=vesa nomodeset inst.repo=http://pxe.linuxsysadmins.local/centos8 ks=http://pxe.linuxsysadmins.local/ks_files/centos8-ks.cfg
label rescue
menu label ^Rescue installed system
kernel centos8/vmlinuz
append initrd=centos8/initrd.img rescue
label local
menu label Boot from ^local drive
localboot 0xffff
We are almost done with all the setup, now allow the TFTP traffic.
# firewall-cmd --add-service=tftp --permanent
# firewall-cmd --reload
Finally, Start the service and enable persistently to start during the reboots.
# systemctl enable tftp.service
# systemctl start tftp.service
# systemctl status tftp.service
Starting with PXE Boot
Before installing my Physical node, Let me use my Physical node’s MAC address on one of the Virtual machines to test the PXE boot functionality.
Change the boot order to network and PowerON the Virtual machine, We should see as shown below.
By following it will show the menu to choose or installation will automatically starts in few seconds.
Using my Physical Node’s MAC works, Now let me try with a new Virtual machine.
Testing with Virtual Machine
Define a new static IP/Hostname and MAC in “/etc/dhcp/dhcpd.conf
” for testing purpose.
host pxetest {
option host-name "pxetest.linuxsysadmins.local";
hardware ethernet 1C:69:7D:11:22:33;
fixed-address 192.168.0.222;
filename "pxelinux.0";
}
Restart the DHCP service by running # systemctl restart dhcpd
The DNS record (pxetest) has been created on my IDM server as well.
Then, PowerOn the Virtual Machine. In the meantime, log in to the PXE Boot Server and check the DHCP logs to know how the IP is offered.
[root@pxe ~]# journalctl -f _SYSTEMD_UNIT=dhcpd.service
-- Logs begin at Mon 2020-11-23 00:55:00 +04. --
Nov 23 20:52:55 pxe.linuxsysadmins.local dhcpd[6124]: DHCPDISCOVER from 1c:69:7d:11:22:33 via ens18
Nov 23 20:52:55 pxe.linuxsysadmins.local dhcpd[6124]: DHCPOFFER on 192.168.0.222 to 1c:69:7d:11:22:33 via ens18
No v 23 20:52:56 pxe.linuxsysadmins.local dhcpd[6124]: DHCPDISCOVER from 1c:69:7d:11:22:33 via ens18
Nov 23 20:52:56 pxe.linuxsysadmins.local dhcpd[6124]: DHCPOFFER on 192.168.0.222 to 1c:69:7d:11:22:33 via ens18
Nov 23 20:52:58 pxe.linuxsysadmins.local dhcpd[6124]: DHCPREQUEST for 192.168.0.222 (192.168.0.51) from 1c:69:7d:11:22:33 via ens18
Nov 23 20:52:58 pxe.linuxsysadmins.local dhcpd[6124]: DHCPACK on 192.168.0.222 to 1c:69:7d:11:22:33 via ens18
Nov 23 20:53:28 pxe.linuxsysadmins.local dhcpd[6124]: DHCPDISCOVER from 1c:69:7d:11:22:33 via ens18
Nov 23 20:53:28 pxe.linuxsysadmins.local dhcpd[6124]: DHCPOFFER on 192.168.0.222 to 1c:69:7d:11:22:33 via ens18
[root@pxe ~]#
If you need to know how the TFTP works, run the tail -f
command on the /var/log/messages
logfile in our PXE Boot Server, we could see what are the files are transferred to the clients.
[root@pxe ~]# tail -f /var/log/messages
Nov 23 20:52:58 pxe systemd[1]: Started Tftp Server.
Nov 23 20:52:58 pxe in.tftpd[6176]: Client ::ffff:192.168.0.222 finished pxelinux.0
Nov 23 20:52:58 pxe in.tftpd[6177]: Client ::ffff:192.168.0.222 finished ldlinux.c32
Nov 23 20:52:58 pxe in.tftpd[6188]: Client ::ffff:192.168.0.222 finished pxelinux.cfg/default
Nov 23 20:53:04 pxe in.tftpd[6190]: Client ::ffff:192.168.0.222 finished vesamenu.c32
Nov 23 20:53:04 pxe in.tftpd[6191]: Client ::ffff:192.168.0.222 finished libcom32.c32
Nov 23 20:53:04 pxe in.tftpd[6192]: Client ::ffff:192.168.0.222 finished libutil.c32
Nov 23 20:53:04 pxe in.tftpd[6193]: Client ::ffff:192.168.0.222 finished pxelinux.cfg/default
Nov 23 20:53:11 pxe in.tftpd[6194]: Client ::ffff:192.168.0.222 finished centos8/vmlinuz
Nov 23 20:53:18 pxe in.tftpd[6195]: Client ::ffff:192.168.0.222 finished centos8/initrd.img
Watch PXE Boot Server in action
This is the VM just now installed with the help of PXE boot Server.
That’s it, we have completed with the PXE boot server setup.
Conclusion
PXE Boot Server with kickstart will help us to automate the Operating system installation without manual interactions. Similarly, we have few other tools which will help to re-image the servers, will come up with another guide in future. Subscribe to our newsletter to get our regular updates, Feedbacks are welcome through below comment section.
Thank you so much for this great and indeed easy tutorial!!!
I have struggled so many nights with all kinds of errors and this just takes all of them awaY!
Best regards.