minute2win Windows deployment, on your terms. Downloads ↗
Early release · Windows deployment not yet verified end to end

Server reference

minute2win-server is a single Go binary with the page built in. It runs next to dnsmasq (or answers PXE itself with -pxe, below) and is where the guard lives. The page uses htmx: the server renders HTML fragments (server/web/templates/, escaped by html/template) and hx-* attributes handle polling, arming and disarming, with no app JavaScript. htmx is vendored, not loaded from a CDN, so it works offline. /api/* stays as JSON for scripts.

cd server && go build -o minute2win-server . && M2W_TOKEN=... ./minute2win-server -manifests ../manifests -data ./data

For existing DHCP/TFTP infrastructure, route the target to iPXE (for example, ipxe.efi for x64 UEFI). Give iPXE an embedded or chained script that runs the chain .../boot/${net0/mac} line above.

HTTP server flags

Flag Default Purpose
-listen :8080 HTTP address; use loopback for preview and a reachable LAN address for deployment
-manifests Auto-detected Profiles directory: current directory, executable directory, then ../manifests
-image-base Maintainer host URL serving wimboot, WinPE, BCD and boot.sdi; replace with your host
-data data State directory; an empty value keeps state in memory
-arm-ttl 2h Expiration of unused arms
-open true on Windows Open browser at startup

M2W_TOKEN is an environment variable, not a command-line flag. Boot assets and the image are served separately from the console. Read Getting started for the complete setup.

Built-in PXE (optional, -pxe)

-pxe makes minute2win-server its own PXE front end, so you don’t need dnsmasq: a proxyDHCP responder and a read-only TFTP server. It is off by default; without -pxe nothing PXE-related binds or runs.

sudo ./minute2win-server -manifests ../manifests -pxe -pxe-dir /srv/ipxe      # /srv/ipxe holds ipxe.efi, undionly.kpxe, ...
Flag Default  
-pxe off Turn the PXE front end on
-pxe-dir (required) Folder served over TFTP. Only regular files directly inside it; no subfolders, .., absolute paths, or symlinks (not even ones pointing inside: copy the file instead)
-pxe-ip receiving interface IPv4 address to advertise
-pxe-file-x64, -pxe-file-bios, -pxe-file-arm64 ipxe.efi, undionly.kpxe, ipxe-arm64.efi Boot file per architecture
-pxe-file-ia32 (empty: no offer) Boot file for 32-bit x86 UEFI (arch 6)
-pxe-dhcp-port, -pxe-proxy-port, -pxe-tftp-port 67, 4011, 69 UDP ports

Privileges. Ports 67, 69 and 4011 need root on Linux, or sudo setcap cap_net_bind_service=+ep ./minute2win-server. On Windows, run it as Administrator and allow UDP 67, 69 and 4011 inbound in the firewall. If a port can’t be bound, startup fails and says which port and why. If another process holds UDP 67 (dnsmasq or another DHCP server on the same host), it says so: stop that process or run minute2win on another host. UDP 67 is opened with SO_REUSEADDR/SO_REUSEPORT so it can share the port with a listener that allows sharing, but don’t run two PXE answerers for the same clients.

Platforms. The PXE sockets are written for Windows, macOS, FreeBSD, NetBSD and Linux on amd64, arm64, 386, arm, riscv64, ppc64le, s390x and loong64. The server builds everywhere else too, but -pxe refuses to start there with an error saying so.

Built-in or dnsmasq? Use -pxe when minute2win-server is the only boot service on the segment and you want one binary. Keep dnsmasq if you already run it, need PXE for machines that aren’t armed (menus, other OSes), or want its own DHCP. Don’t enable both on the same host.

Boot files are yours to provide. This repo does not include or download any iPXE binary (iPXE is GPL; shipping it would bring source obligations). Put your own copies in -pxe-dir: build them from https://ipxe.org, or use the iPXE project’s published signed pair that kvm-it pins (in the separate kvm-it repository, under firmware/ipxe/signed/; its scripts/fetch-ipxe-signed.sh re-downloads and checks them). For Secure Boot, put the shim and iPXE side by side in -pxe-dir (BOOTX64.EFI and IPXE.EFI) and start with -pxe-file-x64 BOOTX64.EFI. TFTP passes the requested spelling to the filesystem. Names must match case on case-sensitive filesystems; Windows may accept different case. If a client asks for a name you don’t have, the log shows tftp: ... refused "<name>".

Security. TFTP has no authentication and can’t know which MAC is asking, so anyone who can reach UDP 69 can download anything in -pxe-dir. Keep only the public iPXE binaries there. Files are opened through os.Root, so the directory confines the open itself. TFTP use is bounded: at most 64 transfers at once and 4 per client IP, each ended after 60 s or 20 s without progress, and a client’s timeout option is honoured only from 1 to 10 s. Every TFTP send has a 2 s write deadline, and a send that fails or times out ends that transfer, so a stuck socket can’t hold a slot. Logging is bounded as well: one line per client/file per minute, and two separate budgets so noise can’t drown out what matters: offers and local errors get about 20 lines a second, while things any host can trigger (malformed packets, unarmed MACs, every TFTP line) get about 5. Dropped lines are counted and reported as “N … log line(s) suppressed”. Anything from the wire, including error text, is logged quoted. The guard is still the arm: a machine that isn’t armed gets no proxyDHCP answer, and the boot script still comes from /boot/{mac}.

Status: unit-tested; seen working only in a QEMU VM on a simulated LAN (BIOS iPXE stage); never run on real PXE firmware. tests/pxe/pxe-lan.sh checks, from packet captures with no drops, that boot 1’s PXE DISCOVER is answered and the arm consumed, that boot 2’s PXE DISCOVER gets no reply, and (positive control) that after re-arming, boot 3 is answered and consumes the new arm. See verification and known issues for the remaining checks.

Windows

The Windows build (minute2win-server-X-windows-x64.zip, Authenticode-signed) is the same server: extract it, run minute2win-server.exe, and the UI opens in your browser. It prints the line a target should chain, for example http://192.168.1.50:8080/boot/${net0/mac}. Windows Firewall will ask to allow it on private networks; that is what lets the target reach it. Set M2W_TOKEN first: a laptop that can arm disk wipes should not leave the port open without one.

The natural pairing is kvm-it’s USB boot drive: the target only needs ordinary DHCP from your network, so no DHCP or TFTP server is needed. For plain PXE, enable the built-in front end with -pxe, or use an existing DHCP/TFTP service such as dnsmasq. The ordinary DHCP server still provides addresses in either case.