Logo

PXE Boot: automated server install over network

PXE Boot: automated server install over network

PXE Boot (Preboot eXecution Environment) lets you boot and install an OS on machines via the network, no CD/USB needed. Essential to quickly deploy dozens of identical servers in a datacenter.

Introduction

PXE (pronounced "pixie") enables:

  • Network boot (PXE-capable NIC)
  • Automated OS install (Debian, Ubuntu, ESXi)
  • Mass deployment without manual intervention
  • Fast re-install on failure
  • Boot in rescue / live mode

Use cases: datacenter with 50 identical servers to deploy, provisioning rack, Proxmox lab.

How it works

PXE Client                       Switch                     PXE Server
    |  1. DHCP DISCOVER (broadcast)  |                            |
    |------------------------------->|                            |
    |                                |  2. DHCPOFFER + filename + |
    |                                |     next-server            |
    |<-------------------------------|----------------------------|
    |  3. TFTP GET pxelinux.0        |                            |
    |---------------------------------|--------------------------->|
    |  4. Bootloader (pxelinux/grub) |                            |
    |  loads kernel + initrd         |                            |
    |  5. Kernel boots, mounts NFS   |                            |
    |     or HTTP for preseed        |                            |

Prerequisites

  • Linux VPS Debian 12 / Ubuntu 24.04 (the PXE server)
  • 2 IPs on same LAN as clients
  • Root access
  • No existing DHCP server, OR ability to configure existing DHCP

Step 1: Install dnsmasq + tftpd

sudo apt update
sudo apt install -y dnsmasq tftpd-hpa pxelinux syslinux-common nginx

Step 2: Configure dnsmasq (DHCP + DNS + TFTP)

/etc/dnsmasq.d/pxe.conf:

interface=eth0
bind-interfaces

dhcp-range=192.168.1.100,192.168.1.200,12h
dhcp-option=3,192.168.1.1
dhcp-option=6,1.1.1.1,8.8.8.8

enable-tftp
tftp-root=/srv/tftp
dhcp-boot=pxelinux.0

dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:efi64,option:client-arch,7
dhcp-boot=tag:bios,pxelinux.0
dhcp-boot=tag:efi64,grubx64.efi

log-dhcp
sudo systemctl restart dnsmasq

Step 3: Download pxelinux and bootloaders

sudo mkdir -p /srv/tftp/pxelinux.cfg
sudo cp /usr/lib/PXELINUX/pxelinux.0 /srv/tftp/
sudo cp /usr/lib/syslinux/modules/bios/ldlinux.c32 /srv/tftp/
sudo cp /usr/lib/syslinux/modules/bios/menu.c32 /srv/tftp/
sudo cp /usr/lib/syslinux/modules/bios/libutil.c32 /srv/tftp/
sudo cp /usr/lib/syslinux/modules/bios/vesamenu.c32 /srv/tftp/
sudo cp /usr/lib/syslinux/modules/bios/libcom32.c32 /srv/tftp/

For UEFI:

sudo apt install -y grub-efi-amd64-signed shim-signed
sudo cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi /srv/tftp/

Step 4: PXE menu

/srv/tftp/pxelinux.cfg/default:

DEFAULT vesamenu.c32
PROMPT 0
MENU TITLE VeryCloud PXE Boot Menu
TIMEOUT 100

LABEL local
    MENU LABEL Boot from local disk
    LOCALBOOT 0

LABEL debian12
    MENU LABEL Install Debian 12 (auto)
    KERNEL debian-installer/amd64/linux
    APPEND vga=788 initrd=debian-installer/amd64/initrd.gz auto=true priority=critical preseed/url=http://192.168.1.5/preseed.cfg ---

LABEL ubuntu24
    MENU LABEL Install Ubuntu 24.04 (auto)
    KERNEL ubuntu/casper/vmlinuz
    APPEND initrd=ubuntu/casper/initrd autoinstall ds=nocloud-net\;s=http://192.168.1.5/autoinstall/ ---

LABEL rescue
    MENU LABEL Rescue / live system
    KERNEL debian-installer/amd64/linux
    APPEND initrd=debian-installer/amd64/initrd.gz rescue/enable=true

Step 5: Download netboot images

Debian 12

sudo mkdir -p /srv/tftp/debian-installer/amd64
cd /srv/tftp/debian-installer/amd64
sudo wget http://ftp.debian.org/debian/dists/bookworm/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux
sudo wget http://ftp.debian.org/debian/dists/bookworm/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz

Ubuntu 24.04

sudo mkdir -p /srv/tftp/ubuntu/casper
cd /tmp
sudo wget https://releases.ubuntu.com/24.04/ubuntu-24.04-live-server-amd64.iso
sudo mount -o loop ubuntu-24.04-live-server-amd64.iso /mnt
sudo cp /mnt/casper/vmlinuz /srv/tftp/ubuntu/casper/
sudo cp /mnt/casper/initrd /srv/tftp/ubuntu/casper/
sudo umount /mnt

