• v0.4.6 55f4765a20

    mward4 released this 2026-05-26 00:02:25 -04:00 | 41 commits to main since this release

    OpenPXE v0.4.6

    UI polish + iVentoy-inspired PXE-menu chrome. No backend behaviour
    changes other than the new idp_logo_url SSO field; existing
    deployments upgrade in place.

    PXE boot menu (iVentoy-style)

    The top-level iPXE menu now opens with a polished centered "OpenPXE"
    wordmark and closes with a single-line footer carrying the version +
    the booting client's arch. Concretely:

    
       ------------------------- Default -------------------------
       Boot from Local HDD
       ----------------------- Installers -----------------------
       Linux Installers >
       Windows Installers >
       -------------------------- Tools --------------------------
       Tools >
       --------------------- Queued Deployment ---------------------
       Queued Deployment (join queue)
    
                     OpenPXE v0.4.6  -  x86_64 UEFI
    
    • ASCII wordmark lives in item --gap lines so every iPXE build
      paints it, even the minimal snponly / undionly variants without
      a graphics console. Always visible regardless of firmware capability.
    • Best-effort PNG overlay. A console --picture <base>/branding/pxe-logo || console line at the top of the script lets iPXE builds with
      PNG support paint the operator's uploaded raster logo as the
      background. The || console resets to plain text on any iPXE that
      doesn't speak PNGs, so the menu always renders cleanly.
    • New endpoint: GET /branding/pxe-logo serves the operator's
      raster logo (PNG / JPEG / WebP / GIF) as-is. SVG uploads return 404
      — iPXE can't rasterize SVG. Endpoint stays public after admin setup
      because iPXE clients have no way to send a session cookie.
    • Footer line OpenPXE v0.4.6 - <arch> mapped from iPXE's
      ${buildarch} × ${platform} to a friendly form:
      x86 BIOS (i386 + pcbios), x86_64 UEFI (x86_64 + efi), arm64 UEFI (arm64 + efi). No website URL per the design brief.

    To get your custom logo painted in the PXE environment: upload a PNG
    (or JPEG / WebP / GIF) on Settings → Branding. SVG continues to drive
    the WebUI's top-left logo as before; the ASCII wordmark stands in on
    the PXE side.

    Top-right user menu

    The "signed in as X / Sign out" row moved out of the sidebar footer
    and into a small person-icon button next to the theme toggle.
    Click opens a popover with three rows:

    • Name — the operator's display username (read-only).
    • Edit account — jumps to Settings, which has the Account card at
      the top.
    • Sign out — revokes the session and bounces to the login screen.

    Esc + click-outside close it. The sidebar footer is back to the clean
    "Service status / Advertised PXE URL / OpenPXE v0.4.6" trio.

    Settings touchups

    • Account card form chrome is now consistent across all four
      inputs (Current password / New username / New password / Confirm).
      The previous CSS selector only styled type=text and type=number
      inputs, leaving password fields with default browser chrome —
      visually misaligned next to the styled username input. The new
      rule covers every input type we use, normalizes Safari's password-
      field metrics, and adds a 1-pixel teal focus ring that works in
      both light and dark mode.
    • SSO card header is now a single 3-column row: IdP display
      name
      , IdP logo URL (new field, FleetDM-style), Metadata
      source
      . All three controls baseline-align because the select
      inherits the same chrome as the text inputs. Below the row, the
      active source field (Metadata URL or pasted XML) spans full width.
    • SsoConfig.idp_logo_url persisted to sso.json alongside the
      existing fields. Length-capped at 2048 chars, must be http:// or
      https://. Used by the future SAML sign-in flow to brand the
      "Sign in with X" button. Empty/missing falls back to a generic
      badge.

    Container image

    • gitea.milesward.dev/mward4/openpxe:0.4.6
    • gitea.milesward.dev/mward4/openpxe:latest

    linux/amd64; static-musl binary; Debian 12-slim runtime (unchanged
    from v0.4.5). Non-root UID 10001 with setcap NET_BIND_SERVICE.

    Quality

    • 138 tests passing (was 132 in v0.4.5). Net +6: +1 IdP-logo-URL
      validation in the SSO config unit tests, +1 regression guard for the
      PXE-menu polish (asserts console --picture, the ASCII banner, the
      footer interpolation, and the three arch labels), +4 integration
      tests for /branding/pxe-logo covering the missing-config / SVG-
      fallback / raster-serve / post-auth-public-allowlist cases.
    • cargo clippy --workspace --all-targets clean.

    Compatibility

    • Existing sso.json files keep working — the new idp_logo_url
      field defaults to the empty string when missing.
    • Existing deployments upgrade in place; the WebUI bumps from v0.4.5
      to v0.4.6 on next launch, picks up the new menu chrome, and the
      user menu's reposition is purely cosmetic.
    Downloads
  • v0.4.5 a1518110ed

    mward4 released this 2026-05-25 22:37:25 -04:00 | 42 commits to main since this release

    OpenPXE v0.4.5

    Maintenance / hardening release. Three meaningful changes:
    a Casper-cmdline fix that makes Ubuntu / Mint / Pop!_OS / elementary
    ISOs reliably PXE-boot under VMware UEFI; a fully static musl binary
    that removes the glibc dependency; and a complete Sonarr/Radarr-style
    Forms admin auth layer with FleetDM-shaped SSO configuration on the
    side.

    VMware UEFI fix

    Borrowed from Bootimus v0.1.67.
    The Debian/Ubuntu kernel command line now reads

    boot=casper initrd=initrd ds=nocloud ip=dhcp iso-url=…
    

    instead of the legacy boot=casper netboot=url url=… ip=dhcp ---.
    Two material changes:

    • iso-url= is the canonical Casper option. Subiquity (the
      live-server installer) consumes it directly; the older netboot=url url=… syntax was a Debian-installer-era artifact that subiquity
      doesn't always honour.
    • ds=nocloud short-circuits cloud-init's metadata probe. On
      VMware-UEFI guests the vmxnet3 driver comes up late enough that
      cloud-init's autoprobe stalls indefinitely; ds=nocloud tells it
      there's no datasource and it should move on.

    Effect: Ubuntu Desktop, Ubuntu Live-Server, Mint, Pop!_OS, and
    elementary OS now boot consistently under ESXi / vSphere / Workstation
    UEFI guests. Bare-metal UEFI was unaffected and continues to work.

    A unit test (casper_cmdline_vmware_uefi_safe) pins the new form so
    this doesn't regress.

    Static musl binary

    The container build stage now compiles against
    x86_64-unknown-linux-musl. The resulting /openpxe binary has zero
    glibc dependency:

    $ ldd /usr/local/bin/openpxe
            statically linked
    

    This matches what Bootimus shipped in v0.1.70 and gives us:

    • No more "GLIBC_2.39 not found" surprises on older RHEL / Rocky
      hosts whose libc trails Debian 12's.
    • A future scratch / distroless variant is now a one-line swap (the
      binary is its own world); v0.4.5 still ships Debian slim runtime so
      we keep the existing samba / wimtools / nfs-common shellouts
      working without behavioural changes.
    • Slightly smaller attack surface — no dynamic-loader, no glibc
      symbol-version skew.

    The choice of Rust pays off here: the entire workspace compiles
    warning-free against musl without touching any code (rustls-via-reqwest,
    tokio, axum, bcrypt all "just work" on the musl target).

    Forms-style admin auth (Sonarr / Radarr layout)

    A complete first-run-bootstrap → login → change-credentials flow,
    deliberately modelled on Sonarr / Radarr. From a fresh install:

    1. The WebUI's /api/me returns setup_required: true and the SPA
      renders a centered "First-run setup" card. The operator picks a
      username + password.
    2. The bootstrap call (POST /api/setup) creates the admin record
      in <work_dir>/auth.json (bcrypt-hashed, cost 10) and sets a
      24-hour openpxe_session HttpOnly cookie.
    3. From that moment on, /api/* requests require the cookie; PXE
      endpoints (/boot.ipxe, /iso/*, /ipxe/*, the iPXE long-poll
      paths) stay public so booting clients don't get gated.
    4. The Settings tab gains an "Administrator account" card for
      rotating username / password. The current password is required
      to make any change; on success every other browser session is
      revoked.

    Endpoints: POST /api/setup, POST /api/login, POST /api/logout,
    GET /api/me, PUT /api/me/credentials.

    Sidebar footer carries a signed in as X chip + Sign out button.
    Forgot-password recovery is the same as Sonarr's: SSH to the host and
    delete <work_dir>/auth.json — the next launch re-enters setup mode.

    SSO config (storage-only this release)

    A FleetDM-shaped SAML configuration surface. Operators teach OpenPXE
    about their IdP today; the actual SAML-response-validation flow lands
    in a future release. Per the brief, the operator-visible fields are
    just:

    • Enable SSO (toggle)
    • IdP display name ("Sign in with X" label)
    • Metadata source — radio between Metadata URL (HTTPS) and
      pasted Metadata XML

    No Entity ID field — that defaults to the advertised public base URL
    internally when the SAML wiring lands, which is what every common IdP
    expects.

    Validation: enabling SSO without either metadata source returns 400;
    metadata XML is capped at 1 MiB; URLs must be http:// or https://
    and ≤2048 chars. Endpoints: GET /api/sso, PUT /api/sso.

    The login screen surfaces a non-functional "Sign in with X" button
    when SSO is configured but the runtime flow isn't live yet — so once
    v0.4.6+ lights it up, no operator config re-entry is needed.

    Container image

    • gitea.milesward.dev/mward4/openpxe:0.4.5
    • gitea.milesward.dev/mward4/openpxe:latest

    linux/amd64; ~97 MB compressed; static-musl binary, Debian 12-slim
    runtime for the shellouts. Non-root UID 10001 with
    setcap NET_BIND_SERVICE.

    Quality

    • 132 tests passing (was 106 in v0.4.4). +5 auth unit tests, +5
      SSO unit tests, +7 auth integration tests, +1 SSO integration test,
      +1 Casper-cmdline regression guard.
    • cargo clippy --workspace --all-targets clean.

    Compatibility

    • Existing installs keep working. Old meta.json and hosts.json
      files deserialize unchanged. There is no auth file on existing
      deployments, so the first hit to the WebUI lands on the new
      first-run setup page — that's the intended UX for the rollout.
    Downloads
  • v0.4.4 7b972dc049

    mward4 released this 2026-05-25 17:47:01 -04:00 | 43 commits to main since this release

    OpenPXE v0.4.4

    Settings tab lands with API reference + custom branding, ISOs get an
    operator-controlled menu category, and Storage now shows how much room
    is left on the volume.

    New: Settings tab

    A dedicated Settings nav item between Terminal and About. Three cards:

    • Identity & access — read-only placeholder for the LDAP, OIDC, and
      user-management work coming in a future release. Today OpenPXE has no
      built-in auth on the WebUI; run behind an identity-aware reverse proxy
      (Authentik, Authelia, oauth2-proxy) for hardened deployments.
    • Branding — upload a custom WebUI logo (PNG, SVG, JPEG, WebP, or
      GIF; up to 2 MB). Persisted under <work_dir>/branding/ and served at
      /assets/logo.svg in preference to the bundled mark. "OpenPXE v0.4.4"
      pins to the sidebar footer so the backend identity stays visible even
      with custom chrome (FleetDM-style).
    • API reference — a self-rendered, grouped list of every /api/*
      endpoint with method, path, and one-line summary. Sourced from a new
      GET /api/docs so operators chasing an integration get it in-product
      rather than having to fetch the OpenAPI YAML separately.

    Storage

    • Type column is now an OS / Tools dropdown. Defaults to OS — the
      ISO is routed by detected family into the Linux or Windows installer
      submenus. Flipping it to Tools moves the entry into the Tools submenu
      next to memtest / shell / NIC info. Family detection still drives
      BIOS/UEFI / kernel args; only the menu placement changes. New endpoint:
      PUT /api/isos/:id/category body {"category":"os"|"tools"}.
    • Disk space card. Free / used / total for the volume hosting the
      ISO directory, with an 80% / 95% colour ramp on the bar. Lives at the
      top of the Storage tab so a half-full volume is visible before you
      start an upload. New endpoint: GET /api/storage/disk. The
      statvfs call lives in iso-store so the http-api crate stays
      #![forbid(unsafe_code)].

    UI polish

    • Aligned brand block. The sidebar header now matches the topbar
      height exactly so the dividing line runs straight across the top of
      the app — no more "OpenPXE big, Dashboard small, different heights"
      step. Brand badge is 26 px icon + 15 px label, matching the topbar's
      h1.
    • Light-mode terminal. --terminal-bg and the per-level text
      colours now track the active theme. Previously the Terminal pane
      stayed dark in light mode, looking like a stuck panel.
    • Sidebar footer version line. "OpenPXE v0.4.4" is pinned below the
      advertised PXE URL so backend identity survives any operator-uploaded
      logo.
    • About tab. Lead paragraph now spans the full content width
      (previously capped at 60ch leaving the right two-thirds blank), and a
      Docs row links to https://openpxe.com/.

    Container image

    • gitea.milesward.dev/mward4/openpxe:0.4.4
    • gitea.milesward.dev/mward4/openpxe:latest

    linux/amd64 Debian 12-slim runtime + binary + iPXE binaries + wimboot,
    non-root UID 10001 with setcap NET_BIND_SERVICE.

    Quality

    • 106 tests passing (was 89 in v0.4.1). Net +17 from new branding
      unit tests, store/disk plumbing, and integration coverage for the
      category / disk / docs / branding endpoints.
    • cargo clippy --workspace --all-targets clean.

    Compatibility

    • Old meta.json files without a category field deserialize as Os
      (matches v0.4.1 behaviour — everything in OS Installers). No migration
      needed.
    • /api/settings is unchanged; existing automations keep working.
    Downloads
  • v0.4.1 a171331a7a

    mward4 released this 2026-05-24 13:53:10 -04:00 | 44 commits to main since this release

    • Adds browser-safe chunked ISO uploads with deterministic progress and visible .partial files.\n- Keeps legacy multipart upload support for API clients.\n- Adds offset validation, abort cleanup, duplicate partial-file protection, and Docker build reproducibility via Cargo.lock.\n- Validates Host log capture, footer service status, 0.4.1 version surfaces, and near-black dark theme polish.\n- Full workspace tests and clippy pass.
    Downloads
  • v0.4.0 ec171ede47

    mward4 released this 2026-05-24 13:12:16 -04:00 | 47 commits to main since this release

    OpenPXE v0.4.0

    Quality-of-life release on top of v0.3.2: upload reliability + diagnostics,
    a per-host install log, and a true jet-black dark theme.

    New features

    • Host log under the Hosts tab — every time a PXE client actually starts
      imaging (i.e. /boot/<entry>.ipxe is served past any password gate, or a
      per-MAC host binding fires) OpenPXE records (timestamp, MAC, IP, image)
      to a bounded ring (latest 500) and appends it to boot_log.jsonl under
      the work dir. The new Host log card shows it newest-first. Reserved
      console shortcuts (_local, _queue, …) are deliberately skipped so the
      log stays focused on "what got installed where."
    • GET /api/boot-log — JSON endpoint backing the new tab. Empty until
      the first client boots.
    • iPXE MAC plumbing — per-entry chain URLs and password-prompt
      submissions now carry ?mac=${mac} so the boot log can attribute events
      to a host without depending on DHCP correlation.

    Reliability

    • Upload truncation handled correctly. The multipart loop used
      while let Ok(Some(_)) = field.chunk().await, which silently treated
      mid-stream errors (reverse-proxy buffer caps like Cloudflare's 100 MB
      free-tier limit, Cloudflare 524s, half-closed TCP, etc.) as clean EOF —
      the server would happily finalise a partial ISO. v0.4.0 distinguishes
      Ok(None) from Err(_) and returns 400 Bad Request with the
      underlying cause and a "try the LAN IP directly" hint when the body is
      truncated.
    • Per-stage upload tracing. openpxe::http::upload now logs at
      info/warn/error for every transition (begin → MB watermarks at
      64/128/256/… → body complete → introspect → final). A stuck or rejected
      upload is now debuggable from the Terminal tab.
    • Client-side upload telemetry. The browser drop-zone now shows
      bytes/total, percent, throughput, and ETA while uploading. Common
      failures (413, 502, 504, network drop, timeout) map to actionable hints.

    UI

    • Jet-black dark theme. Replaced the blue-tinted ramp (#0b1018
      #1a2334) with a true-black palette (#000000#0a0a0a#141414
      #1c1c1c), modelled on NetBox Labs' product chrome. The teal accent
      is preserved for brand continuity. Terminal toolbar/input recoloured to
      match.
    • Service status moved to the sidebar. The top-right "● ready" chip
      is gone; readiness is now part of the sidebar footer block alongside the
      advertised PXE URL ("Service status: Ready / Advertised to clients /
      http://…"). The advertised address was already the PXE boot IP
      (auto-detected NIC) rather than the WebUI URL, but operators wanted them
      grouped together.
    • Queue tab — card header "Forge" → "Status".
    • Hosts tab — dropped the "Inspired by Tinkerbell smee" attribution
      blurb. The MAC-binding mechanic is still the same; the marketing footnote
      was just clutter.

    Container image

    • gitea.milesward.dev/mward4/openpxe:0.4.0
    • gitea.milesward.dev/mward4/openpxe:latest

    linux/amd64; ~97 MB; Debian 12-slim runtime + binary + iPXE binaries

    • wimboot. Non-root UID 10001 with setcap NET_BIND_SERVICE.

    Quality

    • 89 tests passing (was 85 in v0.3.2). Includes 4 new integration
      tests for the boot log (records correctly + skips reserved targets +
      empty endpoint behaviour) and 5 new unit tests for the in-memory ring
      • on-disk JSONL.
    • cargo clippy --workspace --all-targets clean.

    Known caveats

    • Uploading >100 MB ISOs through a Cloudflare reverse proxy will still
      reject (Cloudflare's body cap, not OpenPXE's). The new UI/server hints
      point the operator at the LAN IP for big files.
    Downloads
  • v0.3.2 115ba779da

    mward4 released this 2026-05-21 02:13:32 -04:00 | 48 commits to main since this release

    Downloads
  • v0.3.1 91848e02e3

    mward4 released this 2026-05-06 22:35:11 -04:00 | 49 commits to main since this release

    v0.3.1 — per-ISO boot password gate

    Operators can now lock individual ISOs behind a password set in the WebUI. Picking a locked image at the PXE menu prompts the operator on the client console; the boot script is only released after a correct match. The plaintext never leaves the request — server stores bcrypt hashes, scripts never echo the candidate.

    Pull

    docker pull gitea.milesward.dev/mward4/openpxe:0.3.1
    

    How it looks

    In the WebUI's Storage tab, each image row gains an Auth column (open / protected) and a per-row "Set password" / "Password ✎" button that toggles an inline editor — checkbox + masked input + Save. A 🔒 appears next to the filename when locked.

    In the PXE menu, locked entries get a leading * next to the size box:

    item --key 1 win11-test-winpe *[ 5234 MB] Windows 11 Test
    

    When a locked entry is selected, iPXE shows a "This image requires a password" banner, accepts input via read --secret password (no echo), and chains back with ?token=${password:uristring} so passwords with &, ?, =, spaces, etc. survive transport. Wrong password sleeps 2s, prints Wrong password., then re-prompts. Empty input bails to the main menu.

    API

    PUT /api/isos/:id/password body { "password": "..." } to set, { "password": null } (or empty string) to clear.
    DELETE /api/isos/:id/password explicit clear.

    Both 204 on success, 404 for unknown ids.

    Security posture

    • bcrypt cost = DEFAULT_COST (10). One verify takes ~50ms on modern x86 — acceptable interactive latency, hostile to brute force on a leaked meta.json.
    • Server logs only that a wrong-password attempt happened plus the entry id. Never the candidate, never the correct value, never the bcrypt hash.
    • Boot scripts never echo any password value back to the client console.
    • The token rides in the query string — acceptable on a trusted boot VLAN, but if you reverse-proxy OpenPXE the token will end up in proxy access logs. Don't expose this to untrusted networks.

    Tests

    74 passing across the workspace (was 66 in v0.3.0):

    • 3 store unit tests (bcrypt round-trip, unknown-id error, meta.json persistence across restart)
    • 2 ipxe_script unit tests (prompt + auth-fail invariants: read --secret, :uristring, no candidate echo)
    • 3 HTTP integration tests (full upload → set → prompt → fail → success → clear flow, null/empty bodies, 404 on unknown id)

    cargo clippy --workspace --all-targets clean.

    Local smoke verified end-to-end on a real release binary: upload Win11_Test.iso → PUT password → menu shows the lock indicator → no token returns prompt → wrong token returns Wrong password. → correct token returns the wimboot chain → password values do not appear in the server log.

    Image details

    • Base: debian:12-slim
    • Architecture: linux/amd64
    • Size: ~97 MB
    • Digest: sha256:f3e5ee78079c25f55cb826837b8dda9428bf6b9592d9f15a2f6b413c5642fa1e
    • Runs as uid 10001
    • Required cap: NET_BIND_SERVICE
    • Optional cap: SYS_ADMIN for NFS share mounting

    Upgrade from v0.3.0

    Drop-in. New password_hash field on IsoMeta is Option<String> and skipped during serialize when None — existing meta.json files are forward-compatible. Existing settings.json carries through. :latest now points at 0.3.1.

    Downloads
  • v0.3.0 4e88305101

    mward4 released this 2026-05-06 14:14:09 -04:00 | 50 commits to main since this release

    v0.3.0 — UI/Branding OpenPXE

    Full project rename to match openpxe.com. The product now reads as a polished open-source release rather than a personal-tool nickname. Placeholder retired; new mark is the rainbow-horizon medallion from site examples (animated SMIL gradient, no GIF, no JS).

    Pull

    docker pull gitea.milesward.dev/mward4/openpxe:0.3.0
    

    Naming changes

    OpenPXE everywhere user-visible or developer-facing:

    • 8 crate package names updated
    • The bin crate dir + binary (crates/openpxe, bin = "openpxe")
    • Env vars updated
    • Tracing targets updated
    • Prometheus metrics updated
    • Container image path: gitea.milesward.dev/mward4/openpxe
    • All in-tree paths: /var/lib/openpxe/{isos,work,smb}, /usr/share/openpxe/ipxe
    • Unraid template updated

    Gated Deployment → Queued Deployment as the user-facing concept:

    • Settings::TimeoutAction::GatedDeploymentQueuedDeployment (with #[serde(alias = "gated_deployment")] so v0.2.0 settings.json files keep deserializing transparently)
    • Rust types: GateQueueEntry, GateQueueDeploymentQueue, gate.rsqueue.rs
    • HTTP routes: /api/gate/*/api/queue/*. JSON envelope key flipped from "gates" to "entries"
    • iPXE shortcut: /boot/_gate.ipxe/boot/_queue.ipxe. Top-level menu item id queue instead of gate
    • WebUI sidebar tab: "Forge Gate" → "Queue"

    Brand assets

    • logo.svg is a 24×24 medallion filled with the rainbow-horizon gradient from openpxe.com (sliding hue rotation via SMIL on the gradient stops, no JS).
    • anvil-forge.svgloader.svg, rebuilt as a 64×64 louder version of the same disc — used for page-load transitions and the imaging-progress widget. Adds a subtle scale pulse and a white inner-glow for depth.

    The dashboard layout is unchanged — light/dark theme tokens and the sidebar/topbar carry over from v0.2.0. "Keeping the UI similar" was the brief.

    Validation

    • cargo build --workspace clean
    • cargo clippy --workspace --all-targets no warnings
    • cargo test --workspace66 tests passing
    • Local smoke against the rebuilt release binary verifies:
      • /boot.ipxe emits Queued Deployment + item queue and chains /boot/_queue.ipxe
      • /api/queue returns {count, entries}
      • /metrics emits openpxe_queue_count (renamed from pxeforge_gate_count)
      • /assets/logo.svg and /assets/loader.svg serve the new rainbow brand SVGs
      • /api/status reports version 0.3.0

    Image details

    • Base: debian:12-slim
    • Architecture: linux/amd64
    • Size: ~97 MB
    • Digest: sha256:c5fea580fb248d63f4d6c5bb9af229c2824673d5a1207f1c0e9d841c9fe40d36
    • Runs as uid 10001 (entrypoint chowns bind mounts as root, then drops via gosu)
    • Required cap: NET_BIND_SERVICE
    • Optional cap: SYS_ADMIN for NFS share mounting

    For Unraid: pull deploy/unraid/openpxe.xml and re-add the container under the new template. Move host appdata to /mnt/user/appdata/openpxe/.

    Downloads
  • v0.2.0 49d0b00a8a

    v0.2.0 — pre-beta Pre-Release

    mward4 released this 2026-04-30 02:28:10 -04:00 | 54 commits to main since this release

    v0.2.0 — pre-beta

    This is the bulk pre-beta cleanup pass. The protocol stack and operator UI are exercised by 66 automated tests (up from 56), cargo clippy --workspace --all-targets is fully clean, and the container image is 97 MB of linux/amd64 bytes.

    Pull

    docker pull gitea.milesward.dev/mward4/openpxe:0.2.0
    

    Highlights

    Per-MAC host bindings Pin a MAC to a boot target and the client skips the menu. The DHCP reply embeds ?mac=${mac} in the boot.ipxe URL; iPXE substitutes the literal MAC client-side, and the HTTP layer chains straight to the bound entry. New Hosts tab and /api/hosts CRUD.

    Prometheus /metrics. Counters for DHCP replies (per arch), TFTP transfers + bytes, HTTP requests (per route family). Gauges for ISO / client / gate / imaging counts, NFS active mounts, uptime, build info. Plain text exposition format. Lock-free AtomicU64s — no prometheus/metrics-rs runtime dep.

    Light + dark themes. CSS-token toggle in the top-right corner (or press T). Light palette designed against reference. Pre-paint inline script avoids the dark→light flash on every page load. Terminal pane stays dark in both themes.

    Windows boot workflow validation. A new integration test synthesizes a Windows-style ISO and asserts (1) introspection identifies it correctly, (2) the boot entry is the canonical 5-file wimboot chain, (3) the rendered iPXE script chains wimboot with initrd --name for each, and (4) no trust-store strings (bcdedit, testsigning, certutil, httpdisk, test-signed) appear. WinPE startnet.cmd picks up other open source utility lessons (explicit net start Workstation before net use, surfaced errors).

    Code cleanup pass

    cargo clippy --workspace --all-targets is now warning-free. Among the bigger fixes:

    • format!() appended to Stringstd::fmt::Write::write!
    • manual reverse comparators → Reverse
    • map_or(false, …)is_some_and
    • redundant closures → method references
    • std::io::Error::new(Other, …)Error::other
    • merged identical match arms

    Run on Unraid

    docker pull gitea.milesward.dev/mward4/openpxe:0.2.0
    

    Same deployment as v0.1.0 — see deploy/unraid/README.md. Drop deploy/unraid/openpxe.xml into /boot/config/plugins/dockerMan/templates-user/ for a one-click template. Web UI: http://<unraid-ip>/.

    What's next

    A detailed Phase 6 punch list lives at docs/NEXT_PHASE.md. The headline item is real-hardware validation across BIOS / UEFI x64 / UEFI ARM64 — the protocol legs are CI-tested, but no real firmware has booted OpenPXE yet.

    Image details

    • Base: debian:12-slim
    • Architecture: linux/amd64
    • Size: ~97 MB
    • Digest: sha256:d682c97f903caf16ae9e1631d547d7ec32a8da64b4db7ef93f64b12164233ea4
    • Runs as uid 10001 (entrypoint chowns bind mounts as root, then drops via gosu)
    • Required cap: NET_BIND_SERVICE
    • Optional cap: SYS_ADMIN for NFS share mounting
    Downloads
  • v0.1.0 a9c4f408a9

    v0.1.0 — MVP Pre-Release

    mward4 released this 2026-04-30 00:02:29 -04:00 | 55 commits to main since this release

    Phase 1-4 release: OpenPXE MVP

    First public release — every protocol leg works in CI tests; needs real-hardware validation next.

    What you can do with this image

    • Boot Linux ISOs (Ubuntu, Debian, RHEL family, Arch, Alpine, openSUSE) via PXE on BIOS or x86_64 UEFI clients
    • Boot Windows installers via vanilla Microsoft-signed WinPE + SMB share (no test certs, no testsigning toggle)
    • Mount remote NFSv3 / NFSv4.1 shares as ISO sources without copying images into the PVC
    • Drive Gated Deployment: many clients wait at a queue, operator picks one ISO, all launch simultaneously
    • Watch the live tracing log + run whitelisted commands from the Terminal tab in the web UI

    Pull

    docker pull gitea.milesward.dev/mward4/openpxe:0.1.0
    

    Run on Unraid

    See deploy/unraid/README.md. Drop deploy/unraid/openpxe.xml into /boot/config/plugins/dockerMan/templates-user/ for a one-click Docker template.

    Image details

    • Base: debian:12-slim
    • Architecture: linux/amd64
    • Size: ~97 MB
    • Runs as uid 10001 (entrypoint chowns bind mounts as root, then drops via gosu)
    • Required cap: NET_BIND_SERVICE for ports 67/69/80
    • Recommended cap (optional): SYS_ADMIN if you want NFS share mounting

    Tests

    56 passing across the workspace: 16 core + 1 dhcp-proxy + 8 http-api unit + 13 integration + 12 iso-store + 6 tftp.

    Known gaps deferred to next phase

    • Real-hardware Windows boot validation (plumbing tested only)
    • Real-hardware NFS validation (mount manager tested only)
    • Full ISO9660 + Joliet + Rock Ridge (current parser is plain ISO9660)
    • UEFI HTTP Boot (option 60 = HTTPClient)
    • Multi-replica deployment
    Downloads