Skip to content

elfshoe - Reference

Command-Line Tools

elfshoe

The elfshoe command generates iPXE boot menu scripts from YAML configuration files.

Command Line Usage

# Generate menu with validation (recommended)
elfshoe

# Fast generation (no validation)
elfshoe --skip-validation

# Custom config and output files
elfshoe -c custom-config.yaml -o custom-elfshoe.ipxe

# Quiet mode (no output unless errors)
elfshoe --quiet

# Show help
elfshoe --help

Command Options

  • -c, --config FILE - Path to config file (default: config.yaml)
  • -o, --output FILE - Output file path (default: elfshoe.ipxe)
  • --skip-validation - Skip URL validation for faster generation
  • --quiet - Quiet mode, only show errors
  • --help - Show help message

Command Line Options

elfshoe [OPTIONS]

Options:
  -c, --config FILE     Configuration file (default: config.yaml)
  -o, --output FILE     Output file (default: elfshoe.ipxe)
  --no-validate         Skip URL validation (faster)
  --quiet              Minimal output
  --help               Show help message

ipxelint

The ipxelint tool validates iPXE scripts for syntax errors and common mistakes.

Basic Usage

# Validate a single file
ipxelint elfshoe.ipxe

# Validate multiple files
ipxelint *.ipxe

# Treat warnings as errors (CI-friendly)
ipxelint --strict elfshoe.ipxe

# Only show errors
ipxelint --quiet elfshoe.ipxe

What It Checks

  • Shebang: Ensures script starts with #!ipxe
  • Menu balance: Warns if menu/choose statements are unbalanced
  • Label references: Detects undefined label references in goto statements
  • Command syntax: Warns about unknown or potentially misspelled commands

Exit Codes

  • 0: All files passed validation
  • 1: At least one file had errors (or warnings with --strict)

Example Output

✓ elfshoe.ipxe: OK

⚠️  custom.ipxe: WARNINGS
  Line 12: Unknown or potentially misspelled command: 'slepe'

❌ broken.ipxe: FAILED
  Line 1: Missing or invalid #!ipxe shebang
  Line 15: Reference to undefined label: 'non_existent'

Command Line Options Full Reference

-c, --config FILE      # Config file (default: config.yaml)
-o, --output FILE      # Output file (default: elfshoe.ipxe)
--no-validate          # Skip URL validation (faster)
-q, --quiet            # Minimal output
--version              # Show version
  -h, --help             # Show help

Configuration File Structure

menu:
  title: "Your Menu Title"
  default_item: "distribution_menu"
  timeout: 30000        # Menu timeout (ms)
  error_timeout: 30000  # Error display timeout (ms)

distributions:
  distro_name:
    enabled: true|false
    label: "Display Label"
    type: "static"|"dynamic"

    # Architecture support (optional)
    arch_map:
      arm64: aarch64      # Map iPXE arch names to distro arch names
      x86_64: x86_64

    # For static type:
    versions:
      - version: "X"
        name: "Release Name"  # Optional
        architectures: [x86_64, arm64]  # Optional: per-version control

    # For dynamic type:
    metadata_provider: "provider_name"  # e.g., "fedora"
    metadata_url: "https://..."
    metadata_filter:
      variant: "Server"
      architectures: [x86_64, aarch64]  # Filter for specific architectures
      latest: 3           # Optional: limit to N latest versions

    # Common fields:
    url_template: "http://example.com/{version}/{arch}/path"  # Use {arch} placeholder
    boot_files:
      kernel: "path/to/vmlinuz"
      initrd: "path/to/initrd.img"
    boot_params: "kernel_params_here"

additional_items:
  - id: "unique_id"
    label: "Display Label"
    type: "chain"|"shell"|"exit"
    url: "http://..."  # for chain type only

URL Templates

Use {version} and {arch} placeholders in URL templates:

# Fedora with architecture support
url_template: "http://download.fedoraproject.org/pub/fedora/linux/releases/{version}/Server/{arch}/os"

# CentOS Stream with architecture
url_template: "http://mirror.stream.centos.org/{version}-stream/BaseOS/{arch}/os"

