Files
pxe-server/docs/ARCHITECTURE.md
cproudlock 04db6d6605 Generic build for other GE sites: no WJ data, one shopfloor type, Windows USB builder
Everything West Jefferson specific moved out to a separate repo
(pxe-site-wj): NTLARS/UDC/heat-treat backups keyed by WJ machine numbers,
CMM and Wax/Trace bay lists, WJ OpenText profiles, site-config.json, the
WJ preinstall list, and the WJ shopfloor PC types (Collections,
NoCollections, Common, Keyence, CMM, Genspect, HeatTreat, Wax/Trace,
Display, PartMarker) with GE-Enforce, machine numbers and the desktop
layout. The part-marker bench tools moved to their own repo. Dead
scripts removed: build-proxmox-iso, deploy-bios, sync_hardware_models,
mirror-from-gold, pull-bios, startnet-template.cmd.

Shopfloor is one generic type, gea-shopfloor-standard, with today's
timing:
- PPKG at first logon (unattend Order 10, unchanged).
- Install-AppList.ps1 runs C:\PreInstall\preinstall.json during setup.
- A new SYSTEM task, GE Shopfloor Post-PPKG, runs postppkg.json once
  after the post-PPKG reboot. It also clears AutoLogonCount after the
  ShopFloor handover (the Users-level monitor can be denied that HKLM
  write) and removes the Intune Sync task when done.
- Both lists ship empty. A site adds entries and installers.
- WinPE choice 3 goes straight to the PPKG menu. Staging, fetch and heal
  carry only the generic payload. The webapp's shopfloor sub-menu editor
  is gone, and the imaging tiles name the new stages.
- The playbook deploys the empty lists only if missing. It now deploys
  the PowerShell 7 MSI the shopfloor unattend installs, which it never
  did before.

Blancco site settings move into the webapp (Updates > Blancco releases):
business location, licensing Wi-Fi SSID and password. They are rendered
into the served preferences.xml and applied to every staged release, and
are seeded from site-vars (site_name, blancco_wifi_ssid,
blancco_wifi_password) only while none exist. The repo XML carries no
site values; the plaintext Wi-Fi password is gone from it.

New site_name and site_timezone settings: report and evidence-pack site
name, server clock and webapp time zone. No more West Jefferson defaults
in webapp/config.py or the dashboard title. Sync-BPRT.ps1 gets the
server address filled in at download instead of WJ's GE address.

USB on Windows:
- scripts/Build-PxeUsb.ps1 runs the same checks as build-usb.sh. It
  writes one FAT32 CIDATA partition (ISO files plus patched grub.cfg plus
  payload) with diskpart and reads every file back by SHA-256.
- Tested with Windows PowerShell 5.1 in the win11 VM, and the layout
  installs and first-boots in the pxetest VM.
- scripts/stage-usb-share.sh stages the build folder on a share.
- site-content/ is optional for both builders.

KB docs/kb/How_To_Deploy_PXE_Server_New_Site.html: new-site deployment,
Windows only, with a site-vars.yml guide.

Checks: webapp tests pass (5 suites); the unattend lint and playbook
syntax checks pass; every .ps1 parses; there are no WJ hosts, IPs, names
or PC types in playbook/, webapp/, scripts/ or autoinstall/.
2026-10-16 20:37:22 -04:00

216 lines
11 KiB
Markdown

