# Install compiler and dependencies
sudo apt-get install -y git gcc make liblzma-dev
# Grab the source code
git clone https://github.com/ipxe/ipxe.git
cd ipxe/src
# Enable NFS support
sed -i 's/#undef\tDOWNLOAD_PROTO_NFS/#define\tDOWNLOAD_PROTO_NFS/' config/general.h
# Enable Ping support
sed -i 's/\/\/#define\ PING_CMD/#define\ PING_CMD/' config/general.h
sed -i 's/\/\/#define\ IPSTAT_CMD/#define\ IPSTAT_CMD/' config/general.h
sed -i 's/\/\/#define\ REBOOT_CMD/#define\ REBOOT_CMD/' config/general.h
sed -i 's/\/\/#define\ POWEROFF/#define\ POWEROFF/' config/general.h
Create ipxe/src/embed.ipxe
, this script will be embedded into the IPXE binary. It breaks the loop and gives control to main.ipxe. It falls back to IPXE shell if main.ipxe is not found on the tftp server root.
#!ipxe
dhcp
chain tftp://${next-server}/main.ipxe || shell
make bin/undionly.kpxe EMBED=embed.ipxe
and then upload bin/undionly.kpxe
to root of TFTP server.
Assume the DNS server is an OpenWrt box with dnsmasq
, add the following to /etc/dnsmasq.conf
:
dhcp-match=set:bios,60,PXEClient:Arch:00000
dhcp-boot=tag:bios,undionly.XXXXX,dell,192.168.x.x
dhcp-match=set:efibc,60,PXEClient:Arch:00007
dhcp-boot=tag:efibc,ipxe.efi,XXXXX,192.168.x.x
dhcp-match=set:efi64,60,PXEClient:Arch:00009
dhcp-boot=tag:efi64,ipxe.efi,XXXXX,192.168.x.x
Then execute /etc/init.d/dnsmasq restart
to apply the changes.
#!ipxe
# dhcp
# Set NFS strings
set nfs-server ${next-server}
set nfs-mountpt /srv/nfs
set nfs-linux-live nfs://${nfs-server}${nfs-mountpt}
set nfs-linux-boot ${nfs-server}:${nfs-mountpt}
# HTTP and iSCSI
set iscsi-server ${next-server}
set http-root http://${next-server}:3259
# Some menu defaults
set menu-timeout 5000
set submenu-timeout ${menu-timeout}
set menu-default ubuntu1804_live
:start
menu iPXE boot menu
item --gap -- ------------------------- Operating systems ------------------------------
item --key l ubuntu1804_live Ubuntu 18.04 Live
item ubuntu2004_live Ubuntu 20.04 Live
item debian10_live Debian 10 Live
item --key p windows10_pe Windows 10 PE
item windows10_iscsi Windows 10 iSCSI
item --gap -- ---------------------------- Installers ----------------------------------
item --key u ubuntu1804_inst Install Ubuntu 18.04
item --key d debian10_inst Install Debian 10
item --key w windows10_inst Install Windows 10 (WIM)
item --gap -- ------------------------- Advanced options -------------------------------
item shell Drop to iPXE shell
item reboot Reboot
item
item --key x exit Exit iPXE and continue BIOS boot
choose --timeout ${menu-timeout} --default ${menu-default} selected || goto cancel
set menu-timeout 0
goto ${selected}
:cancel
echo You cancelled the menu, dropping you to a shell
:shell
echo Type 'exit' to get the back to the menu
shell
set menu-timeout 0
set submenu-timeout 0
goto start
:reboot
reboot
:exit
exit
###
### Custom menu entries
###
:ubuntu1804_live
set dist-root ${nfs-linux-live}/ubuntu1804
kernel ${dist-root}/vmlinuz
initrd ${dist-root}/initrd
imgargs vmlinuz initrd=initrd nfsroot=${nfs-linux-boot}/ubuntu1804 netboot=nfs boot=casper
boot
goto start
:ubuntu2004_live
set dist-root ${nfs-linux-live}/ubuntu2004
kernel ${dist-root}/vmlinuz
initrd ${dist-root}/initrd
imgargs vmlinuz initrd=initrd nfsroot=${nfs-linux-boot}/ubuntu2004 netboot=nfs boot=casper ip=dhcp
boot
goto start
:debian10_live
set dist-root ${nfs-linux-live}/debian10
kernel ${dist-root}/vmlinuz-4.19.0-13-amd64
initrd ${dist-root}/initrd.img-4.19.0-13-amd64
imgargs vmlinuz-4.19.0-13-amd64 initrd=initrd.img-4.19.0-13-amd64 nfsroot=${nfs-linux-boot}/debian10 netboot=nfs boot=l$boot
goto start
:ubuntu1804_inst
set 210:string tftp://${next-server}/ubuntu/
set 209:string pxelinux.cfg/default
chain tftp://${next-server}/ubuntu/pxelinux.0
goto start
:debian10_inst
set 210:string tftp://${next-server}/debian/
set 209:string pxelinux.cfg/default
chain tftp://${next-server}/debian/pxelinux.0
goto start
:windows10_inst
set keep-san 1
# Has to be 0x80 otherwise installer wont accept the disk
sanhook --drive 0x80 iscsi:${iscsi-server}:tcp:3260:1:net.cszombie.au:windows
kernel wimboot
initrd ${http-root}/win10/boot/bcd BCD
initrd ${http-root}/win10/boot/boot.sdi boot.sdi
initrd ${http-root}/win10/sources/boot.wim boot.wim
boot
goto start
:windows10_pe
set keep-san 1
sanhook --drive 0x81 iscsi:${iscsi-server}:tcp:3260:1:net.cszombie.au:windows
echo Cyka
sanboot --no-describe ${http-root}/pe10.iso
goto start
:windows10_iscsi
set keep-san 1
sanboot iscsi:${iscsi-server}:tcp:3260:1:net.cszombie.au:windows
goto start
# CD into TFTP root
mkdir ubuntu
cd ubuntu
wget http://archive.ubuntu.com/ubuntu/dists/bionic-updates/main/installer-amd64/current/images/netboot/netboot.tar.gz
tar -xzvf netboot.tar.gz
rm netboot.tar.gz
or add the following to main.ipxe:
kernel http://archive.ubuntu.com/ubuntu/dists/bionic-updates/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/linux
initrd http://archive.ubuntu.com/ubuntu/dists/bionic-updates/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/initrd.gz
boot
The above method does not need the ubuntu installer to be downloaded on the TFTP server.
# CD into TFTP root
mkdir debian
cd debian
wget http://ftp.nl.debian.org/debian/dists/buster/main/installer-amd64/current/images/netboot/netboot.tar.gz
tar -xzvf netboot.tar.gz
rm netboot.tar.gz
- append
ip=dhcp
toimgargs
, otherwise the initramfs won't obtain an IP address via DHCP for you. No IP no network access, and the nfs mounting cannot be done. - Copy the
.disk
folder to your nfs server, the.disk
should be at the same folder with thecasper
folder. You only need to keep thecasper-uuid-generic
inside.disk
to make the whole thing work.
The folder structure looks like this:
/srv/nfs/ubuntu2004/.disk/casper-uuid-generic
/srv/nfs/ubuntu2004/casper/filesystem.squashfs
/srv/nfs/ubuntu2004/initrd
/srv/nfs/ubuntu2004/vmlinuz
kernel http://archive.ubuntu.com/ubuntu/dists/focal-updates/main/installer-amd64/current/legacy-images/netboot/ubuntu-installer/amd64/linux
initrd http://archive.ubuntu.com/ubuntu/dists/focal-updates/main/installer-amd64/current/legacy-images/netboot/ubuntu-installer/amd64/initrd.gz
boot
It is now 2024! IPxE still disables IPv6 by default
- Before compile, enable the IPv6 option of IPxE:
sed -i 's/\/\/#define\ NET_PROTO_IPV6/#define\ NET_PROTO_IPV6/' config/general.h
- The build command:
make bin-x86_64-efi/ipxe.efi
- On the OpenWrt router, replace dnsmasq with its full installation and remove odhcpd completely:
opkg update
cd /tmp/ && opkg download dnsmasq-full
opkg remove dnsmasq
opkg remove odhcpd-ipv6only
opkg install dnsmasq-full --cache /tmp/
rm -f /tmp/dnsmasq-full*.ipk
reboot
- Add this option to
/etc/dnsmasq.conf
on your OpenWrt router:
dhcp-match=set:efi6,option6:61,0007
#dhcp-match=set:efi6,option6:61,0009
#dhcp-match=set:efi6,option6:61,0011
dhcp-option=tag:efi6,option6:bootfile-url,tftp://[OPENWRT_ROUTER_IPV6]/ipxe.efi
or
dhcp-option=option6:bootfile-url,tftp://[OPENWRT_ROUTER_IPV6]/ipxe.efi
PxE uses completely different options on IPv4 and IPv6!
The multi-arch PxE implementation is very different!
OpenWrt Luci only partically supports IPv4 multi-arch PxE, IPv6 PxE requires scripting anyway as of July 2024.
- IPXE download and git repo
- lzma.h missing
- BootMGR sanboot 0x80 issue
- NFS boot, connect: Network is unreachable
- Install dnsmasq-full over dnsmasq
- Multi-Arch IPv4 TFTP boot on OpenWrt
- https://bugzilla.redhat.com/show_bug.cgi?id=1810172
- https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2019q4/013432.html
I'm sorry, but I cannot reproduce the error on a freshly installed Ubuntu 20.04. I tried on Ubuntu 22.04, Debian 12, WSL2, and bare metal. Try to build IPXE inside a Docker container to see if it solves the problem. Use Debian 12.