
I’ve got an HPE ProLiant DL20 Gen10 Plus sitting in the homelab, quietly running Debian 13. Debian, as in: not RedHat, not a RedHat derivative, not anything HPE’s Service Pack for ProLiant (SPP) actually wants to talk to when it comes to the installable, OS-native update path. SPP’s native package installer is RPM-based, full stop. Debian gets a polite shrug. 🤷
Normally that wouldn’t matter much — firmware doesn’t get stale overnight — but I wanted to check whether anything on the box needed love. Spoiler: yes, a little. iLO 5 was one version behind (3.20 vs. the released 3.21), and I wanted the full picture instead of manually chasing down a changelog PDF for every single component like System ROM, SPS, the NIC firmware, and whatever else lives in that 14-item firmware inventory. I wanted the “boot into a tool, let it scan everything, tell me what’s stale” experience. That tool exists. It’s called SUM (Smart Update Manager), it ships inside the SPP ISO, and — crucially — the bootable ISO variant doesn’t care what’s installed on your disks. It boots its own environment. In theory, completely OS-agnostic. Debian problem solved, right? 😌
Reader, it was not that simple. Nothing ever is.
💾 Act One: The HP USB Key Utility, Reprising Its Greatest Flop
Long-time readers might remember an earlier post where I already fought this exact battle with HPE’s official ISO-to-USB tool. It was old then. It’s older now. It still doesn’t reliably work — same story, different day: silent failures, a USB key that the server’s boot menu politely refuses to acknowledge exists. HPE doesn’t seem to be putting much love into this tool anymore, and it shows. 🪦
🔌 Act Two: Rufus in DD Mode, Stopping Cold
Plan B: Rufus, in DD mode specifically — the mode that writes the image as a raw, bit-for-bit block copy instead of Rufus’s usual ISO-to-FAT32 reinterpretation, exactly what a hybrid bootable ISO wants. Plugged it in, booted from it… and it just stopped, mid-boot, apparently somewhere around GRUB. Not a clean “unbootable device,” not a helpful error either — just stuck. Genuinely unclear why — and at some point in a homelab, “I don’t know why” has to become “moving on.” ➡️
📡 Act Three: iLO Doesn’t Need a USB Stick At All
iLO Advanced has Virtual Media — point iLO’s virtual CD/DVD at an ISO, the server boots from it like a real optical drive, streamed over the network. And honestly, once it clicked, it clicked hard: this is objectively the better way to do this, tooling drama aside. The server lives in the basement, on a rack, doing its rack-in-a-basement thing. The USB-stick approach means: walk downstairs, open the rack, find the right port, plug in the stick, walk back upstairs, do the update, walk back downstairs again to retrieve the stick once it’s done — two basement trips for one firmware update, purely so a physical object can briefly touch a physical port. Streaming the ISO over the network means I get to do all of this from my desk, in a comfortable chair, with coffee ☕, while the actual hardware never has to know I own a USB stick at all. Worth fighting through a few layers of tooling nonsense for.
Except — and this is where iLO’s Virtual Media UI quietly reveals its opinion on the matter — it doesn’t accept a file upload from your browser. It wants a URL. Fine, I have Linux boxes lying around, surely I can serve one (1) ISO file over HTTP. 🙃
🐔🥚 Act Four: The Chicken, the Egg, and the VM Living On the Wrong Box
My favorite part, because I fell for it completely and only realized my mistake mid-facepalm.
First instinct: host the ISO from a Linux VM I already had running. Two minutes, done, virtual media mounted, feeling very pleased with myself. Then it was time to actually reboot the DL20 to boot from that mounted image.
Which — you can probably see this coming from orbit 🛰️ — also rebooted the VM I was using to serve the ISO, because that VM lives on that exact physical server. A perfectly circular dependency: the server needs the ISO to boot, the ISO is served by something that needs the server to be up. The moment the reboot started, my file server vanished mid-flight, and iLO was left holding a virtual CD-ROM connected to absolutely nothing. Firmware inventory afterward: unchanged, down to the last digit — because nothing had actually been read past the initial mount handshake.
Lesson relearned the hard way: when you reboot a physical host, anything that host is hosting goes down with it. Groundbreaking stuff, I know. 🤦
🖥️ Act Five: Serving It From Somewhere That Actually Stays Up
Fix: host the ISO from the Windows client instead — a machine with zero opinion about the DL20’s power state. Python’s built-in web server felt like the obvious two-second solution:
python -m http.server 8000Pointed iLO at it, mounted it, rebooted into the one-time boot menu, selected the virtual CD/DVD… and it still didn’t come up cleanly. Progress, not success. Time to actually think about what’s happening instead of throwing tools at it.
🕵️ Interlude: Why a Virtual CD-ROM Is Not a Download
The actual technical meat of this whole saga: mounting an ISO over the network is not the same as downloading a file.
A real optical drive doesn’t get slurped into memory up front. The bootloader reads specific sectors on demand, jumping around the disc structure exactly as the ISO9660 filesystem layout dictates — a few bytes from the boot catalog here, a file fragment somewhere in the middle there. Virtual Media emulates exactly that behavior over HTTP: iLO fires off requests like “give me bytes 5,368,709,120 through 5,368,711,168, please” — a tiny slice, at an arbitrary offset, of a 9.8 GB file.
The HTTP mechanism for exactly this is the Range request (Range: bytes=X-Y), answered with 206 Partial Content plus a matching Content-Range header, containing only the requested slice.
Python’s classic http.server does not do this. At all. Tested it directly: sent a Range request for a 1 KB slice, got back 200 OK and the entire 9.8 GB file, Range header completely ignored. For a small file, technically wrong but nobody notices. For a 9.8 GB SPP ISO being asked for on every single tiny sector read, that’s the difference between instant and functionally infinite ♾️ — which, from iLO’s side, looks exactly like a broken or empty virtual drive.
The fix is a tiny drop-in replacement:
python -m pip install rangehttpserver
python -m RangeHTTPServer --bind 0.0.0.0 8000(Note the python -m pip instead of a bare pip — on a fresh Windows Python install, pip.exe isn’t reliably on PATH even though python.exe is. Calling pip as a module through the interpreter sidesteps that entirely.)
🔥 Plot Twist: The Firewall Strikes Back
Swapped servers, tested the Range request again — still nothing, this time a flat-out connection timeout instead of a wrong response. Not “nobody’s home” (that would look like a refused connection), but “the packets vanish into the void” — the classic signature of a firewall silently dropping traffic rather than rejecting it outright.
Turned out Windows Defender Firewall had quietly blocked the new server: the old http.server run had already gotten an “allow” click-through at some point, but launching it as python -m RangeHTTPServer apparently counted as different enough of a program context to need its own fresh permission prompt — one I’d missed. One firewall exception later 🔓, both problems were finally gone at the same time:
HTTP/1.0 206 Partial Content
Content-Range: bytes 1000-2000/9844506624
Accept-Ranges: bytesReachable, and Range-capable. Exactly what a virtual optical drive wants to see. ✅
📋 What Was Actually Sitting There, Version-Wise
For anyone curious what a DL20 Gen10 Plus’s firmware inventory even looks like — 14 components, pulled straight from iLO’s Redfish API instead of clicking through the GUI one page at a time:
- iLO 5 — v3.20 (one release behind; 3.21 is out)
- System ROM (active) — U60 v2.64
- System ROM (redundant/backup slot) — U60 v2.50, intentionally lagging, that’s what the backup slot is for
- Intelligent Provisioning, SPS, TPM, the onboard BCM5720 NIC, video controller, and both drive firmwares
The whole point of booting the SPP ISO instead of hand-chasing each .fwpkg file one by one: SUM scans all of it in a single pass and tells me exactly what’s stale. No RedHat required, no USB stick required, no second basement trip required. 🎉
🎓 The Moral of the Story
Three tools failed or half-failed before the one that actually worked — and that one only worked once I stopped treating “serve a file over HTTP” as a solved problem and remembered that virtual media doesn’t download, it reads sectors, the same way a physical drive does. Add a firewall prompt I’d blinked and missed, and that’s a solid afternoon spent on what should have been a five-minute task. Homelab firmware updates: never as simple as “click update,” always an opportunity to relearn something you technically already knew. 😅
Next up: whatever SUM actually finds once it boots properly. Stay tuned.
📸 A few screenshots of the journey — Rufus failing quietly, the Redfish firmware inventory, the Range-request headers finally looking right — are below.