# PXE Server Architecture
This document describes the moving parts of the PXE server, the boot chain a
client follows, and how data flows between the server, clients, and external
systems.
## Hardware and host OS
- Single physical host (or VM) with at minimum 4 GB RAM, 4 CPU cores, and one
network interface attached to the isolated PXE LAN.
- Disk: 232 GB minimum if you stay slim (Dell_11 only, no Latitude); 500 GB
recommended for a full mirror; 2 TB+ recommended for headroom across all
driver sets and OS image variants.
- OS: Ubuntu Server 24.04 LTS (Noble), installed unattended via the autoinstall
USB built by `scripts/build-usb.sh`.
## Network layout
- PXE server static IP: `172.16.9.1/24` on an isolated subnet.
- DHCP range served by dnsmasq: `172.16.9.10 - 172.16.9.100`, 12h leases.
- Default gateway and DNS handed out via DHCP point at the PXE server itself.
- The subnet has no route to the corporate LAN. Client traffic (Blancco BMC
cloud, Intune enrollment) goes out via WiFi after Windows boots; PXE-time
traffic stays on the isolated LAN.
## Services on the PXE server
| Service | Port | Role |
|---------------|-----------|------------------------------------------------------|
| dnsmasq | 67/udp | DHCP. Hands out IPs and the next-server (TFTP) info. |
| dnsmasq | 69/udp | TFTP. Serves `ipxe.efi` to firmware PXE clients. |
| Apache | 80/tcp | HTTP. Serves wimboot, boot.wim, Blancco binaries, Clonezilla, and proxies the webapp on /. |
| Apache | 4433/tcp | HTTP. Serves `Altiris/iPXE/GetPxeScript.aspx` (the iPXE menu script). |
| Samba | 445/tcp | SMB shares. WinPE mounts these to fetch image content during deployment. |
| Flask webapp | 9009/tcp | Browser UI for image import, unattend editing, log/report viewing. |
`/etc/cron.d/dnsmasq-restart` restarts dnsmasq 15 seconds after every reboot to
work around a systemd-resolved race condition that can prevent dnsmasq from
binding to the PXE interface on cold boot.
`/etc/cron.d/media-tag-refresh` touches `Media.tag` in every image's
`Deploy/Control/` directory daily and on reboot. Without this, the WinPE
deployment loader stops finding the image after 30 days.
## Samba shares
| Share | Filesystem path | Purpose |
|------------------|-----------------------------|--------------------------------------------------------------|
| winpeapps | /srv/samba/winpeapps | Per-image-type Deploy/ trees (gea-standard, gea-shopfloor, etc.) and the deduped `_shared/` content (Operating Systems, Out-of-box Drivers, Packages). |
| clonezilla | /srv/samba/clonezilla | Clonezilla disk backup images (uploaded by clients running Clonezilla Live). |
| blancco-reports | /srv/samba/blancco-reports | XML erasure reports, written automatically by Blancco Drive Eraser at the end of each wipe. |
| enrollment | /srv/samba/enrollment | Single share that WinPE mounts as Y: during imaging. See "Enrollment share layout" below. |
| image-upload | /home/pxe/image-upload | Staging area for new image content uploaded from a Windows PC running `Upload-Image.ps1`. |
All shares are accessible to `pxe-upload` (password `pxe`) and the public-side
ones also allow guest access. The `blancco` user (password `blancco`) writes to
`blancco-reports` only.
## Enrollment share layout
The `enrollment` share is the catchall WinPE pulls from during imaging. New
fresh installs (built from this repo) deploy this layout:
```
/srv/samba/enrollment/
README.md
ppkgs/ GCCH bulk-enrollment PPKGs (.ppkg)
scripts/ run-enrollment.ps1, wait-for-internet.ps1, migrate-to-wifi.ps1
config/ site-config.json, FlatUnattendW10*.xml, per-site overrides
shopfloor-setup/ PC-type post-imaging scripts (CMM, Display, Standard, Lab, etc.)
pre-install/ WinPE-phase content
bios/ Dell BIOS update binaries + check-bios.cmd + models.txt
installers/ UDC, OpenText, etc. staged on client during preinstall
preinstall.json Preinstall manifest read by the WinPE preinstall stage
installers-post/ Post-OOBE app installers
cmm/ PC-DMIS patched MSIs
blancco/ Blancco custom images / configs (BDE715_GEAE_INTERNET.img.gz)
logs/ Client-uploaded logs and diagnostic bundles
```
Older servers (built before this repo's reorganization) use a flat layout
(everything at the share root). Both layouts work; the `startnet.cmd` baked
into each server's `boot.wim` matches its own layout.
## Boot chain (client perspective)
A client PXE-boots from the isolated LAN. UEFI Secure Boot is supported for
WinPE; the Blancco and Clonezilla utilities require Secure Boot disabled.
```
1. Client UEFI firmware sends DHCP DISCOVER on the isolated LAN.
2. dnsmasq replies with IP, next-server (PXE server IP), and bootfile=ipxe.efi.
3. Firmware fetches /srv/tftp/ipxe.efi via TFTP.
4. ipxe.efi (Broadcom-signed for Secure Boot) starts, gets DHCP, fetches the
iPXE menu script from http://<server>:4433/Altiris/iPXE/GetPxeScript.aspx.
5. Client picks an option:
a. Windows PE:
iPXE -> wimboot -> boot.wim
boot.wim runs startnet.cmd which mounts SMB shares (Y: enrollment,
Z: chosen winpeapps), kicks off FlatSetupLoader.exe -> PESetup.exe
to deploy the OS, then handles per-PC-type setup before reboot.
b. Blancco Drive Eraser:
iPXE chains http://<server>/blancco/grubx64.efi
GRUB loads vmlinuz-bde-linux + initramfs over TFTP (HTTP times out on
large files inside GRUB)
Blancco boot uses copytoram=y to load the rootfs into memory, mounts
the customized airootfs.sfs over HTTP, connects to BMC cloud over WiFi
for license validation, then runs the configured erasure profile.
Reports are written back to \\<server>\blancco-reports.
c. Clonezilla Live:
iPXE loads vmlinuz + initrd over HTTP, fetches filesystem.squashfs.
With Secure Boot on, the Debian-signed kernel starts through Debian's
Microsoft-signed shim (clonezilla/shimx64.efi, iPXE shim command).
The menu checks the CPU (iPXE cpuid --ext 29): 64-bit CPUs get the
current release, 32-bit-only CPUs (XP-era Pentium 4/M, early Atom) get
clonezilla-i686/ (3.2.0-5, the last 32-bit Clonezilla) over legacy BIOS.
"Clonezilla: back up / restore this PC" ask for the machine number,
mount \\<server>\clonezilla as the clonezilla Samba user
(ocs_repository smb3://, password from clonezilla_smb_password) and
run clonezilla-scripts/pxe-cz.sh (ocs_prerun downloads it,
ocs_live_run runs it): images are <machine>-<YYYY-MM-DD-HHMM> with
pxe-meta.txt, checked after saving; restore lists that machine's
images and restores with -k1 -r (larger disks get proportionally
larger partitions). "Clonezilla: manual" is the interactive mode.
Memory testing is not on the menu: Dell PCs have a built-in test
(F12 at power-on, Diagnostics). Memtest86+ was removed because it is
unsigned and needed Secure Boot off.
```
## Windows imaging lifecycle (gea-* images)
```
1. Boot to WinPE via PXE.
2. startnet.cmd mounts Y: \\server\enrollment and presents an interactive
image type and PC type menu.
3. Optionally checks BIOS firmware version against a manifest; if outdated,
stages the new firmware to the disk and reboots so it flashes on POST.
4. PESetup.exe runs the chosen image (image type determines OS, drivers,
apps to deploy).
5. After WinPE finishes, the system reboots into Windows OOBE.
6. During OOBE, the staged PPKG runs (GCCH bulk-enrollment, joins AAD, sets
up Intune enrollment).
7. After OOBE, the per-PC-type Run-ShopfloorSetup.ps1 runs from C:\Enrollment.
It installs the apps for that PC type (eDNC, OpenText, UDC, Dashboard,
etc. depending on the type), configures the desktop, and triggers Intune
sync.
```
## Webapp
`/opt/pxe-webapp/` runs as a systemd service, reverse-proxied by Apache on
port 80 (`/`) and accessible directly on port 9009. Built with Flask. Pages:
- Dashboard: service status, disk usage, recent activity.
- Images: import wizard for new content (from `image-upload` SMB share into
per-image Deploy/ trees), per-image driver and hardware config editing.
- Unattend editor: in-place editing of FlatUnattendW10.xml for each image.
- Startnet editor: edit and re-inject `Windows/System32/startnet.cmd` inside
the deployed `boot.wim` via wimupdate.
- Enrollment: PPKG inventory and upload.
- Backups: Clonezilla backup management.
- Reports: Blancco erasure report viewer.
- Audit: action log.
## Data flow summary
```
Build workstation (this repo)
|
| scripts/build-usb.sh /dev/sdX ubuntu-24.04.iso
v
USB installer (2 partitions: ISO + CIDATA)
|
| inserted into target server, boot from USB
v
Ubuntu auto-install + first-boot Ansible playbook
|
v
Configured PXE server (172.16.9.1) ----+
|
Windows PCs running Upload-Image.ps1 --+--> Image content (SMB, webapp import)
|
PXE clients (UEFI -> iPXE -> WinPE) ---+--> Image deployment (SMB, HTTP)
PXE clients (UEFI -> iPXE -> Blancco) -+--> Drive erasure + report upload
|
+--> Clonezilla backups (SMB)
```
## Where things live
- Ansible playbook: `playbook/pxe_server_setup.yml`. Single file, idempotent.
- WinPE startup script: `playbook/startnet.cmd`. The playbook injects this into `Windows/System32/startnet.cmd` inside the
`boot.wim` it deploys to `/var/www/html/win11/sources/`.
- iPXE menu script source: embedded in the playbook (`Create GetPxeScript.aspx`
task); deployed to `/var/www/html/Altiris/iPXE/GetPxeScript.aspx`.
- Per-PC-type setup scripts: `playbook/shopfloor-setup/`. The playbook copies
the whole tree to the enrollment share so WinPE can fetch them.
- Blancco assets: `boot-tools/blancco/` in the repo, deployed to
`/var/www/html/blancco/` plus TFTP symlinks in `/srv/tftp/blancco/`.
- Site-specific values (IPs, SSIDs, BMC creds, hostnames): currently
hardcoded in multiple files; see SITE-CUSTOMIZATION.md for the migration
plan to consolidate these in `config/`.
## See also
- SETUP.md: build process and target server install
- SITE-CUSTOMIZATION.md: what to change when bringing up a new site
- TROUBLESHOOTING.md: known failure modes and fixes
- BLANCCO.md: erasure boot chain details, custom config.img, BMC licensing
- GEA-IMAGING.md: WinPE deployment internals, PPKGs, per-type setup
- OPERATIONS.md: day 2 procedures (PPKG bumps, BIOS updates, image upload)