Script: install.sh
Repo: https://github.com/scriptmgr
Purpose: Stand up a DHCP‑agnostic PXE/iPXE boot server with TFTP + HTTP, BIOS/UEFI chainloaders, iPXE menus, Windows PE via wimboot, Syslinux/memdisk tooling, and auto‑generated ISO submenus from /mnt/ISOs.
No DHCP included. Keep your existing DHCP (dnsmasq/ISC/Windows, etc). This script only provides TFTP + HTTP and menu automation.
- Distro‑agnostic: Works on Debian/Ubuntu, RHEL/Alma, openSUSE, Arch, Alpine.
- No DHCP: Prints DHCP hints for external servers (dnsmasq/ISC/Windows).
- BIOS & UEFI: Serves
undionly.kpxe(BIOS),ipxe.efi/snponly.efi(UEFI). - HTTP + TFTP: Prefers nginx on :80; falls back to Python
http.serveron :8080. TFTP served from/srv/tftp. - Menu layout: Linux, Windows, BSD, Tools, iPXE, Local Boot (default = HD).
- Windows PE / Installer: via wimboot (auto‑fetched).
- Syslinux/memdisk: For BIOS ISO/IMG tools and utilities.
- Auto ISO menus: Scans
/mnt/ISOs(subdirs → submenus) and wires a BIOS‑only memdisk launcher. - Netboot seeds: Placeholders for Debian, AlmaLinux, Alpine, Arch.
- Systemd services:
tftpd-ipxe.serviceand eithernginxor fallbackipxe-httpd.service. - Idempotent: Safe to re‑run; creates required directories and links.
-
TFTP root:
/srv/tftp/srv/tftp/ipxe/{undionly.kpxe, ipxe.efi, snponly.efi, wimboot, boot.ipxe}/srv/tftp/syslinux/{memdisk, pxelinux.0, *.c32}(when available)/srv/tftp/mgr/pxe(requested path, for your own assets)
-
HTTP root:
/srv/www/ipxemenus/→ generated iPXE menus (boot.ipxe,linux.ipxe,windows.ipxe,bsd.ipxe,tools.ipxe,ipxe.ipxe,iso-auto.ipxe)linux/{debian,alma,alpine,arch}/→ put netboot kernels/initrds herewindows/winpe/{bootmgr,BCD,boot.sdi,boot.wim}tools/→ utilities (e.g.,memtest86+.bin.gzif downloaded)isos/→ symlink to/mnt/ISOswhen present
# As root
bash install.shAfter it completes, set your DHCP to point to this server:
-
Next‑server (a.k.a. TFTP server):
NEXT-SERVER <SERVER_IP> -
Filename:
- BIOS:
ipxe/undionly.kpxe - UEFI x86_64:
ipxe/ipxe.efi(oripxe/snponly.efi)
- BIOS:
Optional HTTP chain (if your environment supports iPXE over HTTP):
http://<SERVER_IP>/menus/boot.ipxe
The installer auto‑detects a host IP for menus. You can safely edit the menu files in
/srv/www/ipxe/menus/if you need to change host/IP/port.
-
Root access, systemd environment (services are created as units).
-
Network ports available:
- TFTP UDP/69
- HTTP TCP/80 (nginx) or TCP/8080 (Python fallback)
-
Outbound Internet access during install (to fetch iPXE binaries and wimboot). If offline, pre‑stage those files and re‑run.
apt-get, dnf, yum, zypper, pacman, apk
The script installs base tooling, TFTP server, Syslinux (for memdisk), and nginx (if available) or Python 3 for fallback.
Again, DHCP is external. Configure your existing server to point to this PXE host.
# Common settings
log-dhcp
# Set TFTP server
dhcp-option=66,<SERVER_IP>
# BIOS
dhcp-boot=ipxe/undionly.kpxe
# UEFI x86_64 example
#dhcp-match=set:efi-x86_64,option:client-arch,7
#dhcp-boot=tag:efi-x86_64,ipxe/ipxe.efi
# Or use snponly.efi for UEFInext-server <SERVER_IP>;
# BIOS
filename "ipxe/undionly.kpxe";
# For UEFI (x86_64 = 00:07)
# if option arch = 00:07 {
# filename "ipxe/ipxe.efi";
# } else {
# filename "ipxe/undionly.kpxe";
# }
-
Scope Options:
- 066 Boot Server Host Name =
<SERVER_IP> - 067 Bootfile Name =
ipxe/ipxe.efi(UEFI) oripxe/undionly.kpxe(BIOS)
- 066 Boot Server Host Name =
If you have mixed BIOS/UEFI clients, use vendor class policies or IP helper rules to differentiate.
Top‑level: Linux · Windows · BSD · Tools · iPXE · Local Boot
- Linux: Debian, AlmaLinux, Alpine, Arch + ISO Submenus (auto‑discovered from
/mnt/ISOs). - Windows: WinPE/Installer via wimboot (place files under
windows/winpe/). - BSD: Example FreeBSD entry (customize to your tree).
- Tools: Memtest86+ and local‑disk boot option.
- iPXE: Shell and custom snippets.
- Local Boot: Default; attempts
sanboot 0x80(first disk).
Note: Memdisk ISO boot is BIOS‑only. For UEFI, prefer kernel+initrd netboot workflows or WinPE.
Below are minimal patterns. Replace with actual versions/filenames from your distro’s netboot artifacts.
-
Place files:
linux/debian/vmlinuzlinux/debian/initrd.gz- Optional:
linux/debian/preseed.cfg
-
The menu uses:
kernel http://<SERVER_IP>/linux/debian/vmlinuz
initrd http://<SERVER_IP>/linux/debian/initrd.gz
imgargs vmlinuz ip=dhcp url=http://<SERVER_IP>/linux/debian/preseed.cfg auto=true priority=critical
boot
-
Place files:
linux/alma/vmlinuzlinux/alma/initrd.img- Optional Kickstart:
linux/alma/ks.cfg
-
Menu snippet:
kernel http://<SERVER_IP>/linux/alma/vmlinuz
initrd http://<SERVER_IP>/linux/alma/initrd.img
imgargs vmlinuz inst.stage2=http://<SERVER_IP>/linux/alma/ inst.ks=http://<SERVER_IP>/linux/alma/ks.cfg ip=dhcp
boot
-
Place files:
linux/alpine/vmlinuz-ltslinux/alpine/initramfs-ltslinux/alpine/modloop-lts
-
Menu snippet:
kernel http://<SERVER_IP>/linux/alpine/vmlinuz-lts
initrd http://<SERVER_IP>/linux/alpine/initramfs-lts
imgargs vmlinuz-lts modloop=http://<SERVER_IP>/linux/alpine/modloop-lts alpine_repo=http://<SERVER_IP>/linux/alpine/repo ip=dhcp
boot
-
Place files:
linux/arch/vmlinuz-linuxlinux/arch/initramfs-linux.img
-
Menu snippet:
kernel http://<SERVER_IP>/linux/arch/vmlinuz-linux
initrd http://<SERVER_IP>/linux/arch/initramfs-linux.img
imgargs vmlinuz-linux archiso_http_srv=http://<SERVER_IP>/linux/arch ip=dhcp
boot
Tip: You can host full mirrors or netboot roots under the HTTP tree if you prefer offline installs.
-
Place these in
windows/winpe/:bootmgrBCDboot.sdiboot.wim(WinPE or installer WIM)
-
The menu loads
wimbootand those resources, then boots into WinPE/Installer.
The script downloads wimboot into
/srv/tftp/ipxe/wimbootautomatically.
- Put ISO files under
/mnt/ISOs. - Subdirectories become submenus. The installer symlinks this tree into
http://<SERVER_IP>/isos/. - iPXE entries use Syslinux
memdiskto boot ISO images on BIOS clients.
UEFI + ISO via memdisk is generally not supported. Use UEFI‑native netboot or WinPE instead.
- TFTP:
systemctl status tftpd-ipxe - HTTP (nginx):
systemctl status nginx(listens on :80) - HTTP (fallback):
systemctl status ipxe-httpd(Pythonhttp.serveron :8080)
Logs: use journalctl -u <service>.
Open these ports to your provisioning/VLAN:
- UDP/69 (TFTP)
- TCP/80 (HTTP if nginx) or TCP/8080 (fallback HTTP)
firewalld
firewall-cmd --add-service=tftp --permanent
firewall-cmd --add-service=http --permanent
firewall-cmd --reloadufw
ufw allow 69/udp
ufw allow 80/tcp
# or if using Python fallback
ufw allow 8080/tcp/srv/tftp/
├─ ipxe/
│ ├─ undionly.kpxe
│ ├─ ipxe.efi
│ ├─ snponly.efi
│ ├─ wimboot
│ └─ boot.ipxe # copy of main menu for TFTP access
├─ syslinux/
│ ├─ memdisk
│ ├─ pxelinux.0 (if available)
│ └─ *.c32 modules
└─ mgr/pxe/ # reserved path for your custom assets
/srv/www/ipxe/
├─ menus/
│ ├─ boot.ipxe (main)
│ ├─ linux.ipxe
│ ├─ windows.ipxe
│ ├─ bsd.ipxe
│ ├─ tools.ipxe
│ ├─ ipxe.ipxe
│ └─ iso-auto.ipxe
├─ linux/{debian,alma,alpine,arch}/...
├─ windows/winpe/{bootmgr,BCD,boot.sdi,boot.wim}
├─ tools/
└─ isos/ -> /mnt/ISOs (symlink)
- Host/IP/port: Detected at install; edit URLs in
/srv/www/ipxe/menus/*.ipxeas needed. - Menu entries: Add/remove sections in
menus/*.ipxe. iPXE syntax is simple—usemenu,item,choose,kernel,initrd,imgargs,boot,chain. - Alternative chainloaders: Swap
ipxe.efiwithsnponly.efiif vendor SNP driver works better. - Local mirrors: Host full repositories under
/srv/www/ipxe/linux/<distro>/and point menu args accordingly.
- PXE times out / no file: Check DHCP
next-serverandfilenamevalues; verify TFTP port 69/UDP is open. - UEFI clients fail to boot ISO: Expected—use kernel+initrd netboot or WinPE.
- 403/404 over HTTP: Confirm nginx is active (
systemctl status nginx) or Python fallback service, and that files exist under/srv/www/ipxe. - iPXE says “No such file”: URLs are case‑sensitive; verify exact paths and filenames.
- Windows PE stuck early: Ensure
bootmgr,BCD,boot.sdi,boot.wimare present and correct for your architecture. - Syslinux assets missing: On some distros, Syslinux modules live under different paths. Re‑run the installer; it will try multiple locations.
- Limit exposure to provisioning networks/VLANs only.
- If using nginx, consider
autoindex off;and explicit locations. - Keep WinPE/WIM images and installers on restricted segments.
- Regularly update iPXE and distro netboot images.
systemctl disable --now tftpd-ipxe || true
systemctl disable --now ipxe-httpd || true
systemctl disable --now nginx || true
rm -f /etc/systemd/system/tftpd-ipxe.service /etc/systemd/system/ipxe-httpd.service
systemctl daemon-reload
# Remove content trees (optional)
rm -rf /srv/tftp /srv/www/ipxe /var/lib/ipxe-installerIssues and PRs welcome at https://github.com/scriptmgr. Keep changes POSIX‑friendly and distro‑agnostic.
MIT — © ScriptMgr