# Debian with architecture
url_template: "http://deb.debian.org/debian/dists/{version}/main/installer-{arch}/current/images/netboot/debian-installer/{arch}"

Architecture Support

Overview

elfshoe supports multiple CPU architectures with automatic client filtering:

  • x86_64 - 64-bit x86 (most servers and desktops)
  • arm64 - 64-bit ARM (Raspberry Pi 4, Apple Silicon, AWS Graviton)
  • i386 - 32-bit x86 (legacy systems)
  • arm - 32-bit ARM (older embedded devices)

Architecture Name Mapping

Different distributions use different architecture names. Use arch_map to translate:

distributions:
  fedora:
    arch_map:
      arm64: aarch64  # iPXE calls it arm64, Fedora calls it aarch64
      x86_64: x86_64

  debian:
    arch_map:
      x86_64: amd64   # iPXE calls it x86_64, Debian calls it amd64
      arm64: arm64

Common mappings:

iPXE Name Fedora/RHEL Debian/Ubuntu
x86_64 x86_64 amd64
arm64 aarch64 arm64
i386 i386 i386
arm armhfp armhf

Dynamic Distributions (Metadata-Driven)

For Fedora and other distributions with metadata providers:

fedora:
  type: dynamic
  metadata_filter:
    variant: Server
    architectures: [x86_64, aarch64]  # ← Filter metadata
    latest: 3
  arch_map:
    arm64: aarch64
  url_template: "https://.../{version}/Server/{arch}/os"

Behavior:

  • Fetches metadata for specified architectures
  • Only includes versions that exist in metadata
  • Validates URLs for each architecture
  • Skips architectures not available in metadata

Static Distributions (Manual Configuration)

For distributions without metadata providers:

debian:
  type: static
  arch_map:
    x86_64: amd64
  versions:
    - version: "bookworm"
      name: "12 Bookworm"
      architectures: [x86_64, arm64]  # ← Per-version control
    - version: "bullseye"
      name: "11 Bullseye"
      architectures: [x86_64]  # Only x86_64 for this version

Behavior:

  • You specify which architectures each version supports
  • Can vary architectures per version
  • Validates URLs for each specified architecture

Client-Side Filtering

Generated menus use iseq ${buildarch} to filter items:

menu Fedora - Select Version
iseq ${buildarch} x86_64 && item fedora_43_x86_64 Fedora 43 Server (x86_64) ||
iseq ${buildarch} arm64 && item fedora_43_arm64 Fedora 43 Server (aarch64) ||

Result:

  • x86_64 clients only see x86_64 menu items
  • ARM64 clients only see ARM64 menu items
  • No manual selection needed
  • No wrong architecture served

Single Architecture (Default)

If you don't specify architectures, defaults to x86_64 only:

centos:
  type: static
  versions:
    - version: "9"
  url_template: "http://mirror.centos.org/{version}/BaseOS/x86_64/os"

This is backward compatible with existing configurations.

Boot Parameters

Use {base_url} in boot parameters:

# Repository installation
boot_params: "inst.repo={base_url}/"

# Network configuration
boot_params: "ip=dhcp inst.repo={base_url}/"

# Text mode
boot_params: "inst.text inst.repo={base_url}/"

Command-Line Options

-c, --config FILE      # Config file (default: config.yaml)
-o, --output FILE      # Output file (default: elfshoe.ipxe)
--no-validate          # Skip URL validation (faster)
-q, --quiet            # Minimal output
--version              # Show version
-h, --help             # Show help

File Locations

Project Root/
├── config.yaml              # Main configuration (see docs/examples/config.yaml)
├── elfshoe.ipxe             # Generated menu (output)
├── docs/
│   └── examples/
│       ├── config.yaml      # Complete example with all features
│       └── 99-dnsmasq-pxe-ipxe.conf  # dnsmasq config example
├── src/elfshoe/             # Package source
│   ├── core/                # Core components
│   ├── distributions/       # Distribution plugins
│   └── templates/           # Jinja2 templates
└── tests/                   # Test suite

Adding a Distribution

Static (Simple)

Add to config.yaml:

