Skip to content

Instantly share code, notes, and snippets.

Last active July 23, 2024 04:35
Show Gist options
  • Save rikka0w0/50895b82cbec8a3a1e8c7707479824c1 to your computer and use it in GitHub Desktop.
Save rikka0w0/50895b82cbec8a3a1e8c7707479824c1 to your computer and use it in GitHub Desktop.
Build IPXE

1. Install tools and config IPXE

# Install compiler and dependencies
sudo apt-get install -y git gcc make liblzma-dev

# Grab the source code
git clone
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

2. Create the embedded script

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.


chain tftp://${next-server}/main.ipxe || shell

3. Compile IPXE

make bin/undionly.kpxe EMBED=embed.ipxe and then upload bin/undionly.kpxe to root of TFTP server.

4. Configure DNS server

Assume the DNS server is an OpenWrt box with dnsmasq, add the following to /etc/dnsmasq.conf:




Then execute /etc/init.d/dnsmasq restart to apply the changes.

5. Create main.ipxe on TFTP root

# 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

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 --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}

echo You cancelled the menu, dropping you to a shell

echo Type 'exit' to get the back to the menu
set menu-timeout 0
set submenu-timeout 0
goto start



### Custom menu entries

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
goto start

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
goto start

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

set 210:string tftp://${next-server}/ubuntu/
set 209:string pxelinux.cfg/default
chain tftp://${next-server}/ubuntu/pxelinux.0
goto start

set 210:string tftp://${next-server}/debian/
set 209:string pxelinux.cfg/default
chain tftp://${next-server}/debian/pxelinux.0
goto start

set keep-san 1
# Has to be 0x80 otherwise installer wont accept the disk
sanhook --drive 0x80 iscsi:${iscsi-server}
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
goto start

set keep-san 1
sanhook --drive 0x81 iscsi:${iscsi-server}
echo Cyka
sanboot --no-describe ${http-root}/pe10.iso
goto start

set keep-san 1
sanboot iscsi:${iscsi-server}
goto start

Add Ubuntu Netboot (BIOS only)

# CD into TFTP root
mkdir ubuntu
cd ubuntu
tar -xzvf netboot.tar.gz
rm netboot.tar.gz

or add the following to main.ipxe:


The above method does not need the ubuntu installer to be downloaded on the TFTP server.

Add Debian Netboot

# CD into TFTP root
mkdir debian
cd debian
tar -xzvf netboot.tar.gz
rm netboot.tar.gz

Boot Ubuntu 20.04 Live

  1. append ip=dhcp to imgargs, 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.
  2. Copy the .disk folder to your nfs server, the .disk should be at the same folder with the casper folder. You only need to keep the casper-uuid-generic inside .disk to make the whole thing work.

The folder structure looks like this:


Boot Ubuntu 20.04 Installer (Network)


Enable IPv6 Support

It is now 2024! IPxE still disables IPv6 by default

  1. Before compile, enable the IPv6 option of IPxE: sed -i 's/\/\/#define\ NET_PROTO_IPV6/#define\ NET_PROTO_IPV6/' config/general.h
  2. The build command: make bin-x86_64-efi/ipxe.efi
  3. 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
  1. Add this option to /etc/dnsmasq.conf on your OpenWrt router:

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.


  1. IPXE download and git repo
  2. lzma.h missing
  3. BootMGR sanboot 0x80 issue
  4. NFS boot, connect: Network is unreachable
  5. Install dnsmasq-full over dnsmasq
  6. Multi-Arch IPv4 TFTP boot on OpenWrt
Copy link

what OS are you using? I tried this on Debian 11, I get a compile error. fatal error: config/local/ioapi.h: No such file or directory

Copy link

what OS are you using? I tried this on Debian 11, I get a compile error. fatal error: config/local/ioapi.h: No such file or directory

I was using Ubuntu 20.04, and I remembered that the same compilation procedure works on Debian 10

Copy link

On ubuntu 20.04 with standard developer tools, I'm getting:

In file included from <command-line>: crypto/aes.c: In function ‘aes_gcm_setkey’: include/assert.h:82:10: error: call to ‘build_assert_805’ declared with attribute error: build_assert(( ( void * ) &context->raw ) == ( ( void * ) context->gcm.raw_ctx )) failed 82 | _C2 ( build_assert_, __LINE__ ) (); \ | ^ ./include/compiler.h:46:21: note: in definition of macro ‘_C1’ 46 | #define _C1( x, y ) x ## y | ^ include/assert.h:82:4: note: in expansion of macro ‘_C2’ 82 | _C2 ( build_assert_, __LINE__ ) (); \ | ^~~ include/ipxe/gcm.h:92:2: note: in expansion of macro ‘build_assert’ 92 | build_assert ( ( ( void * ) &context->gcm ) == ctx ); \ | ^~~~~~~~~~~~ crypto/aes.c:805:1: note: in expansion of macro ‘GCM_CIPHER’ 805 | GCM_CIPHER ( aes_gcm, aes_gcm_algorithm, | ^~~~~~~~~~ make: *** [Makefile.housekeeping:962: bin/aes.o] Error 1

Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment