Miles WardandClaude Opus 4.8 3a32d65fb7 v0.7.0: Secure Boot chain, boot rules + decision webhook, tokenized answer files
Three features, all zero-toggle and principle-clean (single static musl
binary, container-first, no test certs, no client trust-store changes).

Secure Boot via signed shim+GRUB (automatic):
- The v0.6.1 escalation ladder gains a third rung: Firmware -> Builtin
  -> Shim. Secure-Boot firmware downloads our unsigned iPXE but refuses
  to execute it — indistinguishable from a failed chainload — so after
  two unconfirmed attempts the MAC is offered Fedora's Microsoft-signed
  shimx64.efi, which loads the signed GRUB, which fetches a
  server-rendered grub.cfg. Fully signed chain, SB stays on.
- scripts/fetch-shim.sh pulls shim-x64/grub2-efi-x64 (+aa64 best-effort)
  from the official Fedora 43 packages and ships the EFI binaries
  byte-for-byte unmodified; Dockerfile fetch stage gained rpm2cpio/cpio.
- New grub_script renderer (Linux kernel entries only — signed GRUB only
  boots signed kernels; sanboot/wimboot have no signed equivalent and
  are omitted with an explanatory menu line).
- TFTP server gains a DynamicAsset hook for server-rendered names
  (grub.cfg); HTTP serves the same config under /ipxe/grub.cfg for
  native UEFI HTTP Boot chains. Arch-aware fallback walks back down the
  ladder where no shim exists (BIOS, IA32).

Boot rules + decision webhook (open 'Matrix Boot'):
- Ordered first-match-wins rules over MAC prefix + client arch (the DHCP
  proxy now bakes arch into the boot.ipxe chain URL), generalizing
  per-MAC pins. Persisted to boot_rules.json; GET/PUT /api/boot-rules;
  rules editor + webhook field on the Hosts tab.
- Optional pixiecore-style webhook: unmatched boots GET
  <url>?mac=&arch= and 200 {"target":"id"} chains to it. Fail-open
  with a 2s budget — a dead endpoint can never block PXE.
- Decision order: exact pin -> rules -> webhook -> menu. Empty config
  is byte-for-byte the previous behavior.

Tokenized answer files (the post-WDS/CVE-2026-0386 hardening):
- Every generated unattended URL (inst.ks / preseed url / autoinstall
  seed) now carries a 4h boot-scoped token; /unattended/{id} and the
  cloud-init seed routes require it (or an operator session) once an
  admin exists. Stops answer-file credential harvesting by anything
  else on the network. No toggle; setup-mode installs stay open.