distributions:
  mylinux:
    enabled: true
    type: "static"
    label: "My Linux"
    versions:
      - version: "1.0"
        label: "My Linux 1.0"
    url_template: "http://mirror.example.com/{version}/os"
    boot_files:
      kernel: "vmlinuz"
      initrd: "initrd.img"
    boot_params: ""

Dynamic Distribution (Automatic Version Detection)

For distributions like Fedora that support automatic version detection:

distributions:
  fedora:
    enabled: true
    type: "dynamic"
    label: "Fedora"
    metadata_provider: "fedora"
    metadata_url: "https://fedoraproject.org/releases.json"
    metadata_filter:
      variant: "Server"
      architectures: [x86_64, aarch64]
      latest: 3  # Only show 3 most recent versions
    arch_map:
      arm64: aarch64  # Map iPXE arm64 to Fedora aarch64
    url_template: "http://download.fedoraproject.org/pub/fedora/linux/releases/{version}/Server/{arch}/os"
    boot_files:
      kernel: "images/pxeboot/vmlinuz"
      initrd: "images/pxeboot/initrd.img"
    boot_params: "inst.repo={base_url}/"

Note: To add custom metadata providers, see the Adding Distributions guide.

Troubleshooting

# Skip URL validation for faster generation (development mode)
elfshoe --skip-validation
# or
elfshoe --no-validate

Tip: Use validation in production to catch broken URLs, but skip it during development/testing.

# Run with validation to see which URLs are failing
elfshoe

# Test specific URL manually
curl -I http://your-mirror-url/vmlinuz

Boot Files Not Found (404 errors)

  • Check that the url_template is correct for your mirror
  • Verify boot_files paths match your distribution's file structure
  • Test the full URL: {url_template}/{kernel_path}
  • Try a different mirror if the current one is down

iPXE Shows "No Such File"

This usually means:

  1. The URL in the generated menu is incorrect
  2. The web server hosting the files is not accessible from the client
  3. The file paths in boot_files don't match the actual file locations

Solutions:

# Regenerate menu with validation to check URLs
elfshoe

# Verify your web server can serve the files
curl http://your-server/path/to/vmlinuz

# Check the generated elfshoe.ipxe file for correct URLs
cat elfshoe.ipxe | grep -A5 "boot_fedora"

Performance

  • With validation: 30-45 seconds (checks all URLs exist)
  • Without validation: <1 second (generates menu only)
  • Recommendation: Use validation before deploying to production

Version Detection

Fedora (Dynamic)

  • Fetches versions from: https://fedoraproject.org/releases.json
  • Filters by: variant=Server, arch=x86_64
  • Returns: Latest 3-5 supported versions automatically

Other Distributions

  • CentOS, Debian, Rocky: Use static version lists
  • Custom distributions: Can add dynamic metadata providers (see contributor docs)

iPXE Boot Process

How It Works

  1. Client machine boots via PXE
  2. DHCP server provides iPXE binary location
  3. iPXE loads and fetches elfshoe.ipxe from your web server
  4. User selects OS from menu
  5. iPXE downloads kernel and initrd
  6. Boot proceeds with specified parameters

Generated Menu Structure

#!ipxe

:start
menu Network Boot Menu
item fedora_38 Fedora 38 Server
choose selected
goto ${selected}

:fedora_38
echo Booting Fedora 38 Server...
initrd http://mirror/fedora/38/images/pxeboot/initrd.img || goto error
kernel http://mirror/fedora/38/images/pxeboot/vmlinuz initrd=initrd.img inst.repo=http://mirror/fedora/38/ || goto error
boot

:error
echo Boot failed!
prompt --timeout ${error_timeout}
goto start

Boot Parameters

Common parameters you can add to boot_params:

  • Fedora/RHEL: inst.repo={base_url}/ inst.ks=http://server/kickstart.cfg
  • Debian/Ubuntu: auto=true url=http://server/preseed.cfg
  • Generic: console=ttyS0,115200 (for serial console)

Supported File Types

  • Kernel: vmlinuz, linux, bzImage
  • Initrd: initrd.img, initrd.gz, initramfs