Install Using PXE Boot
Deploy Garden Linux on bare-metal systems using iPXE network boot. This guide covers two PXE deployment modes: ephemeral live boot (system runs from RAM) and persistent boot+install (system installs to disk).
For non-network installations using bootable media, see Install Using ISO.
Overview
Garden Linux supports two PXE deployment modes:
PXE Live Boot — Boot Garden Linux from the network and run entirely from RAM. The system is ephemeral and stateless; changes are lost on reboot.
PXE Boot + Install — Boot from the network, then automatically install to disk for persistent storage. First boot runs from RAM while installing to disk, then reboots into the installed system. Subsequent boots load directly from disk.
Both modes support Ignition for first-boot configuration (users, SSH keys, files, services).
PXE Live Boot Workflow
- Network boot via iPXE — Client firmware loads iPXE from TFTP, which fetches the kernel, initrd, and squashfs root filesystem over HTTP
- Live system — Garden Linux runs from an OverlayFS with the squashfs image as the lower layer and tmpfs as the upper layer
- Ignition configuration (optional) — Applies first-boot configuration if configured
- System ready — Garden Linux runs from RAM; changes are ephemeral
PXE Boot + Install Workflow
- Network boot via iPXE — Same as live boot: fetch kernel, initrd, and squashfs over HTTP
- Live system — Garden Linux runs from OverlayFS temporarily
- Ignition configuration — Applies partition layout, target disk configuration, and merges the install configuration
- Installation — Copies the live system to disk, installs the bootloader, and reboots into the installed system
- Subsequent boots — System boots directly from disk without PXE
Boot + Install Flow Diagram
flowchart TD
A[Power On] --> B[Firmware: BIOS/UEFI]
B --> C[PXE Boot]
C --> D[DHCP: Get IP + TFTP server]
D --> E[TFTP: Download iPXE binary]
E --> F[iPXE: Get boot script URL via DHCP]
F --> G[HTTP: Download boot.ipxe]
G --> H[HTTP: Download kernel + initrd]
H --> I[Boot Kernel]
I --> J[Initramfs: Fetch squashfs via HTTP]
J --> K[Mount OverlayFS: squashfs + tmpfs]
K --> L[Ignition: Fetch config from URL]
L --> M[Ignition: Write files, enable services]
M --> InstallCheck{_install or _autoinstall<br/>feature included?}
InstallCheck -->|No| LiveOnly[Live boot only<br/>System runs from RAM]
InstallCheck -->|Yes| AutoCheck{_autoinstall<br/>feature?}
AutoCheck -->|Yes| AutoService[gl-autoinstall.service:<br/>Detect first suitable disk]
AutoCheck -->|No| ManualOrIgnition{Ignition triggers<br/>install.service?}
ManualOrIgnition -->|Yes| IgnitionInstall[install.service: Run installer]
ManualOrIgnition -->|No| ManualInstall[Manual: User runs<br/>/opt/install/install.sh]
AutoService --> Partition[Partition disk: GPT with EFI + ROOT]
IgnitionInstall --> Partition
ManualInstall --> Partition
Partition --> Copy[Copy rootfs to disk]
Copy --> InstallBoot[Install bootloader: syslinux/systemd-boot]
InstallBoot --> Reboot[Reboot into installed system]
Reboot --> Running[Garden Linux running from disk]
Running --> Subsequent[Subsequent boots: direct from disk]
style InstallCheck fill:#e1f5ff
style AutoCheck fill:#e1f5ff
style ManualOrIgnition fill:#e1f5ff
style LiveOnly fill:#f0f0f0
style AutoService fill:#fff4e1
style IgnitionInstall fill:#d4edda
style ManualInstall fill:#f0f0f0Prerequisites
- Target clients — Physical servers or virtual machines with BIOS or UEFI firmware supporting network boot
- Garden Linux build — Image built with
_pxe(which includes_ignitefor Ignition support),baremetal, andserverfeatures, generating:vmlinuz— Kernel imageinitrd— Initramfs with live boot supportroot.squashfs— Compressed root filesystem- For disk installation, also include
_installor_autoinstall
- TFTP server — Serves iPXE binaries for Legacy BIOS and UEFI firmware:
undionly.kpxe— Legacy BIOS iPXE binaryipxe.efi— UEFI iPXE binary
- DHCP server — Provides IP addresses and PXE chainloading configuration
- HTTP server — Hosts Garden Linux images, iPXE boot scripts, and Ignition configuration files
Download iPXE binaries from https://boot.ipxe.org.
Disk Layout and Bootloader
The installation creates a GPT partition table with EFI (510 MiB, VFAT) and ROOT (remaining space, ext4) partitions. The bootloader is firmware-dependent: syslinux for Legacy BIOS, systemd-boot for UEFI.
For full details on the partition layout and bootloader configuration, see Disk Layout and Bootloader.
Prepare PXE Boot Artifacts
Before deploying, build Garden Linux with PXE support and create the iPXE boot script.
Build PXE Images
Build a Garden Linux image with the _pxe feature:
./build baremetal-gardener_prod_pxeThis generates an archive in .build/ with the naming pattern baremetal-gardener_prod_pxe-amd64-<version>-<commit>.pxe.tar.gz. This archive needs to be extracted and contains the following files:
vmlinuz— Kernel imageinitrd— Initramfs with live boot and Ignition supportroot.squashfs— Compressed root filesystemcmdline— Kernel Command-Line for live boot
tar -C .build -xf baremetal-gardener_prod_pxe-amd64-today-local.pxe.tar.gzBuild Variants for PXE
The _pxe feature provides the core PXE boot capability (network boot with Ignition support). For disk installation, add either _install (manual/Ignition-triggered) or _autoinstall (automatic):
| Build Command | Features | Use Case |
|---|---|---|
./build baremetal-gardener_prod_pxe | _pxe | Live boot only (ephemeral, runs from RAM) |
./build baremetal-gardener_prod_pxe_install | _pxe, _install | Manual or Ignition-triggered installation |
./build baremetal-gardener_prod_pxe_autoinstall | _pxe, _autoinstall | Automatic installation to first disk |
The _autoinstall feature includes _install, so you get both automatic detection and the ability to manually run the installer.
Building PXE Images
For detailed build system documentation and building PXE images with custom features, see Building Images.
Create the iPXE Boot Script
Create an iPXE boot script that instructs iPXE to fetch the Garden Linux kernel, initramfs, and root filesystem. The kernel parameters differ depending on the deployment mode.
Live Boot Only (No Disk Installation)
For an ephemeral live boot without installing to disk:
cat > boot.ipxe <<'EOF'
#!ipxe
set base-url http://192.168.1.10:8080
kernel ${base-url}/vmlinuz initrd=rootfs.initrd \
gl.ovl=/:tmpfs \
gl.url=${base-url}/root.squashfs \
gl.live=1 \
ip=dhcp \
console=ttyS0,115200n8 console=tty0
initrd ${base-url}/initrd
boot
EOFThis boots Garden Linux from RAM without Ignition configuration. To add Ignition support for configuring users, SSH keys, or services while in live mode, add these kernel parameters:
ignition.firstboot=1 \
ignition.config.url=${base-url}/ignition.json \
ignition.platform.id=metalBoot + Install to Disk
Required Feature
Boot + install mode requires the _install or _autoinstall feature. If your PXE image was built without these features, the /opt/install/install.sh script will not be available.
For persistent installation to disk:
cat > boot.ipxe <<'EOF'
#!ipxe
set base-url http://192.168.1.10:8080
kernel ${base-url}/vmlinuz initrd=rootfs.initrd \
gl.ovl=/:tmpfs \
gl.url=${base-url}/root.squashfs \
gl.live=1 \
ip=dhcp \
console=ttyS1,115200n8 console=tty0 \
earlyprintk=ttyS1,115200n8 consoleblank=0 \
ignition.firstboot=1 \
ignition.config.url=${base-url}/ignition.json \
ignition.platform.id=metal
initrd ${base-url}/initrd
boot
EOFThis requires an Ignition configuration that triggers the built-in /opt/install/install.sh script. See Configure First-Boot Provisioning.
TIP
The cmdline file from the *.pxe.tar.gz archive contains many useful parameters and can be used as a reference when building custom boot scripts.
Kernel Parameters Explained
| Parameter | Live Boot | Boot + Install | Description |
|---|---|---|---|
gl.ovl=/:tmpfs | Required | Required | Use tmpfs as the upper layer for the OverlayFS root filesystem |
gl.url=<url> | Required | Required | URL to the compressed root filesystem image (root.squashfs) |
gl.live=1 | Required | Required | Enable live boot mode (system runs from OverlayFS during initial boot) |
ip=dhcp | Required | Required | Configure network interfaces via DHCP |
console=ttyS0 / ttyS1 | Recommended | Recommended | Output to serial console (use ttyS0 for live boot, ttyS1 for install) |
console=tty0 | Recommended | Recommended | Output to VGA console |
ignition.firstboot=1 | Optional | Required | Tell Ignition this is a first boot (Ignition only runs on first boot) |
ignition.config.url=<url> | Optional | Required | URL to the Ignition configuration file (.json format) |
ignition.platform.id=metal | Optional | Required | Platform identifier for Ignition (use metal for bare-metal deployments) |
Replace http://192.168.1.10:8080 with your HTTP server's address.
Configure First-Boot Provisioning
Garden Linux PXE deployments use Ignition for first-boot provisioning. The _pxe feature includes the _ignite feature, which provides Ignition support during the initramfs stage.
For cloud platform deployments, Garden Linux uses cloud-init instead. Both tools provide declarative system configuration including users, SSH keys, files, and services.
Ignition Configuration for Live Boot
For ephemeral live boot without disk installation, create an Ignition configuration with the desired system state (users, SSH keys, services):
---
variant: fcos
version: 1.3.0
passwd:
users:
- name: gardenlinux
groups:
- wheel
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExamplePublicKeyHere user@host
systemd:
units:
- name: ssh.service
enabled: trueTranslate the YAML to JSON using Butane and serve the resulting ignition.json file on your HTTP server.
For additional Ignition configuration examples including network configuration, package installation, and custom scripts, see Provision with Ignition.
Ignition Configuration for Boot + Install
Installation Support
Garden Linux PXE images require the _install or _autoinstall feature for disk installation. The _pxe feature alone provides only live boot capability.
To enable disk installation, build with one of:
_pxe+_install— Manual or Ignition-triggered installation_pxe+_autoinstall— Automatic installation (includes_install)
When _install is included, /opt/install/install.sh is available and can be used in three ways:
- Automatic with
_autoinstall: Build with features_pxeand_autoinstallfor automatic disk detection and installation - Semi-automatic via Ignition: Use Ignition to trigger
/opt/install/install.shwith specific target disk - Manual: SSH into the live system and run
/opt/install/install.shinteractively
The examples below show the semi-automatic approach using Ignition.
Installation Approaches
Approach 1: Automatic Installation (Recommended for Automation)
Build PXE with _autoinstall to automatically detect and install to the first suitable disk:
./build baremetal-gardener_prod_pxe_autoinstallThis builds a PXE image with both _pxe and _autoinstall features. Since _autoinstall includes _install, you also have access to manual installation via /opt/install/install.sh.
No Ignition configuration needed for installation - the system will automatically:
- Detect the first suitable block device
- Partition and format the disk
- Copy the system
- Install bootloader
- Reboot into the installed system
Approach 2: Ignition-Triggered Installation (Custom Configuration)
Required Feature
This approach requires the _install feature. Build with _pxe_install or _pxe_autoinstall:
./build baremetal-gardener_prod_pxe_installFor more control over the installation (specific target disk, custom partition layout), use Ignition to trigger the built-in installer.
Create an Ignition configuration that sets the target disk and triggers installation:
---
variant: fcos
version: 1.3.0
systemd:
units:
- name: install.service
enabled: true
contents: |
[Unit]
Description=Garden Linux Installation
ConditionFirstBoot=yes
After=local-fs.target network.target
[Service]
Type=oneshot
Environment="GL_INSTALL_TARGET=/dev/sda"
ExecStart=/opt/install/install.sh
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=multi-user.target
passwd:
users:
- name: gardenlinux
groups:
- wheel
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExamplePublicKeyHere user@hostConfiguration fields:
systemd.units.install.service— Systemd service that triggers installation on first bootEnvironment="GL_INSTALL_TARGET=/dev/sda"— Specifies the target disk for installation (change to match your disk:/dev/sda,/dev/nvme0n1, etc.)ExecStart=/opt/install/install.sh— Calls the built-in installer (provided by_installfeature)passwd.users— User accounts to create on the installed systemConditionFirstBoot=yes— Ensures installation only runs once
Target Disk Device Names
NVMe drives use the naming pattern /dev/nvme0n1, /dev/nvme1n1, etc. Virtio disks use /dev/vda, /dev/vdb, etc. SATA/SAS drives use /dev/sda, /dev/sdb, etc. Adjust the GL_INSTALL_TARGET value accordingly.
Customizing the Installation
The built-in installer (/opt/install/install.sh from the _install feature) uses default configurations that can be customized:
Default partition layout (/opt/install/install.part):
label: gpt
type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name="EFI", size=510MiB
type=4f68bce3-e8cd-4db1-96e7-fbcaf984b709, name="ROOT"INFO
The ROOT partition uses the x86-64 root partition GUID from the Discoverable Partitions Specification. For ARM64 systems, use b921b045-1df0-41c3-af44-4c6f280d3fae.
Default fstab (/opt/install/install.fstab):
LABEL=ROOT / ext4 errors=remount-ro 0 1
LABEL=EFI /boot/efi vfat umask=0077 0 1To customize these, you can either:
- Provide custom
install.partandinstall.fstabfiles via Ignition - Use a custom installation script served via Ignition (for advanced use cases)
Approach 3: Manual Installation
For interactive installation, boot the PXE system without installation configuration, then SSH in and run:
/opt/install/install.shThe script will prompt for the target disk and root password.
Built-in Installation Features
INFO
The installation script and features described below are only available when your PXE image is built with the _install or _autoinstall feature.
The /opt/install/install.sh script (provided by the _install feature) handles:
- Disk partitioning — Creates GPT partition table with EFI (100MiB) and ROOT partitions
- Filesystem formatting — Formats EFI as vfat and ROOT as ext4 with quota support
- System copying — Copies the live rootfs to the target disk using tar with xattrs
- Initrd rebuild — Regenerates initramfs without the
gardenlinux-livedracut module - Bootloader installation — Installs appropriate bootloader:
- UEFI: systemd-boot with Boot Loader Specification entries
- Legacy BIOS: syslinux with manual configuration
- Post-install marker — Creates
/.installedmarker file to prevent re-installation
When using _autoinstall, an additional wrapper script (/usr/local/sbin/gl-autoinstall) is provided that:
- Auto-detects the first suitable disk
- Exports
GL_INSTALL_TARGETand callsinstall.sh - Reboots into the installed system
Translate and Deploy
Translate the Ignition YAML file to JSON using Butane and deploy it to your HTTP server:
# Translate ignition.yaml to JSON
./butane --strict ignition.yaml > ignition.json
# Copy to HTTP server
cp ignition.json /var/www/pxe/The iPXE boot script references ignition.json via the ignition.config.url= kernel parameter.
Set Up Network Boot Infrastructure
Configure DHCP Server
Set up a DHCP server to provide PXE chainloading. Example using dnsmasq:
# Install dnsmasq
apt-get install dnsmasq
# Configure dnsmasq for PXE boot
cat > /etc/dnsmasq.d/pxe.conf <<'EOF'
# Enable DHCP
dhcp-range=192.168.1.100,192.168.1.200,12h
# 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
# BIOS clients: chainload to iPXE
dhcp-boot=tag:bios,undionly.kpxe,192.168.1.10
# UEFI clients: chainload to iPXE
dhcp-boot=tag:efi64,ipxe.efi,192.168.1.10
# iPXE clients: provide boot script URL
dhcp-match=set:ipxe,175
dhcp-boot=tag:ipxe,http://192.168.1.10:8080/boot.ipxe
EOF
# Restart dnsmasq
systemctl restart dnsmasqReplace 192.168.1.10 and other IPs to match your environment.
Configure TFTP Server
Set up a TFTP server to serve iPXE binaries. Example using tftpd-hpa:
# Install TFTP server
apt-get install tftpd-hpa
# Download iPXE binaries
cd /var/lib/tftpboot
curl -O https://boot.ipxe.org/undionly.kpxe
curl -O https://boot.ipxe.org/ipxe.efi
# Restart TFTP service
systemctl restart tftpd-hpaConfigure HTTP Server
Set up an HTTP server to host Garden Linux images and configuration files. Example using nginx:
# Install nginx
apt-get install nginx
# Create directory structure
mkdir -p /var/www/pxe
# Copy Garden Linux images
cp .build/{vmlinuz,initrd,root.squashfs} /var/www/pxe
# Copy configuration files
# For live boot:
cp boot.ipxe ignition.json /var/www/pxe
# For boot + install:
cp boot.ipxe ignition.json /var/www/pxe
# Configure nginx
cat > /etc/nginx/sites-available/pxe <<'EOF'
server {
listen 8080;
root /var/www/pxe;
autoindex on;
location / {
try_files $uri $uri/ =404;
}
}
EOF
ln -s /etc/nginx/sites-available/pxe /etc/nginx/sites-enabled/
systemctl reload nginxBoot the Target System
Live Boot Mode
- Configure BIOS/UEFI — Enable network boot in the firmware settings and set network boot as the first boot device
- Power on the system — The system boots via PXE and fetches the iPXE binary from TFTP
- iPXE loads — iPXE fetches
boot.ipxefrom the HTTP server and boots the Garden Linux kernel - Live system starts — The initramfs downloads
root.squashfsand mounts it as an OverlayFS - Ignition runs (if configured) — Fetches and applies the Ignition configuration
- System ready — Garden Linux runs from RAM; changes are ephemeral and lost on reboot
The system is now running in live mode. All changes are stored in tmpfs and will be lost on reboot.
Boot + Install Mode
- Configure BIOS/UEFI — Enable network boot in the firmware settings and set network boot as the first boot device
- Power on the system — The system boots via PXE and fetches the iPXE binary from TFTP
- iPXE loads — iPXE fetches
boot.ipxefrom the HTTP server and boots the Garden Linux kernel - Live system starts — The initramfs downloads
root.squashfsand mounts it as an OverlayFS - Ignition runs — Fetches and applies the Ignition configuration (partition layout, target disk, merged install configuration)
- Installation begins — The
install.servicesystemd unit partitions the disk, copies the live system to disk, and installs the bootloader - System transitions — System reboots into the installed system running from disk
- Subsequent boots — System boots directly from disk without PXE
The installation typically completes in 5-10 minutes depending on network speed and disk performance.
Post-Installation
After Live Boot
Live boot systems run entirely from RAM. Changes are ephemeral and lost on reboot or shutdown. To persist configuration:
- Switch to boot + install mode — Reboot with an iPXE boot script configured for installation (see Boot + Install to Disk)
- Manual installation — Log into the live system and manually partition, format, and install to disk
After Boot + Install
After installation, the system boots directly from disk without PXE. The dracut module responsible for live booting is disabled, and the installation tools remain available in /opt/install/ for reference.
System configuration tasks:
- Enable SSH — SSH is disabled by default. Enable it via Ignition (add
ssh.serviceto systemd units in yourignition.yaml) or manually after installation - Create users — Add users via Ignition in your
ignition.yaml(see example above) or create them manually after installation - Configure networking — Network configuration can be defined using Ignition with systemd-networkd configuration files (see Provision with Ignition)
- Advanced provisioning — For additional system configuration examples, see Provision with Ignition (bare-metal/PXE) or Provision with cloud-init (cloud platforms)
Troubleshooting
System Does Not Boot via PXE
- Verify network boot is enabled — Check BIOS/UEFI settings
- Check DHCP responses — Use
tcpdumpon the DHCP server to verify PXE DHCP responses:bashtcpdump -i eth0 -n port 67 and port 68 - Verify TFTP server accessibility — Test TFTP from another machine:bash
tftp 192.168.1.10 get undionly.kpxe
iPXE Fails to Download Files
- Check HTTP server logs — Verify requests are reaching the server:bash
tail -f /var/log/nginx/access.log - Test HTTP URLs manually — Verify files are accessible:bash
curl http://192.168.1.10:8080/boot.ipxe curl http://192.168.1.10:8080/rootfs.vmlinuz - Verify file permissions — Ensure files are readable by the web server
Ignition Configuration Not Applied
- Check Ignition logs — After booting the live system, check Ignition journal entries:bash
journalctl -u ignition-fetch.service journalctl -u ignition-files.service - Validate Ignition JSON syntax — Use Butane to validate the YAML before translation:bash
./butane --strict ignition.yaml > /dev/null - Verify ignition.config.url is reachable — Ensure the URL in
boot.ipxeis correct and accessible from the target system
Installation Fails or Does Not Start
For _autoinstall images:
- Check gl-autoinstall.service logs:bash
journalctl -u gl-autoinstall.service - Verify disk auto-detection — Check which disk was detected:bash
lsblk - Override disk detection — Pass
gl.install.target=/dev/sdXas kernel parameter
For Ignition-triggered installation:
- Check install.service logs:bash
journalctl -u install.service - Verify target disk exists — Check that the disk specified in
GL_INSTALL_TARGETexists:bashlsblk echo $GL_INSTALL_TARGET - Check install script — Manually run the installer to see detailed output:bash
GL_INSTALL_TARGET=/dev/sda /opt/install/install.sh
System Boots Back to PXE After Installation
- UEFI boot order not updated — The installation should update the UEFI boot order. If it does not, manually set the disk as the first boot device in firmware settings
- Bootloader installation failed — Check installation logs for bootloader errors
Testing PXE Boot in QEMU
The Garden Linux test framework supports testing PXE boot scenarios using QEMU. This is useful for validating PXE installations without physical hardware or a full network boot infrastructure.
Test PXE Live Boot
Test a PXE archive in live boot mode (no installation):
./test .build/baremetal-gardener_prod_pxe-amd64-*.pxe.tar.gzINFO
This tests live boot mode only. The system runs from RAM and no disk installation occurs. To test disk installation, see the next section.
The test script automatically:
- Extracts the PXE archive (
vmlinuz,initrd,root.squashfs,cmdline) - Sets up a local HTTP server to serve the PXE files
- Creates an iPXE boot script for live boot
- Boots QEMU via network boot using iPXE
- Runs the test suite on the live system
Test PXE Installation with _autoinstall Feature
To test PXE boot + installation to disk, build the image with the _autoinstall feature:
./build baremetal-gardener_prod_pxe_autoinstallThen test the installation:
./test .build/baremetal-gardener_prod_pxe_autoinstall-amd64-*.pxe.tar.gzThe test framework automatically detects the _autoinstall feature (via the .requirements file) and triggers a two-stage workflow:
- Stage 1 — Boot via PXE, install to disk using
gl-autoinstall.service, reboot - Stage 2 — Boot from installed disk, run tests on the installed system
The test script automatically:
- Extracts the PXE archive
- Detects
autoinstall=truein the.requirementsfile - Creates a 4G target disk for installation
- Sets up the HTTP server to serve PXE files
- Boots QEMU via network boot —
gl-autoinstall.serviceruns and installs automatically - Waits for installation to complete and system to power off
- Starts a second QEMU instance booting from the installed disk
- Runs the test suite on the installed system
This workflow allows testing the complete PXE boot + installation process without requiring a full PXE infrastructure setup.
Reference
- iPXE Documentation
- iPXE Chainloading Guide
- Ignition Documentation
- Butane Documentation
- systemd-boot Documentation
- Syslinux Documentation