Just wanna to make a note since my previous articles are missing.
    In the very first, we have to make sure that DHCP server is setup. In this part, we'll focus on the Legay mode.
    There're some services that we need to setup: DHCP, TFTP and HTTP services.

DHCP service(IPv4)

    In legacy mode, PXE only support the IPv4, IPv6 only support UEFI mode.
    The main setup file is /etc/dhcp/dhcpd.conf:
# dhcpd.conf
#
# Sample configuration file for ISC dhcpd
#

# option definitions common to all supported networks...
#option domain-name-servers ns1.example.org, ns2.example.org;

allow bootp;
allow booting;
default-lease-time 259200;
max-lease-time 518400;
option routers  192.168.100.1;
option broadcast-address 192.168.100.255;
option domain-name-servers      8.8.8.8, 8.8.4.4;
#######  Add Para. for UEFI boot ##########
option space PXE;
option PXE.mtftp-ip     code 1 = ip-address;
option PXE.mtftp-cport  code 2 = unsigned integer 16;
option PXE.mtftp-sport  code 3 = unsigned integer 16;
option PXE.mtftp-tmout  code 4 = unsigned integer 8;
option PXE.mtftp-delay  code 5 = unsigned integer 8;
option arch code 93 = unsigned integer 16; #RFC4570
###########################################

# Use this to enble / disable dynamic dns updates globally.
#ddns-update-style none;

# 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;
subnet 192.168.100.0 netmask 255.255.255.0 {
        range 192.168.100.10 192.168.100.100;
}
class   "pxeclients"    {
        match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
        next-server     192.168.100.1;

        if option arch = 00:07 {
                filename "shimx64.efi";  ## This is for UEFI PXE
                } else {
                filename "pxelinux.0";   ## It's for legacy PXE
        }
}

TFTP service(Legacy)

    We need to copy some files to the default folder of TFTP service (/var/lib/tftpboot, make sure all tftp-related packages are installed):
cp /usr/share/syslinux/{gfxboot.c32,ldlinux.c32,libutil.c32,menu.c32,chain.c32, libcom32.c32,mboot.c32, pxelinux.0,vesamenu.c32}  /var/lib/tftpboot

Then, we'll create a boot menu file in /var/lib/tftpboot/pxelinux.cfg/, file name is "default" (if pxelinux.cfg doesn't exist, create it):
UI vesamenu.c32
TIMEOUT 100
DEFAULT 1
MENU TITLE Welcom to PXE Server System
MENU RESOLUTION 1024 768
MENU BACKGROUND flw.jpg

# Boot to the local disk
LABEL 1
  MENU LABEL Boot from local drive
  LOCALBOOT 0

# Install Ubuntu server 1804 manually
LABEL 2
  MENU LABEL Install Ubuntu Server 18.04 
  kernel images/ub1804srv/linux
  append initrd=images/ub1804srv/initrd.gz method=http://192.168.100.1/ub1804srv/ live-installer/net-image=http://192.168.100.1/ub1804srv/install/filesystem.squashfs
# Install CentOS 8 kickstart
LABEL 3
  MENU LABEL Install CentOS 8 kickstart
  kernel images/c8os/vmlinuz
  append initrd=images/c8os/initrd.img inst.repo=http://192.168.100.1/c8os ks=http://192.168.100.1/cfgfiles/c8lite.cfg
# Install CentOS manually
LABEL 4
  MENU LABEL Install CentOS 8 manual
  kernel images/c8os/vmlinuz
  append initrd=images/c8os/initrd.img inst.repo=http://192.168.100.1/c8os

The main core setup is that we have to make sure the basic file (linux && initrd.gz in debian system, vmlinuz && initrd.img in Red Hat system) are put in the correct place. Next we'll setup the actual installation file and start the HTTP service.

Installation source/HTTP service

    Take CentOS 8 for example, 1st we mount the CentOS 8 installation image and copy all files in the image to a target folder, e.g., we create a folder called "c8os/" under /var/www/html/:
cp * /var/www/html/c8os/.
Then, we'll copy the file from the source image file to /var/lib/tftpboot/images, and create a folder called "c8os" under the "images/" folder:
cp /var/www/html/c8os/isolinux/{vmlinuz, initrd.img} /var/lib/tftpboot/images/c8os
Enable the http service directly since we've put the installation file under the /var/www/html/ folder.
Booting the client host, the PXE boot image would look like:
Right now we could start installation manually, to perform automated installation, we also need kickstart file and seed file (for debian-like distribution).
    Next, we'll show the automated installation -- kickstart and seed file(for debian-like distribution).

