cproudlock ead3314f58 Two-NIC standard: pin imaging and GE NICs by MAC everywhere
Every server has an imaging NIC (static, the only one that serves
DHCP/TFTP/HTTP boot/SMB) and a GE corporate NIC (DHCP client, SSH and the
webapp on 9009). The playbook guessed the PXE NIC and the installer put
172.16.9.1/24 on every en* NIC, so a two-NIC box could answer on the GE
network.

- New per-site vars pxe_nic_mac / corp_nic_mac (required, from
  playbook/site-vars.yml or -e; template site-vars.example.yml), stable
  names pxe_nic_name / corp_nic_name (default pxe0 / corp0, overridable),
  pxe_server_ip, pxe_subnet, DHCP range. pxe_imaging_mac / pxe_ge_mac are
  derived from them. The play stops before touching anything if a MAC is
  unset, malformed, duplicated or not on the box (lists the box's NICs).
- Heuristic NIC detection and the single-NIC netplan task replaced by a
  two-NIC netplan template (match macaddress + set-name), installed by
  pxe-netplan-apply.sh: validate in a scratch root, back up, generate,
  rename, apply, restore the previous config on any failure. cloud-init
  network config disabled so it cannot rewrite it.
- dnsmasq: /etc/dnsmasq.d/pxe-nic-only.conf from the vars (interface=,
  except-interface=, no-dhcp-interface=); dnsmasq.conf IP/range from vars.
- UFW per interface: imaging NIC 22, 67/udp, 69/udp, 80, 4433, 445, 139,
  137/udp, 138/udp, 9009; GE NIC 22 and 9009 only. Old any-interface rules
  and the stale 9011 rule removed after the new ones are in.
- sysctl drop-in: IPv4/IPv6 forwarding off; ip_nonlocal_bind so Apache
  can bind the imaging IP before the address is up.
- Samba [global]: interfaces = 127.0.0.0/8 <imaging NIC>, bind interfaces
  only. Apache 80 and 4433 on the imaging IP only; 9009 stays on all (TODO:
  the webapp has no auth).
- autoinstall: DHCP only on en*, no static 172.16.9.1; apt geoip off and
  offline-install fallback now that the corp NIC may have a lease.
- Blancco UEFI/Secure Boot: blancco_kver (7.0.0-34-generic) drives the
  kernel, initramfs and modules builds instead of the running kernel;
  outputs vmlinuz-ubuntu-70, kexec-initrd-70.img, kmod-<kver>.tar.gz as the
  menu and blancco-init.sh expect; creates: guards keyed on the full kver.
  Ubuntu's shimx64.efi.signed published as blancco/shimx64.efi.
  download-packages.sh adds shim-signed, linux-generic-hwe-24.04 and the
  pinned linux-image/modules/modules-extra for BLANCCO_KVER.

Rendered with the live MACs and names, netplan generate output is
identical to the live config; pxe-nic-only.conf and the Samba binding
match live directive for directive.
2026-10-15 08:53:41 -04:00

GE Aerospace PXE Boot Server

Automated, air-gapped PXE boot server for deploying GE Aerospace Windows images. Built on Ubuntu 24.04 Server with zero-touch provisioning via autoinstall and Ansible.

Overview

This project provides a complete, repeatable build process for a PXE boot server that serves Windows PE images to client machines on an isolated network. Everything runs offline after initial setup — no internet required on the target server.

Boot Chain

Client PXE boot (UEFI Secure Boot)
  -> iPXE (TFTP, Broadcom-signed for Secure Boot)
  -> iPXE boot menu (HTTP, port 4433)
  -> User selects boot option:
     ├── Windows PE  -> wimboot -> boot.wim -> startnet.cmd -> Samba share -> Image deployment
     ├── Clonezilla  -> vmlinuz/initrd -> Disk cloning/imaging
     ├── Blancco     -> Native kernel + initramfs -> NIST 800-88 drive erasure
     └── Memtest86+  -> Memory diagnostics

Services

Service Port Purpose
dnsmasq 67/udp DHCP (172.16.9.10-100, 12h lease)
dnsmasq 69/udp TFTP (serves ipxe.efi)
Apache 80/tcp HTTP (wimboot, WinPE boot files, proxy)
Apache 4433/tcp iPXE boot script (GetPxeScript.aspx)
Samba 445/tcp Deployment content + Clonezilla + Blancco
Flask Webapp 9009/tcp Web management interface

Network

  • PXE server IP: 172.16.9.1/24
  • DHCP range: 172.16.9.10 - 172.16.9.100
  • Firewall: UFW deny-by-default, only service ports open (22, 67, 69, 80, 445, 4433, 9009)

Quick Start

Prerequisites

On your workstation (internet-connected):

  • Ubuntu 24.04 (or Linux Mint / similar) for downloading packages
  • Ubuntu Server 24.04 ISO
  • GE Aerospace Media Creator LITE (for WinPE images)
  • USB drive >= 8 GB (32+ GB if bundling WinPE images)

GE Access Packages (MyAccess portal):

  • EPM Rufus Exception Request
  • EPM DT Functions
  • DLP - Encrypted Removable (USB) Long Term Access

Step 1: Download Offline Packages

./scripts/download-packages.sh
./scripts/fetch-ipxe.sh

fetch-ipxe.sh downloads the Secure Boot iPXE chain into boot-files/, pinned by sha256: the iPXE release tarball (its snponly build becomes ipxe.efi) and iPXE's dual-signed shim (Microsoft UEFI CA 2011 + 2023), which every UEFI client boots as ipxe-shim.efi. Keep the old Broadcom-signed boot-files/ipxe.efi too: the playbook installs it as ipxe-bcm.efi, the rollback boot file.

Downloads all .deb packages and Python wheels for offline installation (~140 MB of debs, ~20 MB of wheels).

Step 2: Prepare Boot Tools (optional)

./scripts/prepare-boot-tools.sh /path/to/blancco.iso /path/to/clonezilla.zip /path/to/memtest.bin

Extracts and configures boot tool files (Blancco, Clonezilla, Memtest86+). Automatically patches Blancco's config.img to auto-save erasure reports to the PXE server's Samba share.

Step 3: Build the USB

sudo ./scripts/build-usb.sh /dev/sdX /path/to/ubuntu-24.04-live-server-amd64.iso

Creates a bootable USB with two partitions:

  • Partition 1: Ubuntu Server installer
  • Partition 2: CIDATA (autoinstall config, offline .debs, pip wheels, Ansible playbook, webapp, boot tools)

Step 4: Install on Target Server

  1. Insert USB into the target machine
  2. Press F12 and boot from USB
  3. Ubuntu auto-installs with no interaction
  4. After reboot, the first-boot script:
    • Installs all offline .deb packages
    • Runs the Ansible playbook (configures dnsmasq, Apache, Samba, UFW, webapp)
    • Configures static IP 172.16.9.1/24
  5. Move the server's wired NIC to the isolated PXE switch

Step 5: Access the Web Interface

Open http://172.16.9.1:9009 from any machine on the isolated network.

Web Management Interface

The Flask webapp (port 9009) provides a browser-based management UI:

  • Dashboard — Service status overview, disk usage, connected DHCP clients
  • Image Import — Import WinPE deployment images from USB drives
  • Unattend Editor — Edit Windows unattend.xml files per image type (XML syntax highlighting)
  • startnet.cmd Editor — Modify the startnet.cmd inside boot.wim without Windows (uses wimtools)
  • Clonezilla Backups — Upload, download, and manage disk backup images
  • Blancco Reports — View, download, and manage drive erasure reports (auto-collected via Samba)
  • Image Config — Per-image configuration editor (drivers, OS packages, hardware models)
  • Enrollment — Upload, download, and manage GCCH bulk enrollment packages
  • Audit Log — Activity history for all write operations (imports, edits, deletes)

Image Types Supported

Image Type Domain Description
gea-standard geaerospace.com Standard desktop
gea-engineer geaerospace.com Engineering desktop
gea-shopfloor geaerospace.com Shop floor kiosk
ge-standard ge.com Standard desktop
ge-engineer ge.com Engineering desktop
ge-shopfloor-lockdown ge.com Shop floor (locked)
ge-shopfloor-mce ge.com Shop floor (MCE)

Project Structure

pxe-server/
├── autoinstall/
│   ├── user-data                 # Cloud-init autoinstall config + first-boot script
│   └── meta-data                 # Cloud-init metadata (required, empty)
├── playbook/
│   ├── pxe_server_setup.yml      # Ansible playbook: all server configuration
│   ├── inventory.ini             # Ansible inventory
│   ├── startnet.cmd              # WinPE startup script (injected into boot.wim)
│   ├── blancco-init.sh           # Custom initramfs for Blancco PXE boot
│   ├── blancco-preferences.xml   # Blancco auto-report preferences
│   ├── check-bios.cmd            # Pre-imaging BIOS update checker
│   ├── FlatUnattendW10-shopfloor.xml  # Shopfloor unattend.xml
│   └── shopfloor-setup/          # PC type setup scripts (Standard, CMM, Display, etc.)
├── webapp/
│   ├── app.py                    # Flask application (~1600 lines)
│   ├── requirements.txt          # Python deps (flask, lxml)
│   ├── static/
│   │   ├── ge-aerospace-logo.svg # GE Aerospace branding
│   │   ├── favicon.ico           # Browser favicon
│   │   ├── app.js                # Frontend JavaScript
│   │   ├── bootstrap.min.css     # Bootstrap 5 (bundled offline)
│   │   ├── bootstrap.bundle.min.js
│   │   ├── bootstrap-icons.min.css
│   │   └── fonts/                # Icon fonts (woff/woff2)
│   └── templates/
│       ├── base.html             # Layout with GE branding and sidebar nav
│       ├── dashboard.html        # Service status and overview
│       ├── import.html           # USB image import wizard
│       ├── unattend_editor.html  # XML editor for unattend files
│       ├── startnet_editor.html  # startnet.cmd WIM editor
│       ├── image_config.html     # Per-image driver and hardware config
│       ├── enrollment.html       # GCCH bulk enrollment packages
│       ├── backups.html          # Clonezilla backup management
│       ├── reports.html          # Blancco erasure reports
│       └── audit.html            # Activity audit log
├── docs/
│   └── shopfloor-display-imaging-guide.md  # End-user imaging guide
├── boot-tools/                   # Extracted boot tool files (gitignored)
│   ├── blancco/                  # Blancco Drive Eraser
│   ├── clonezilla/               # Clonezilla Live
│   └── memtest/                  # Memtest86+
├── boot-files/                   # WinPE boot files (boot.wim, wimboot, ipxe.efi, BCD)
├── offline-packages/             # .deb files (gitignored, built by download-packages.sh)
├── pip-wheels/                   # Python wheels (gitignored, built by download-packages.sh)
├── enrollment/                   # PPKGs and run-enrollment.ps1 (gitignored)
├── bios-staging/                 # Dell BIOS update binaries (gitignored)
├── scripts/                      # Build, deploy, and helper scripts
│   ├── build-usb.sh              # Builds the installer USB (2-partition)
│   ├── build-proxmox-iso.sh      # Builds self-contained Proxmox installer ISO
│   ├── prepare-boot-tools.sh     # Extracts and patches boot tool files
│   ├── download-packages.sh      # Downloads offline .debs + pip wheels
│   ├── download-drivers.py       # Downloads Dell drivers directly from dell.com
│   ├── deploy-bios.sh            # Pushes BIOS updates to enrollment share
│   ├── pull-bios.sh              # Pulls BIOS binaries from upstream cache
│   ├── sync_hardware_models.py   # Syncs hardware model configs across images
│   ├── Upload-Image.ps1          # Windows: upload MCL cache to PXE via SMB
│   └── Download-Drivers.ps1      # Windows: download hardware drivers from GE CDN
├── config/                       # Site-specific configuration overrides
├── startnet-template.cmd         # startnet.cmd template (synced with playbook copy)
├── README.md                     # This file
└── SETUP.md                      # Detailed setup guide

Proxmox Deployment

A single ISO can be built for deploying the PXE server in a Proxmox VM:

Build the ISO

# Prerequisites (on build workstation)
sudo apt install xorriso p7zip-full

# Build the installer ISO
./scripts/build-proxmox-iso.sh /path/to/ubuntu-24.04-live-server-amd64.iso

This creates pxe-server-proxmox.iso containing the Ubuntu installer, autoinstall config, all offline packages, the Ansible playbook, webapp, and boot tools.

Deploy on Proxmox

  1. Upload pxe-server-proxmox.iso to Proxmox storage (Datacenter -> Storage -> ISO Images)
  2. Create a new VM:
    • OS: Linux 6.x kernel
    • BIOS: OVMF (UEFI) or SeaBIOS
    • Memory: 4096 MB
    • CPU: 2+ cores
    • Disk: 40+ GB (VirtIO SCSI)
    • Network: Bridge connected to your isolated PXE network
  3. Attach the ISO as CD-ROM and start the VM
  4. Ubuntu auto-installs with zero interaction (~10-15 minutes)
  5. After reboot, first-boot configures all PXE services automatically
  6. Access the web interface at http://172.16.9.1:9009

Import WinPE Images

After the server is running, import deployment images via the web interface at http://172.16.9.1:9009/import or by mounting a USB drive with WinPE content.

Samba Shares

Share Path Purpose
winpeapps /srv/samba/winpeapps WinPE deployment images
clonezilla /srv/samba/clonezilla Clonezilla disk backup images
blancco-reports /srv/samba/blancco-reports Blancco erasure reports (auto)
enrollment /srv/samba/enrollment GCCH bulk enrollment packages
image-upload /home/pxe/image-upload Image upload staging area

All shares use guest access (no authentication) for ease of use on the isolated network.

Blancco Drive Erasure

Blancco Drive Eraser 7.15.1 boots via a native Ubuntu kernel with a custom initramfs (blancco-init.sh) that downloads and mounts the Blancco rootfs over HTTP. XML erasure reports are automatically saved to the PXE server's Samba share (blancco-reports). The server supports BMC cloud licensing for Blancco activation over WiFi.

Reports are viewable and downloadable from the web interface at http://172.16.9.1:9009/reports.

Notes

  • Run download-packages.sh before building USB — it downloads all offline .deb packages including wimtools (needed for startnet.cmd editing)
  • The webapp uses session-based CSRF tokens on all POST forms and API endpoints

Commit History

Commit Description
5791bd1 Initial project setup: automated PXE server provisioning
cee4ecd Add web management UI, offline packages, WinPE consolidation
f614596 Fix unattend.xml path to match actual image structure
e7313c2 Add multi-boot PXE menu, Clonezilla backups, GE Aerospace branding
89b5834 Add wimtools and startnet.cmd editor for boot.wim modification
05dbb7e Add Blancco erasure reports Samba share and webapp viewer
ef75839 Auto-patch Blancco config.img for network report storage
92c9b0f Fix review findings: offline assets, security, audit logging
725c8f4 Change webapp to port 9009, add test VM script
f3a384f Add Proxmox ISO builder, CSRF protection, boot-files integration
1a5c4f7 Eliminate USB requirement for WinPE PXE boot
dd2fec5 Blancco PXE boot via Ubuntu kernel switch_root
86660a0 Remove UEFI HTTP Boot config from dnsmasq
6d0e6ee BIOS check fix, parallel downloads, shopfloor hardening
7616549 Shopfloor PC type system, webapp enhancements
b7cd097 Blancco 7.15.1 upgrade: native kernel boot, BMC cloud licensing
163e58a Fix dnsmasq reboot cron: use /etc/cron.d/ instead of crontab
Description
PXE Boot Server Setup - Automated Ubuntu PXE server for deploying GE Aerospace Windows images
Readme 150 MiB
Languages
PowerShell 56.4%
Python 14.4%
Shell 10.7%
HTML 10%
Batchfile 6.1%
Other 2.4%