Validation: clippy clean, fmt clean, 290 workspace tests green
(+18 new across boot_tokens, boot_rules, arch ladder, escalation,
grub renderer, and four new full-flow integration tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-09 20:17:18 -04:00
2026-04-29 02:47:00 -04:00
2026-05-21 02:13:08 -04:00
2026-04-29 02:47:00 -04:00
2026-05-06 14:13:38 -04:00
2026-06-05 13:13:07 -04:00
2026-04-29 02:47:00 -04:00

OpenPXE

OpenPXE

Container-native network boot & OS deployment — built in Rust.

Drag in an ISO. PXE-boot and image an entire fleet from a browser.
No iPXE scripting. No dnsmasq + tftpd + Samba glue. No glibc. No garbage collector.

release license rust container binary


OpenPXE turns bare-metal provisioning into a single container with a web UI. It's a ground-up Rust reimplementation of iVentoy (ventoy/PXE), designed for Docker/OCI and OpenShift instead of a Windows desktop — so it drops onto an Unraid box, a Linux server, or a Kubernetes cluster and just runs.

Upload .iso files (or point at a remote share), and any machine on the network boots them — Linux installers, live tools, or stock Windows setup — with zero iPXE knowledge required by the operator.

Status — v0.6.0, late pre-beta. The full PXE stack, web UI, remote ISO libraries (SMB/NFS/SFTP), Windows deployment, queued fleet rollout, SAML SSO, and Prometheus metrics are implemented and test-covered. The release checklist gates every tag on the full test suite + clippy. Currently in real-hardware validation.

Why OpenPXE

Standing up network boot the traditional way means hand-wiring dnsmasq, a TFTP daemon, hand-written iPXE menu scripts, an HTTP server, and Samba — then keeping that fragile stack alive, and discovering none of it containerizes cleanly (kernel-mount NFS, raw sockets, CAP_SYS_ADMIN). iVentoy solved the UX beautifully, but it's a Windows GUI app.

OpenPXE collapses that whole stack into one statically-linked binary in one container:

  • A web UI does everything. iPXE is an internal implementation detail — there is no script upload, no .ipxe editing, no PXE jargon in the interface.
  • It runs anywhere a container runs. No kernel modules, no privileged mode — proxy-mode DHCP + NET_BIND_SERVICE is the entire requirement. Verified on Unraid, plain Docker, and OpenShift's restricted SCC.
  • It's air-gap native. Zero CDN assets, zero outbound calls from the server, browser, or generated boot scripts. Build the image once, run it forever, disconnected.

Highlights

Boot stack

  • DHCP proxy (RFC 4578) that coexists with your existing DHCP — it never hands out IPs.
  • TFTP (RFC 1350 + 2347/2348/2349/7440 option negotiation) serving arch-correct iPXE firmware.
  • HTTP serving the UI, generated boot scripts, raw ISOs (with byte-range), and files inside ISOs with no prior extraction.
  • Graphical iPXE boot menu built from your uploads, with a PNG background and a clean hierarchy — generated fresh on every request from current settings.

ISO management & remote libraries

  • Drag-and-drop chunked uploads that don't 502 on multi-GB images.
  • Automatic introspection — detects the distro family and generates the right kernel+initrd or Windows wimboot chain. No manual config.
  • Remote ISO libraries, streamed on demand (no local cache) over SMB, NFS, or SFTP — see the table below.

Fleet deployment

  • Queued Deployment — clients join a queue and wait; the operator fires one image at every waiting machine simultaneously.
  • Per-MAC host bindings — pin a MAC straight to a target (with optional auto hostname, auto IP, and an unattended answer file); it skips the menu and chains through.
  • Unattended installs — upload Kickstart / Preseed / Autoinstall / Windows answer files; they're templated per-host (hostname / IP / MAC) and served only to booting clients.
  • Windows deployment from a stock Microsoft ISO — every binary the client runs stays Microsoft-signed (details below).

Operations & access

  • SAML 2.0 single sign-on (pure-Rust SP, no OpenSSL/xmlsec) alongside local accounts.
  • Custom branding — light / dark / PXE-client logos and favicon.
  • Notifications — Slack / Teams / Discord webhooks and SMTP email on boot events.
  • Prometheus /metrics, a built-in operator terminal, live tracing log, and /healthz · /readyz probes.
  • Layered config — defaults → TOML file → OPENPXE_* env, in that order.

Built in Rust

Rust isn't a checkbox here — it's why OpenPXE deploys the way it does:

  • One static binary, ~18 MB. Compiled to x86_64-unknown-linux-musl — no glibc, no interpreter, no sidecar runtime. The runtime image is "binary + a few CLI tools."
  • No garbage collector, async throughout. A Tokio runtime drives DHCP, TFTP, HTTP, and many concurrent multi-GB ISO streams on a tiny, predictable memory footprint — it idles near-zero and never GC-pauses mid-transfer.
  • Memory-safe by construction. unsafe is denied workspace-wide; the only exceptions are two small, individually-audited FFI calls (statvfs for disk usage and a Samba SIGHUP).
  • OpenSSL-free, pure-Rust crypto. TLS via rustls/ring; the SAML Service Provider does XML-DSig verification with RustCrypto — no xmlsec, no libxml2, no C crypto to CVE-patch. Even the SMB/NFS/SFTP clients avoid C libraries.
  • Sub-minute, reproducible container builds. Cross-compiled with cargo-zigbuild (zig as the linker) — a full image builds in well under a minute on a warm cache, with no QEMU emulation.

Quick start

Run the container

# Build the self-contained image (iPXE binaries are fetched + built inside the Dockerfile).
docker build -f deploy/docker/Dockerfile -t openpxe:0.5.5 .

# Run it on the box plugged into your PXE network. Host networking is required in
# proxy mode so the container sees DHCPDISCOVER broadcasts; set PUBLIC_IP to this
# host's LAN address so advertised boot URLs are reachable.
docker run -d --name openpxe --network host \
  -e OPENPXE_PUBLIC_IP=10.0.0.5 \
  -e OPENPXE_DHCP_MODE=proxy \
  -v $PWD/data/isos:/var/lib/openpxe/isos \
  -v $PWD/data/work:/var/lib/openpxe/work \
  openpxe:0.5.5

# Open the UI and drop an ISO in.
open http://10.0.0.5

On macOS/Windows, Docker runs inside a Linux VM, so "host network" means the VM — use the openpxe-dev service in docker-compose.yml for API-only testing on a laptop: OPENPXE_PUBLIC_IP=127.0.0.1 docker compose up openpxe-dev.

Build from source

./scripts/fetch-ipxe.sh          # populate assets/ipxe/ (embedded at compile time)
cargo run --release              # needs root or CAP_NET_BIND_SERVICE for :80/:69

Pre-seed ISOs from a directory

docker run --rm \
  -v /my/iso-library:/seed:ro \
  -v openpxe-data:/var/lib/openpxe/isos \
  -e OPENPXE_PUBLIC_IP=10.0.0.5 \
  openpxe:0.5.5 seed --from /seed          # add --dry-run to preview

Remote ISO libraries

Point OpenPXE at a NAS and boot ISOs straight off it — read on demand, no local copy, so a 50-ISO library costs zero disk on the OpenPXE host. All three clients are userspace (no kernel mounts, no CAP_SYS_ADMIN); pick whichever your storage speaks.

Protocol Implementation Auth HTTP Range¹
NFS (v3) Pure-Rust in-process client Client-IP (server export list)
SFTP (SSH) Pure-Rust in-process client (russh) Password or SSH key · host-key TOFU
SMB / CIFS Userspace smbclient Guest or username/password

¹ Range support lets clients seek into a multi-GB ISO without downloading what comes before it — needed for kernel/initrd extraction and httpdisk-style boots. NFS and SFTP expose explicit offsets; the SMB CLI streams sequentially, so SMB-sourced ISOs serve whole-file.

Supported client architectures

DHCP option 93 Architecture Firmware served
0x0000 Legacy x86 BIOS undionly.kpxe
0x0006 IA32 UEFI snponly-i386.efi
0x0007 / 0x0009 x86_64 UEFI snponly.efi
0x000B ARM64 UEFI snponly-arm64.efi

UEFI firmware that advertises HTTPClient (option 60) skips TFTP entirely and is handed an HTTP URL.

The boot menu, on a real client

                        OpenPXE — network boot menu

 ------------------------- Default -------------------------
 Boot from Local HDD
 ----------------------- Installers ------------------------
 Linux Installers   >
 Windows Installers >                (only if enabled in Settings)
 -------------------------- Tools --------------------------
 Tools              >    Utilities / OpenPXE Shell / NIC Info / Reboot
 ---------------------- Queued Deployment ------------------
 Queued Deployment   (join queue)

Linux/Windows submenus list images iVentoy-style with sizes:

                   OpenPXE — Linux Installers

 [  4699 MB]  ubuntu-22.04.2-desktop-amd64
 [  2002 MB]  Fedora-Workstation-Live-x86_64-38-1.6
            < Back to main menu

The entire hierarchy is generated from what you upload and toggle — iPXE never surfaces.

Windows deployment

Enable Windows ISO support in Settings, then upload a stock, unmodified Microsoft ISO:

  1. On upload, OpenPXE uses wimlib-imagex to inject exactly two plain-text files into the WinPE image (winpeshl.ini + startnet.cmd) — no drivers, no certificates.
  2. The container's Samba smbd serves the extracted install tree on :445.
  3. The client chainloads wimboot → patched WinPE → Windows Setup running off the share.

Every executable the client runs is stock Microsoft-signed. OpenPXE never ships drivers, never installs certificates into the client trust store, and never recommends bcdedit /set testsigning on. The SMB approach is adapted (re-implemented, not copied) from Bootimus (Apache-2.0). Port 445 must be directly reachable from clients; Windows 10/11 client SKUs are the tested target.

Configuration

All settings have defaults and layer defaults → TOML (--config / OPENPXE_CONFIG) → OPENPXE_* env. The common knobs:

Var Default Meaning
OPENPXE_PUBLIC_IP auto-detect IP advertised to clients. Startup fails if unset and auto-detect yields loopback.
OPENPXE_DHCP_MODE proxy proxy or disabled
OPENPXE_HTTP_PORT 80 Web UI + boot-script HTTP port
OPENPXE_TFTP_PORT 69 TFTP port
OPENPXE_DHCP_PORT 67 DHCP server-side port
OPENPXE_ISO_DIR /var/lib/openpxe/isos Uploaded ISOs
OPENPXE_WORK_DIR /var/lib/openpxe/work Scratch, settings, share + branding state
OPENPXE_LOG info,openpxe=info tracing filter

OpenShift

oc apply -f deploy/openshift/
oc -n openpxe get route openpxe -o jsonpath='{.spec.host}'

The bundled openpxe-scc grants exactly hostNetwork (CNI overlays don't deliver L2 broadcast into pod netns) and NET_BIND_SERVICE (to bind ports <1024) — nothing else. No raw sockets, no privileged mode. The Route covers 80/TCP; PXE clients reach UDP 67/69/4011 on the node's host IP directly.

Health & observability

Endpoint Purpose
/healthz Liveness — always 200 if the HTTP stack is up.
/readyz Readiness — 200 only once iPXE firmware is bundled and the ISO dir is reachable.
/api/status Full JSON: version, assets, counts, live settings, share + SMB state.
/metrics Prometheus text format — DHCP replies by arch, TFTP/HTTP counts, queue gauges, uptime.

Architecture

Workspace of focused crates — core, dhcp-proxy, tftp, http-api, iso-store, ipxe-assets, webui, and the openpxe binary. See docs/architecture.md for the protocol stack, crate layout, and the full decision log.

License

Dual-licensed under MIT OR Apache-2.0 — use whichever fits your project.

S
Description
Modern, secure, air-gapped PXE boot solution. Container-native Rust.
Readme
6.4 MiB
2026-07-16 15:56:49 -04:00
Languages
Rust 82.1%
JavaScript 11.8%
CSS 3.3%
Shell 1.4%
Dockerfile 0.8%
Other 0.6%