Kickstart && seed files

    Below is the basic configuration of the kickstart file:
#Generated by Kickstart Configurator
#platform=x86

#System language
lang en_US
#Language modules to install
langsupport en_US
#System keyboard
keyboard us
#System mouse
mouse
#System timezone
timezone Asia/Taipei
#Root password
rootpw --disabled
# Create a sudo user
user balajan --fullname "balajan" --plaintext --password balajan --groups=sudo
#Reboot after installation
reboot
#Use text mode install
text
#Install OS instead of upgrade
install
#Use Web installation
url --url http://192.168.122.1/ub1804srv/
#System bootloader configuration
bootloader --location=mbr 
#Clear the Master Boot Record
zerombr yes
#Partition clearing information
clearpart --all --initlabel
part / --fstype ext4 --size 1 --grow --asprimary 
part swap --size 8000 

#System authorization infomation
auth  --useshadow  --enablemd5 
#Firewall configuration
firewall --disabled 
#Do not configure the X Window System
skipx

#Package install information
%packages
ubuntu-server
openssh-server
screen
curl
wget
python
%end
    In RedHat-like distribution, you only need kickstart file, in debian-like one, you also need a file called "seed file":
## Pre-setting
d-i live-installer/net-image sting http://192.168.100.1/ub1804srv/install/filesystem.squashfs

## Remind the host to remember mirror
# Since choosing http method, setup the mirror/country setting
d-i mirror/http/mirror select 192.168.100.1
d-i mirror/country string manual
##d-i mirror/http/mirror string 192.168.100.1
d-i mirror/http/hostname string 192.168.100.1
d-i mirror/http/directory string /ub1804srv
d-i mirror/http/proxy string 
#d-i mirror/suite string bionic
#d-i mirror/codename string bionic

# Suggest Regular by default.
d-i partman-auto/disk string /dev/nvme0n1

# Regular partition
d-i partman-auto/method string regular
# All files in a partition
d-i partman-auto/choose_recipe atomic
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
#d-i passwd/root-login boolean true

# Install the Ubuntu Server seed.
tasksel tasksel/force-tasks     string server
# Only install basic language packs. Let tasksel ask about tasks.
d-i     pkgsel/language-pack-patterns   string
# No language support packages.
d-i     pkgsel/install-language-support boolean false
# Only ask the UTC question if there are other operating systems installed.
d-i     clock-setup/utc-auto    boolean true
# Verbose output and no boot splash screen.
d-i     debian-installer/quiet  boolean false
  d-i     debian-installer/splash boolean false
# Install the debconf oem-config frontend (if in OEM mode).
d-i     oem-config-udeb/frontend        string debconf
# Wait for two seconds in grub
d-i     grub-installer/timeout  string 5
# Add the network and tasks oem-config steps by default.
oem-config      oem-config/steps        multiselect language, timezone, keyboard, user, network, tasks 
#d-i    pkgsel/include string openjdk-8
d-i     pkgsel/include string openssh-server build-essential unzip zip libasound2 libasound2-data libasyncns0 python
#d-i    debian-installer/exit/poweroff boolean true

d-i preseed/late_command string \
## Download the preset file
in-target sh -c 'wget -O /home/pixellab/tfpreset.sh http://192.168.100.1/postinst/preset.sh' ;\
in-target sh -c 'wget -O /etc/apt/sources.list http://192.168.100.1/postinst/sources.list' 

#Reboot the host
d-i finish-install/reboot_in_progress note
    In debian-like distribution, the importance of seed file might be more than kickstart file.
    BTW, in the PXE default file, you'll need to setup below message:
  kernel images/ub1804srv/linux
  append ks=http://192.168.100.1/cfgfiles/ubkstf.cfg initrd=images/ub1804srv/initrd.gz preseed/url=http://192.168.100.1/seedfiles/ubsrv.seed
Please note if you're using the RedHat style, the message "preseed/url=http://192.168.100.1/seedfiles/ubsrv.seed" is needless.
    That's all. Next article we'll introduce the PXE installation under UEFI mode.

Reference:

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/chap-installation-server-setup