A personal homelab network-boot environment: iPXE menu generation for live-booting Linux distros over the LAN, a custom Arch Linux live image, a Windows 11 iSCSI-boot image builder, idempotent workstation setup scripts, and Mellanox NIC firmware tooling.
Three roles, three sets of scripts:
| Host | Role | Runs |
|---|---|---|
PXE server (Fedora Linux, 192.168.1.11) |
TFTP (/srv/tftp), HTTP on :81 (/srv/http/pxe), iSCSI target (LIO/targetcli) |
update-pxe-images.sh, build_archiso.sh |
| Windows build machine | Builds the Win11 iSCSI boot image | build_win11pxe.ps1 + the Get-*.ps1 scrapers |
| Clients | UEFI/BIOS PXE boot into the generated menu | — |
Boot flow: DHCP → TFTP (ipxe.efi / undionly.kpxe) → default.ipxe menu →
live boot from public mirrors / netboot.xyz assets / local HTTP artifacts /
Windows 11 via iSCSI sanboot.
Scrapes the Purdue PLUG mirror for the current Debian, Fedora, Rocky, and Ubuntu LTS
live ISOs (x86_64 and ARM64), resolves matching netboot.xyz kernel/initrd release
assets via the GitHub API, and generates /srv/tftp/default.ipxe with per-distro
menu entries plus Clonezilla, netboot.xyz, and an iPXE shell. Finishes with a
HEAD-check pass over the embedded URLs.
Feature toggles (edit the variables at the top of the script):
ENABLE_TFTP_BOOTSTRAP— download iPXE binaries (snponly.efisaved asipxe.efi,undionly.kpxe, ARM64 EFI) into the TFTP dir.ENABLE_LOCAL_ARCH— copy a local Arch kernel/initramfs from/srv/archand add an NBD-root boot entry.ENABLE_CUSTOM_ARCHISO— add menu entries for the custom archiso image (below).ENABLE_WIN11_PXE— add the Windows 11 iSCSIsanbootentry.
If /srv/http/pxe or /srv/tftp is not writable (e.g. run without root), the script
falls back to ./pxe_test/ — useful as a dry run.
Run as Administrator with PowerShell 7 on a Windows machine:
.\build_win11pxe.ps1 -IsoPath .\Win11_25H2_English_x64.iso -OutPath .\win11_netboot.vhdx -ImageIndex 6 [-Drivers] [-Updates]Creates a dynamic VHDX (GPT: ESP / MSR / NTFS), applies the Windows image with DISM,
writes boot files with bcdboot, then edits the offline SYSTEM/SOFTWARE hives:
promotes iSCSI/NIC/storage services to boot-start, sets the SAN policy, disables
BitLocker auto-encryption, injects LabConfig hardware-check bypasses and BypassNRO,
and drops an unattend.xml (local lan admin account with autologon) plus a
SetupComplete.cmd that disables supported NIC sleep features without restarting adapters.
The helper logs errors to %SystemRoot%\Logs\DisableNetPower.log; SetupComplete
logs to DisableNetPower-setup.log in the same directory. OEM-keyed editions can
skip SetupComplete, so confirm execution on the target.
-Driversruns every NIC/Wi-FiGet-*Drivers.ps1scraper in parallel (theGet-*GraphicsDrivers.ps1shims are excluded — see-GraphicsDrivers) and injects the results withDISM /Add-Driver.-DriverPath .\drivers\boot-nicinjects extracted, tested driver packages from a local directory (recursively) or an individual INF. Multiple paths are allowed. Use it instead of-Driversto avoid changing the NIC package on each catalog refresh; it can still be combined with-GraphicsDrivers. The original driver directory is never deleted. DISM servicing failures stop the build.-GraphicsDrivers Intel|AMD|NVIDIA|Alladditionally injects GPU display drivers (also catalog-sourced) into the same image. GPU CABs are large (~0.6–1.2 GB each), so it is opt-in and separate from-Drivers;Allinjects the ~3–5 GB union of all three vendors, so prefer a single vendor matching the target machine. GPU drivers are post-boot-only (a GPU never serves iSCSI boot), so they get plainDISM /Add-Driverwith no boot-start promotion. A bare INF install yields a fully accelerated driver (incl. the OpenGL/Vulkan/OpenCL/D3D and CUDA/NVENC runtimes); the vendor control-panel apps (NVIDIA App, AMD Adrenalin, Intel Graphics Software — all Microsoft Store) are not installed, and Radeon Pro cards get the base WHQL driver, not the ISV-certified PRO Edition. x64 only (discrete GPUs have no ARM64 Windows driver; Qualcomm Adreno is not on the catalog). The same shims run standalone on a live system (-Install→pnputil).-UpdatesrunsGet-Win11CumulativeUpdates.ps1and injects the latest cumulative update (with checkpoint prerequisites) via folder-basedDISM /Add-Package.
Serving the image: convert the VHDX to a raw image first
(qemu-img convert -f vhdx -O raw win11_netboot.vhdx win11.img) and expose it as an
LIO/targetcli backstore behind iqn.2026-02.lan.pxe:win11. LIO serves file bytes
raw — it does not parse the VHDX container. The targetcli configuration itself is
not versioned in this repo.
Boot NIC (-BootAdapterGuid): optionally run the undocumented DISM
/Add-NetAdapter operation. The adapter must be present with a working driver in
the Windows session running this builder. A GUID from another machine or a
previous WinPE session is not a portable hardware identifier. Invalid/missing
host adapters fail validation before a VHDX is created; a failed requested DISM
operation stops the build.
# Run on the build host; select the intended NIC rather than the first result:
Get-CimInstance Win32_NetworkAdapter | Select-Object GUID,Name,ServiceName
.\build_win11pxe.ps1 -IsoPath .\Win11_25H2_English_x64.iso -DriverPath .\drivers\boot-nic -BootAdapterGuid '{GUID}'GUID-less builds remain available with boot-NIC preparation marked unverified.
Windows can enumerate new hardware during first boot; missing pre-existing PnP
entries alone do not prove failure. Driver staging and the fallback service table
also do not prove iSCSI first-boot compatibility. Different .sys binaries with
the same filename now stop fallback service creation instead of selecting the
first file found; byte-identical duplicates are accepted. The fallback still
cannot reproduce arbitrary INF/WDF/device installation requirements.
Output and diagnostics: builds use a unique temporary VHDX beside -OutPath.
The previous output is replaced only after image preparation, registry hive
unloads and image dismounts succeed. Failed builds retain their temporary VHDX
for inspection; a hive-unload failure deliberately leaves that disk attached.
Each run writes <OutPath>.<build-id>.build.json and a DISM log alongside the
output. The report includes source/serviced Windows versions, NIC package
versions, native DISM results, service paths, start overrides and warnings.
Complete means the build and cleanup succeeded, not that hardware boot was
tested; ColdBootValidated remains false. Keep the matching report when copying
an image. The large failed temporary images can be removed after inspection and
successful hive/disk cleanup.
PXE interface selection: the Windows menu entry tries interfaces net0 through
net63 individually, preserving existing IPv4 settings and using DHCP only when
an interface lacks an address. A successful iSCSI attachment identifies the NIC
whose MAC supplies the initiator IQN. For ordinary subnet/default-gateway routing,
it first tests attachment without a gateway; failure restores the gateway and
tries routed access. DHCP option 121 routes bypass this workaround because a
no-gateway probe would not establish on-link access. Each client's ACL must map
LUN 0 to a separate writable backstore; unique initiator IQNs alone do not isolate
NTFS volumes. The entry closes other iPXE interfaces to prevent ambiguous routing.
Driver/update scrapers (Microsoft Update Catalog):
| Script | Covers |
|---|---|
Get-IntelEthernetDrivers.ps1 |
Intel I210/I219/I225/I226, X540/X550, X710, E810, AVF |
Get-RealtekEthernetDrivers.ps1 |
RTL8125/8126/8127/8168 PCIe, RTL8153/8156/8157 USB |
Get-MarvellEthernetDrivers.ps1 |
Aquantia/Marvell AQC107/AQC113 PCIe, AQC111U USB |
Get-IntelWiFiDrivers.ps1 |
Intel Wi-Fi 6/6E/7 (post-boot convenience) |
Get-MediatekWiFiDrivers.ps1 |
MediaTek MT79xx Wi-Fi (post-boot convenience) |
Get-QualcommWiFiDrivers.ps1 |
Qualcomm WCN/FastConnect Wi-Fi (post-boot convenience) |
Get-IntelGraphicsDrivers.ps1 |
Intel Arc / Iris Xe / UHD GPU (post-boot convenience) |
Get-NvidiaGraphicsDrivers.ps1 |
NVIDIA GeForce + RTX/Quadro GPU (post-boot convenience) |
Get-AmdGraphicsDrivers.ps1 |
AMD Radeon RX + Radeon Pro GPU (post-boot convenience) |
Get-Win11CumulativeUpdates.ps1 |
Latest monthly CU + checkpoint chain + SSU per Windows version |
Status: offline build hardening is implemented; first boot, OOBE and subsequent cold boots still require testing on the intended NIC, firmware and Windows build. There is no automatic WinPE provisioning stage. If offline NIC preparation is insufficient, Setup over an iBFT-attached LUN remains an alternative.
Run as root on an Arch system with archiso installed. Clones the releng profile,
applies customizations (local pacman.conf, zstd squashfs, archlinux-custom ISO
name, a large multi-desktop package set), and injects a systemd generator +
configure-desktop.sh that enable exactly one desktop environment per boot based on
the desktop= kernel argument (gnome, kde, xfce, sway, enlightenment — selected by
the corresponding iPXE menu entry). Outputs the ISO plus extracted
vmlinuz-linux / initramfs-linux.img / airootfs.sfs into /srv/http/pxe/archiso
(or ./archiso when not on the server) for HTTP PXE boot.
One convergent script per platform. Package-manager
refreshes and updates normally run on each pass (including Arch's full pacman -Syu and AUR
update). They replaced the earlier comtrya manifests; comtrya is
unmaintained upstream. Run from any directory: the Linux scripts resolve their config
payloads (files/) relative to their own location.
macOS now has setup-macos-workstation.sh, targeting native Apple Silicon on
macOS 26 and macOS 27. Its default core profile includes Linux CLI parity, wget and Go,
Python/Rust, everyday apps and the portable Bash configuration. Full adds
large toolchains, Java/Maven/Gradle, stable Android SDK/build-tools/NDK, optional
apps and games. All Store apps and supplemental game-data downloads are excluded.
Full prints the per-engine data directories to populate manually.
Start with ./setup-macos-workstation.sh --dry-run or --check; both are offline
and read-only. Apply as the console user with no arguments for core, or
--profile full. --no-upgrade retains installed versions; Xcode selection,
Sharing and power settings each require their explicit --with-* flag.
Exit codes are 0 for satisfied/dry-run, 1 for failures and 2 for drift/manual work.
See the macOS guide, approved plan
and package comparison for ownership, exclusions,
manual steps and validation limits. Initial validation uses mocked tests and
read-only previews; a clean-machine installation smoke test remains outstanding.
Fedora and Arch install Balun alongside Tributary (balun from jmsqrd/balun
COPR on Fedora, balun-bin from the AUR on Arch). Both also install Cockpit with
file management, package updates, Podman containers, and storage/LVM support,
and start cockpit.socket for access at https://localhost:9090.
setup-arch-workstation.sh— run as your normal user; sudo is used for the privileged steps (AUR builds refuse to run as root). Requires an existing GRUB installation, safely enables[multilib], runspacman -Syu, installs the official package set and detected Intel/AMD microcode, installs dotfiles/system config and zram policy fromfiles/, explicitly generates and validates every dracut image before removing mkinitcpio, then enables services and GDM settings. AUR work is last: a self-bootstrappedyayinteractively presents PKGBUILD diffs, updates installed AUR packages (including VCS/devel packages), and installs the requested set. Arch's signed repositories provide Code OSS, OpenCode, Codex CLI, and Zed; the AUR supplies Claude Code and the native Antigravity 2.0+ desktop/CLI. The script removes VSCodium, Antigravity IDE, and any installed Antigravity 1.x package before installing their replacements. The package selection intentionally includes Intel/AMD graphics support and NVIDIA open modules for bothlinuxandlinux-lts. It installs the AURr8152-dkmspackage only below kernel 7.2; on 7.2+ it purges that out-of-tree driver, regenerates the initramfs, and reports when a loaded out-of-tree module requires a reboot to activate the in-tree driver. GNOME uses Vitals for sensors, Dash to Dock from the AUR, and the bundled System Monitor extension withlibgtop.setup-fedora-workstation.sh— run as your normal user; Fedora 41+ (dnf5). Adds the signed third-party repos (files/etc/yum.repos.d/, the Tributary/Balun coprs, RPM Fusion, Microsoft VS Code, Chrome, Claude Code, sing-box; PowerShell/NVIDIA/Steam repos on x86_64), installs the dnf and flatpak sets (plus the x86_64-only 32-bit/Steam extras), applies available DNF/Flatpak updates, and installs Zed plus native AI tools. Both x86_64 and aarch64 are supported, including Fedora Asahi's 16K kernel variant. DNF reconciles the package/group set directly with visible output and automatic confirmation; there is no separate user-cache group query to block on hidden repository-key prompts. Chrome and GitHub CLI are installed on both architectures; ARM64 PowerShell uses Microsoft's checksum-verified release archive. Installsdnf5-plugin-automaticand enablesdnf5-automatic.timerimmediately, with the controller setup'sapply_updates = yesandreboot = when-neededpolicy in/etc/dnf/automatic.conf. Antigravity 2.0+ and its CLI, OpenCode, and Zed resolve the latest stable native artifacts and their published checksums on each run; Codex uses OpenAI's checksum-verifying current-release installer; Claude Code uses Anthropic's signed RPM repository. The abandoned unsigned Antigravity 1.x RPM/repository, its exact script-managed IDE settings, and VSCodium are removed, while customized settings or repo files are preserved (and retired repos disabled). The script also installs a deliberately fixed, checksum-pinned Ookla speedtest CLI. Below kernel 7.2 it resolves the latest stable r8152 USB NIC driver release to one upstream commit per run and installs it via DKMS; on 7.2+ it purges the out-of-tree driver, reconciles every installed-kernel initramfs, and reports when a loaded out-of-tree module requires a reboot to activate the in-tree driver. The script then applies dotfiles, zram policy, services, and GDM settings. Secure Boot hosts are warned when the DKMS MOK still needs enrollment.setup-win11-workstation.ps1— run from an elevated PowerShell (5.1 is enough):powershell -ExecutionPolicy Bypass -File .\setup-win11-workstation.ps1. Sets up OpenSSH Server viaenable-openssh-win11.ps1, then installs the winget package set. Every managed package is checked for upgrades on every run unless explicitly marked presence-only; the deliberately fixed Speedtest CLI is currently the only such package. The highest stable Python 3 minor-package channel is resolved from WinGet rather than hard-coded. Antigravity IDE and VSCodium are removed, with Microsoft VS Code kept as the supported Windows editor. Onewinget exportsnapshot decides the remaining state;--include-unknownkeeps versionless registrations from silently freezing, so those vendor installers may run again. "Already installed" / "reboot required" results count as success, and any other failure is reported at the end (exit code 1) without stopping the run.-HyperVadditionally enables the supported Windows optional feature on Pro, Enterprise, or Education; Windows 11 Home is rejected.
Missing package-set entries are installed and existing Arch/AUR packages are updated.
Config files are rewritten only when their content, type, mode, or ownership differs;
follow-ups (grub-mkconfig, sysctl, dconf update, DKMS/dracut builds) run only when
their inputs or validation require them. Workstation zram uses zstd, priority 100, and
min(RAM, 8 GiB). Linux systemd services are enabled, not started, and come up on the
next boot. The Windows OpenSSH helper starts sshd immediately and opens Microsoft's
standard inbound TCP/22 firewall rule on all profiles; narrow that rule separately if
the workstation's policy requires it.
Windows helpers (called by setup-win11-workstation.ps1, also usable standalone):
enable-openssh-win11.ps1— installs the OpenSSH Server capability, starts/enablessshd, ensures the firewall rule, sets PowerShell as the default SSH shell.enable-hyperv-win11.ps1— enables Hyper-V through the supported optional-feature API on eligible Windows editions and refuses the unsupported Windows 11 Home hack.
Dotfiles and system config consumed by the workstation setup scripts: bashrc,
vimrc, grub defaults, etc/locale.conf, etc/sysctl.d/99-inotify.conf,
etc/systemd/zram-generator.conf,
etc/cron.daily/pacman-update (unattended Arch updates + reboot scheduling),
etc/dnf/automatic.conf (Fedora automatic updates + reboot when needed),
etc/dconf/db/gdm.d/10-font-settings, Fedora repo definitions under
etc/yum.repos.d/, and the Fedora Antigravity desktop entry under
usr/share/applications/. etc/pacman.conf is kept for reference only — the Arch
script deliberately does not install it.
Interactive detector/cross-flasher for ConnectX-3 through ConnectX-7 NICs. Queries
devices with mstflint, downloads stock NVIDIA firmware, flashes (including
OEM→stock cross-flash with -allow_psid_change after explicit confirmation), and
configures UEFI/legacy boot ROM options via mstconfig. Requires root, mstflint,
and pciutils. Firmware flashing is inherently risky — read every prompt.
- One-time: point DHCP at the TFTP server (
ipxe.efifor UEFI,undionly.kpxefor BIOS); setENABLE_TFTP_BOOTSTRAP=truefor the first run to fetch the binaries. - Periodically (cron or manual):
./update-pxe-images.shon the server to refresh distro versions and regenerate the menu. - Optional:
sudo ./build_archiso.shto rebuild the custom Arch image; enableENABLE_CUSTOM_ARCHISO. - Optional: build the Win11 VHDX on the Windows machine, convert to raw, configure
the iSCSI target, enable
ENABLE_WIN11_PXE. - After installing an OS on a workstation: run the matching
setup-*-workstation.*script (re-run any time to converge).
update-pxe-images.shwrites to the live server paths and needs root; pass--test(orDRY_RUN=true) to generate into./pxe_test/instead. It publishesdefault.ipxeatomically and keeps a.bakof the previous menu. SetGITHUB_TOKENto avoid the 60-req/hr unauthenticated GitHub API rate limit.- CI discovers every Bash and PowerShell/data file instead of relying on a hand-kept
list. It runs actionlint on workflows, Bash syntax + ShellCheck, PowerShell parsing +
PSScriptAnalyzer with a no-growth warning baseline, imports every
.psd1, and parses/tests the Windows workstation helpers under both PowerShell Core and an actual Windows PowerShell 5.1 runner. It also runs the catalog, WinGet-inventory, Hyper-V state, file-convergence, Arch kernel-reboot, and zram-generator tests undertests/. The test scripts can be run locally; the zram test requiressystemd-zram-generatorand the static checks require ShellCheck and PSScriptAnalyzer 1.25.0. - Build artifacts (
*.vhdx,*.iso,*.img,*.raw,pxe_test/,archiso/,custom_archiso/) are gitignored. - Server address/ports, mirror URLs, and the iSCSI IQN namespace
(
iqn.2026-02.lan.pxe) are currently hard-coded constants at the top ofupdate-pxe-images.shand inside the Win11 stanza. - The Win11 image intentionally trades security for LAN convenience (blank-password autologon admin, hardware-check bypasses, no CHAP on the target) — do not expose any of this beyond a trusted network.