Step 6: HTTP server for preseed

/etc/nginx/sites-available/pxe:

server {
    listen 80;
    server_name 192.168.1.5;
    root /srv/www;
    
    location / {
        autoindex on;
    }
}
sudo mkdir -p /srv/www
sudo ln -s /etc/nginx/sites-available/pxe /etc/nginx/sites-enabled/
sudo systemctl restart nginx

Step 7: Debian preseed

/srv/www/preseed.cfg:

d-i debian-installer/locale string en_US.UTF-8
d-i keyboard-configuration/xkb-keymap select us

d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string server

d-i mirror/country string manual
d-i mirror/http/hostname string deb.debian.org
d-i mirror/http/directory string /debian

d-i passwd/root-login boolean true
d-i passwd/root-password-crypted password $6$rounds=4096$xxxx...
d-i passwd/user-fullname string Admin
d-i passwd/username string admin
d-i passwd/user-password-crypted password $6$rounds=4096$yyyy...

d-i clock-setup/utc boolean true
d-i time/zone string UTC
d-i clock-setup/ntp boolean true

d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select 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

tasksel tasksel/first multiselect ssh-server
d-i pkgsel/include string openssh-server sudo curl

d-i grub-installer/bootdev string default
d-i grub-installer/only_debian boolean true

d-i finish-install/reboot_in_progress note

d-i preseed/late_command string \
    in-target wget -O /root/post.sh http://192.168.1.5/post.sh; \
    in-target chmod +x /root/post.sh; \
    in-target /root/post.sh

Generate password hashes:

mkpasswd -m sha-512

Step 8: Post-install script

/srv/www/post.sh:

#!/bin/bash
mkdir -p /root/.ssh
echo "ssh-ed25519 AAAA... [email protected]" > /root/.ssh/authorized_keys
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys

apt-get update
apt-get install -y htop curl vim git fail2ban

sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh

Step 9: Ubuntu autoinstall (cloud-init)

sudo mkdir -p /srv/www/autoinstall
sudo touch /srv/www/autoinstall/meta-data

/srv/www/autoinstall/user-data:

#cloud-config
autoinstall:
  version: 1
  locale: en_US.UTF-8
  keyboard:
    layout: us
  identity:
    hostname: server
    username: admin
    password: "$6$rounds=4096$xxxx..."
  ssh:
    install-server: true
    authorized-keys:
      - "ssh-ed25519 AAAA... [email protected]"
  storage:
    layout:
      name: lvm
  packages:
    - htop
    - curl
    - vim
    - git
  late-commands:
    - curtin in-target -- systemctl enable ssh

Step 10: Boot a machine in PXE

On client:

  1. Enter BIOS / UEFI
  2. Enable "Network Boot" / "PXE Boot"
  3. Set LAN first in boot order
  4. Save and restart

Machine should:

  1. DHCP DISCOVER
  2. Receive DHCPOFFER with next-server (your PXE)
  3. TFTP download pxelinux.0
  4. Show PXE menu
  5. Launch auto-install

Step 11: Logs and debug

sudo tail -f /var/log/syslog | grep dnsmasq
sudo journalctl -u dnsmasq -f
sudo journalctl -u tftpd-hpa -f

TFTP test:

tftp 192.168.1.5
> get pxelinux.0
> quit

Step 12: Foreman / Cobbler (going further)

For complex deployments:

  • Cobbler: separate tutorial
  • Foreman: full provisioning stack + reporting
  • MAAS (Canonical): "Metal as a Service" for bare metal deployment

Troubleshooting

Client doesn't get DHCP

  • dnsmasq on correct interface
  • No firewall (port 67/UDP, 69/UDP)
  • Client on right VLAN
  • No competing DHCP
sudo tcpdump -i eth0 -n port 67 or port 68

TFTP "File not found"

sudo ls -la /srv/tftp/
sudo chmod -R 755 /srv/tftp/
sudo chown -R tftp:tftp /srv/tftp/

Very slow boot

TFTP is slow (UDP, small packets). Use iPXE to chainload via HTTP. See https://ipxe.org

Preseed fails silently

Press Esc then e at menu boot to edit kernel line. Add debconf/priority=low to see errors.

Useful commands

sudo systemctl status dnsmasq
sudo systemctl status tftpd-hpa
sudo systemctl status nginx

sudo journalctl -u dnsmasq -f

tftp 192.168.1.5 -c get pxelinux.0

ls -la /srv/tftp/
cat /srv/tftp/pxelinux.cfg/default

sudo apt install -y ipxe

Conclusion

PXE Boot enables fast and automated deployment:

  • No physical media needed
  • Reproducible (preseed / autoinstall)
  • Essential in datacenters

Limits:

  • Requires LAN control (DHCP)
  • TFTP is slow (use iPXE + HTTP)
  • Technical initial setup

Going further:

  • iPXE for HTTP boot (10x faster)
  • Cobbler to orchestrate multiple distros
  • Foreman / MAAS for full provisioning

Resources

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members