Skip to content

Latest commit

 

History

History
485 lines (349 loc) · 9.98 KB

File metadata and controls

485 lines (349 loc) · 9.98 KB

Installation Guide - iPXE PXE Boot Server

This guide will walk you through setting up the iPXE PXE boot server on your Debian 13 VM.

Prerequisites

  • Fresh Debian 13 VM with network connectivity
  • Root access to the VM
  • Existing DHCP server in your network (will be configured later)
  • VM IP address (we'll use YOUR_VM_IP as placeholder)

Step 1: Install Required Packages

SSH into your VM and install all required packages:

apt update
apt install -y \
    tftpd-hpa \
    nginx \
    wget \
    curl \
    ipxe \
    libguestfs-tools \
    qemu-utils \
    git

Step 2: Create Directory Structure

Create the necessary directories on the VM:

mkdir -p /srv/tftp
mkdir -p /srv/boot/ipxe
mkdir -p /srv/boot/debian-13/amd64
mkdir -p /srv/boot/cloud-init/debian-13
mkdir -p /srv/images/debian-13

Step 3: Configure TFTP Server

Copy the TFTP configuration:

cp config/tftpd-hpa /etc/default/tftpd-hpa

Install iPXE bootloaders:

cp /usr/lib/ipxe/undionly.kpxe /srv/tftp/
cp /usr/lib/ipxe/ipxe.efi /srv/tftp/
cp /usr/lib/ipxe/snponly.efi /srv/tftp/
chmod 644 /srv/tftp/*
chown -R tftp:tftp /srv/tftp/

Restart TFTP service:

systemctl restart tftpd-hpa
systemctl status tftpd-hpa

Step 4: Configure nginx

Copy nginx site configuration:

cp config/nginx-pxe-boot /etc/nginx/sites-available/pxe-boot
ln -s /etc/nginx/sites-available/pxe-boot /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default

Test nginx configuration:

nginx -t

If test passes, restart nginx:

systemctl restart nginx
systemctl status nginx

Step 5: Deploy iPXE Scripts

IMPORTANT: Before copying, update the IP address in ipxe/chain.ipxe.

Edit ipxe/chain.ipxe and replace SERVER_IP_PLACEHOLDER with your VM's IP address.

Then copy iPXE scripts:

cp ipxe/chain.ipxe /srv/boot/ipxe/
cp ipxe/menu.ipxe /srv/boot/ipxe/
cp ipxe/debian-13.ipxe /srv/boot/ipxe/

Set permissions:

chown -R www-data:www-data /srv/boot/
chmod -R 644 /srv/boot/ipxe/*

Step 6: Deploy Cloud-init Configuration

IMPORTANT: Before copying, update cloud-init/debian-13/user-data with your SSH public key.

Edit cloud-init/debian-13/user-data and replace YOUR_SSH_PUBLIC_KEY_HERE with your actual SSH public key.

Then copy cloud-init files:

cp cloud-init/debian-13/meta-data /srv/boot/cloud-init/debian-13/
cp cloud-init/debian-13/user-data /srv/boot/cloud-init/debian-13/

Set permissions:

chown -R www-data:www-data /srv/boot/cloud-init/
chmod -R 644 /srv/boot/cloud-init/debian-13/*

Step 7: Deploy Image Download Script

Copy the download script:

cp scripts/download-boot-images.sh /usr/local/bin/
chmod +x /usr/local/bin/download-boot-images.sh

Step 8: Deploy Systemd Service

Copy systemd service file:

cp config/download-boot-images.service /etc/systemd/system/

Reload systemd and enable service:

systemctl daemon-reload
systemctl enable download-boot-images.service

Step 9: Download Boot Images

Run the download script manually for the first time:

/usr/local/bin/download-boot-images.sh

This will:

  • Download Debian 13 cloud image (~200-400MB, may take several minutes)
  • Extract kernel and initrd from the image
  • Place them in /srv/boot/debian-13/amd64/

Monitor progress:

tail -f /var/log/download-boot-images.log

Verify files were created:

ls -lh /srv/boot/debian-13/amd64/
# Should show: vmlinuz, initrd.img, version.txt

Step 10: Test HTTP Server

Test that nginx is serving files correctly:

# Test iPXE scripts
curl http://localhost/boot/ipxe/menu.ipxe

# Test boot files
curl http://localhost/boot/debian-13/amd64/version.txt

# Test cloud-init
curl http://localhost/boot/cloud-init/debian-13/user-data

All commands should return file contents without errors.

Step 11: Test TFTP Server

From another machine on the network (or from the VM itself):

tftp YOUR_VM_IP
> get undionly.kpxe
> quit

ls -lh undionly.kpxe
# Should show file ~100KB

Step 12: Configure DHCP Server

Now you need to configure your existing DHCP server to point clients to this PXE boot server.

For ISC DHCP Server

Add to your DHCP configuration (usually /etc/dhcp/dhcpd.conf):

subnet 192.168.1.0 netmask 255.255.255.0 {
    # ... your existing config ...

    # PXE Boot Configuration
    next-server YOUR_VM_IP;

    # Architecture-specific boot files
    if option architecture-type = 00:00 {
        # BIOS x86
        filename "undionly.kpxe";
    } elsif option architecture-type = 00:07 {
        # UEFI x86_64
        filename "ipxe.efi";
    } elsif option architecture-type = 00:09 {
        # UEFI x86_64 (alternative)
        filename "ipxe.efi";
    }
}

Restart DHCP:

systemctl restart isc-dhcp-server

For dnsmasq

Add to your dnsmasq configuration (usually /etc/dnsmasq.conf):

# Enable TFTP
enable-tftp
tftp-root=/srv/tftp

# PXE Boot Configuration
dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:efi64,option:client-arch,7
dhcp-match=set:efi64,option:client-arch,9

dhcp-boot=tag:bios,undionly.kpxe,YOUR_VM_IP
dhcp-boot=tag:efi64,ipxe.efi,YOUR_VM_IP

Restart dnsmasq:

systemctl restart dnsmasq

For pfSense/OPNsense

  1. Go to Services → DHCP Server
  2. Scroll to "Network Booting" section
  3. Enable network booting
  4. Set "Next Server" to YOUR_VM_IP
  5. Set "Default BIOS file name" to undionly.kpxe
  6. Set "UEFI 64 bit file name" to ipxe.efi
  7. Save

Step 13: Test PXE Boot

  1. Boot a test VM or physical machine
  2. Configure BIOS/UEFI to boot from network
  3. Watch the boot sequence:
    • DHCP request → receives IP + boot server info
    • TFTP → downloads iPXE bootloader
    • iPXE menu appears with 10-second timeout
    • Default option: Debian 13
    • System boots and cloud-init provisions it

Verification

Monitor logs in real-time during boot:

# TFTP logs
journalctl -u tftpd-hpa -f

# nginx access logs
tail -f /var/log/nginx/pxe-boot-access.log

# nginx error logs
tail -f /var/log/nginx/pxe-boot-error.log

Expected boot sequence in nginx logs:

  1. Request for /boot/ipxe/menu.ipxe
  2. Request for /boot/ipxe/debian-13.ipxe
  3. Request for /boot/debian-13/amd64/vmlinuz
  4. Request for /boot/debian-13/amd64/initrd.img
  5. Request for /boot/cloud-init/debian-13/meta-data
  6. Request for /boot/cloud-init/debian-13/user-data

Troubleshooting

TFTP Not Working

Check TFTP service:

systemctl status tftpd-hpa
journalctl -u tftpd-hpa -n 50

Verify files exist:

ls -la /srv/tftp/

Check firewall:

ufw status
# If enabled, allow TFTP:
ufw allow 69/udp

nginx Not Serving Files

Check nginx service:

systemctl status nginx
nginx -t

Verify file permissions:

ls -la /srv/boot/

Check firewall:

ufw status
# If enabled, allow HTTP:
ufw allow 80/tcp

iPXE Menu Not Appearing

Check that DHCP is providing correct next-server and filename.

From a booting client, check DHCP options received.

Verify iPXE can reach HTTP server:

  • Boot to iPXE shell (if you can)
  • Type: dhcp
  • Type: show ${next-server}
  • Type: chain http://${next-server}/boot/ipxe/menu.ipxe

Image Download Failed

Check logs:

tail -f /var/log/download-boot-images.log

Common issues:

  • No internet connectivity
  • libguestfs-tools not installed
  • Insufficient disk space
  • Cloud image URL changed

Cloud-init Not Running

Check kernel parameters include cloud-init datasource:

ds=nocloud-net;s=http://YOUR_VM_IP/boot/cloud-init/debian-13/

Verify cloud-init files are accessible:

curl http://YOUR_VM_IP/boot/cloud-init/debian-13/meta-data
curl http://YOUR_VM_IP/boot/cloud-init/debian-13/user-data

Firewall Configuration

If you have a firewall enabled, allow these ports:

# TFTP (UDP)
ufw allow 69/udp

# HTTP (TCP)
ufw allow 80/tcp

Security Considerations

Current Setup (Development)

  • HTTP (unencrypted) - credentials visible in cloud-init
  • No authentication on TFTP/HTTP
  • Anyone on network can PXE boot

Production Improvements (Future)

  1. Use HTTPS for nginx - encrypt cloud-init data
  2. Network isolation - Put boot server on management VLAN
  3. Firewall rules - Only allow boot clients to access server
  4. Remove autoindex - Disable directory browsing in nginx
  5. MAC address filtering - Only allow specific MACs to boot

Maintenance

Update Boot Images

The download script checks if images already exist before downloading. To force update:

rm -rf /srv/images/debian-13/debian-13-generic-amd64.qcow2
rm -rf /srv/boot/debian-13/amd64/*
/usr/local/bin/download-boot-images.sh

Check Service Status

systemctl status tftpd-hpa
systemctl status nginx
systemctl status download-boot-images

View Logs

# TFTP logs
journalctl -u tftpd-hpa

# nginx logs
tail -f /var/log/nginx/pxe-boot-access.log
tail -f /var/log/nginx/pxe-boot-error.log

# Image download logs
tail -f /var/log/download-boot-images.log

Next Steps

Once the basic setup is working:

  1. Add more OS images - Create similar structures for other distributions
  2. Customize cloud-init - Add your specific provisioning needs
  3. Add preseed for installation - Convert PXE boot to automated installer
  4. Containerize - Move to Docker/Kubernetes (see CONTAINERIZATION.md)
  5. Enable HTTPS - Encrypt boot traffic

Success Criteria

You'll know everything is working when:

  1. TFTP service is running and accessible
  2. nginx is serving files on port 80
  3. Boot images are downloaded and extracted
  4. PXE client boots and shows iPXE menu
  5. Debian 13 boots successfully
  6. Cloud-init provisions the system
  7. You can SSH into the booted system

Help & Support

If you encounter issues:

  1. Check logs (see Troubleshooting section)
  2. Verify all files are in correct locations
  3. Verify IP addresses are correct in all configs
  4. Test each component individually (TFTP, HTTP, etc.)
  5. Check network connectivity between components