Replaces the stale v0.4.1 README with a polished, accurate overview: centered brand-mark header + tagline + badges, a "Why OpenPXE" pitch, a scannable Highlights section, and a "Built in Rust" section framed on real properties (single ~18MB static musl binary, no GC, async Tokio, workspace-wide unsafe deny, OpenSSL-free pure-Rust crypto, sub-minute zigbuild images). Surfaces everything shipped since v0.4.1: SMB + NFS + SFTP remote ISO libraries (with a comparison table), SAML SSO, branding, notifications, unattended installs, per-MAC host bindings, and layered figment config. Quick-start, env table, OpenShift, and health/observability all updated to v0.5.5. Adds docs/openpxe-logo.svg (render-safe static copy of the web-UI mark) for the header. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
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.
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.5.5, 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
.ipxeediting, no PXE jargon in the interface. - It runs anywhere a container runs. No kernel modules, no privileged mode — proxy-mode
DHCP +
NET_BIND_SERVICEis 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
wimbootchain. 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·/readyzprobes. - 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.
unsafeis denied workspace-wide; the only exceptions are two small, individually-audited FFI calls (statvfsfor disk usage and a SambaSIGHUP). - OpenSSL-free, pure-Rust crypto. TLS via
rustls/ring; the SAML Service Provider does XML-DSig verification with RustCrypto — noxmlsec, nolibxml2, 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-devservice indocker-compose.ymlfor 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:
- On upload, OpenPXE uses
wimlib-imagexto inject exactly two plain-text files into the WinPE image (winpeshl.ini+startnet.cmd) — no drivers, no certificates. - The container's Samba
smbdserves the extracted install tree on:445. - 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.