◉ Pulse
FluxBilling-app avatar
#23 today

FluxBilling-app/FluxBilling-OS-Installer

Shell AI #autoinstall #bare-metal #datacenter #hosting

A 3 MB iPXE boot ISO that installs 20+ server operating systems unattended — Ubuntu, Debian, AlmaLinux, Rocky, CentOS Stream, openSUSE. No PXE server, no DHCP, no config host.

Created Jul 21, 2026
Stars
12
Today
+12
Forks
1
Quality
100/100
Momentum
21

README

Fetched from GitHub on Oct 30, 2026, 11:04 PM UTC · README.md

View original on GitHub

Third-party content — Open Source Pulse is not the owner of this repository.

This README belongs to FluxBilling-app/FluxBilling-OS-Installer and its contributors. We fetch it directly from the project’s public GitHub repository and display it for reference only. All text, code, images and trademarks remain the property of their respective authors. See the repository for its license terms. Copyright / takedown policy.

FluxBilling

FluxBilling OS Installer

A 3 MB boot ISO that installs 20+ server operating systems — fully automated.
Free and open source, from FluxBilling.app — billing, DCIM and IPAM for hosting providers.


Rack the server, attach the ISO to iDRAC/iLO/IPMI virtual media, answer five prompts, pick an OS, walk away. It reboots into a configured system with SSH root login.

Every heavy payload — kernels, initrds, install ISOs — streams at boot over the data NIC you choose in the menu, straight from the official distro mirrors. The slow management port only ever carries the 3 MB image, and there is no private config webserver: installer identity and network config are generated on the machine itself from your answers.

  • Tiny — ~3 MB, attaches over IPMI virtual media in seconds.
  • Zero-touch — hostname, static IP and root password typed once.
  • No PXE server, no DHCP — static IP from the menu; works in any colo. That holds for the installer image too, not just the installed system: the Ubuntu seed carries a network-config so cloud-init configures the live environment from the address you typed instead of falling back to DHCP and waiting for a lease that is never coming.
  • Manual mode — one toggle boots the same installer interactively.
  • BIOS + UEFI, serial console (SOL) mirrored, /31 subnets supported.

Supported operating systems

Family Versions Automated config
Ubuntu (subiquity) 26.04 LTS, 24.04 LTS, 22.04 LTS NoCloud seed generated at boot
Ubuntu (d-i) 20.04, 18.04 preseed + cmdline
Debian 13, 12, 11 preseed + cmdline
AlmaLinux 10, 9, 8 kickstart (%pre from cmdline)
Rocky Linux 10, 9, 8 kickstart
CentOS Stream 10, 9 kickstart
Oracle Linux† 10, 9, 8 kickstart (same file as Alma/Rocky)
openSUSE Leap 15.6 AutoYaST profile
openSUSE Leap 16.0 Agama profile injected into the initrd
Proxmox VE† 9 (9.2), 8 (8.4) answer.toml generated in-installer from cmdline

† Oracle publishes no netboot images and Proxmox no netboot installer at all, so these entries boot kernel/initrd (and Oracle's anaconda stage2) from this repo's signed boot-* release — they stay on the menu but fail cleanly until that release is cut (see docs/SIGNED-BOOT.md and src/sign-boot-images.sh). The Proxmox install ISO itself streams unmodified from download.proxmox.com into RAM, where the stock installer finds it as /proxmox.iso — manual mode is the ordinary Proxmox GUI installer, automated mode generates the official answer.toml on the machine from your typed answers (password as a SHA-512 hash, never plaintext at rest).

Quick start

  1. Grab FluxBilling-OS-Installer_v1.6.iso from Releases — or build it.

  2. Attach via virtual media — or flash a USB stick:

    # macOS - replace diskN with the USB stick
    diskutil unmountDisk /dev/diskN
    sudo dd if=FluxBilling-OS-Installer_v1.6.iso of=/dev/rdiskN bs=1m
    # Linux - replace sdX with the USB stick
    sudo dd if=FluxBilling-OS-Installer_v1.6.iso of=/dev/sdX bs=1M status=progress conv=fsync

    Windows — Windows has no dd. Use Rufus: select the ISO, and when it asks, pick DD Image mode (not ISO mode), then Start.

    USB boot needs a hybrid MBR. Virtual media — the intended path — is unaffected: iDRAC/iLO present the image as a CD and El Torito handles it. Verify a build is USB-bootable before trusting a stick: xxd -s 510 -l 2 *.iso must read 55aa, not 0000.

  3. Boot it and answer:

    Port number [ENTER = 0]             <- live NIC list (pick the data NIC)
    IP / subnet: 203.0.113.111/27       <- one field; /1../31 (incl. /31 p2p)
    Gateway [ENTER = 203.0.113.97]      <- auto-calculated, ENTER accepts
    Hostname:
    Password:                           <- hidden (TAB to the field, ENTER)
    
  4. Review screen, fix any field, pick an OS.

  5. Automated mode asks Erase every disk and install? — answer Yes. The OS goes on the first disk and every disk in the server is wiped first; see Disks. The default is No, which goes back to the OS menu without touching anything. Done.

The OS menu opens with two toggles. Install mode switches AUTOMATED (answer files injected, zero-touch, every disk erased after you confirm) and MANUAL (same installer, no answer file, driven by hand — nothing is erased for you). Installer output picks which console the installer UI actually draws on - SOL (serial, the automated default and what a headless node gives you) or Video (the iDRAC/iLO/VNC screen, the manual default). Kernel messages go to both either way, so a video console left on SOL shows dmesg, then nothing: that silence is the installer running elsewhere, not a hang. BOOTIF=01-<mac> lets every installer find the boot NIC by MAC, so there is no NIC-name guessing on any hardware.

How it works

One iPXE image with a custom CIDR parser (fluxcidr, C, compiled in) and the payload files listed in build.sh's EMBEDLIST. At boot iPXE fetches the official kernel/initrd for the chosen OS and injects the matching answer file into the initrd in memory (cpio append) — no vendor artifact is ever rebuilt or redistributed. Answer files ride under flux-* names so no installer auto-probes them during a manual install.

Per-family mechanics, mirror URLs and the hard-won gotchas are documented inline in fluxbilling.ipxe and src/builder.Dockerfile.

Surviving upstream moves

Every URL is baked in at build time, and an ISO burned to a customer's iDRAC cannot be edited — so an upstream move would otherwise kill that menu entry forever. Two mechanisms cover it, neither of which needs FluxBilling to host anything:

  • Fallback hosts. A failed casper fetch retries old-releases.ubuntu.com, where Ubuntu moves superseded point releases; the d-i entries walk a country mirror and then the archive host (archive.debian.org for a deleted Debian suite). Both paths are exercised before a release by booting ISOs with the primary host deliberately dead.
  • A watchdog. upstream-watch probes every URL the menu fetches — generated from the menu itself by src/menu-urls.sh, never hand-copied — the way iPXE fetches it, and opens a bump PR when Ubuntu supersedes a pinned release.
  • A pairing check, on every entry. Each entry boots images from one upstream path and then has the installer download a payload — an ISO, a repo, an apt mirror — from another, and the two sides are refreshed on different schedules. Ubuntu 24.04 showed what that costs: Canonical rebuilds <point>/netboot/ in place while the ISO beside it stays frozen, casper found a UUID that did not match, unmounted the ISO it had just downloaded and panicked onto /dev/console — the serial line in automated mode, so the operator watching the video console saw nothing at all. src/boot-pairing-check.sh now asserts the pairing for all 23 entries on every push: textually where both halves come from one menu variable (Debian, Alma/Rocky/CentOS, Leap 15.6), and by content where they do not — the netboot kernel must be one of the kernels inside the exact ISO casper downloads, the Leap 16 loader kernel must be the one inside the Agama ISO, the Proxmox ISO the menu boots must be the one the signing manifest extracted from. An entry with no rule fails the build, so the next distro cannot ship unverified, and src/pairing-selftest.sh proves the gate still rejects each breakage it was written for. The Ubuntu entries boot from the codename tree (noble/, resolute/), whose netboot images upstream rebuilds alongside the newest point-release ISO: 26.04 rides the ubuntu-26.04-latest-…iso alias, and 24.04 names that ISO (24.04.5) itself, since Canonical stopped serving the noble alias; 22.04 has no codename netboot tree, so it keeps a pin frozen on both halves.
  • A readable failure. If an installer does stop, it says so on every console the machine has. Stock casper prints its reason and opens its debug shell on a single console — the serial line in automated mode — which is how a real failure looked like a frozen screen on an iDRAC. A panic() wrapper injected as /conf/param.conf prints a labelled INSTALL FAILED banner with the reason to the video console and the serial line, states that nothing was written to the target disk, and then holds: it never reboots, and it ignores a panic= boot argument so a wedge cannot turn into a silent reboot loop. The dracut-based installers (Alma, Rocky, CentOS Stream, Oracle, Leap 16.0) get the same banner from an emergency hook, run just before dracut opens its emergency shell. dracut keeps that hook directory under usr/lib on EL8/EL9 and under var/lib on EL10 and Leap 16, and no injected path reaches both — so a small /etc/conf.d snippet copies the hook into whichever one dracut itself uses, at boot. The anaconda entries also have to get to that shell when the mirror or the network is down, which stock dracut does not do in any useful time: anaconda retries its installer image on every pass of dracut's initqueue, and dracut gives up only after 360 passes — a count, not a clock. With nothing answering, one pass is a stack of curl timeouts; measured on Alma 9 that put the shell 2½ hours (mirror refusing connections) to almost four days (every SYN dropped) away, with nothing on screen but failed to fetch stage2 scrolling past. src/flux-giveup.sh, installed by the same snippet, gives up after five minutes of failed passes instead, caps each curl attempt so a pass cannot overshoot by much, and puts the mirror host and curl's last error in the banner. A download that is still running is never cut short, and exiting the shell (manual mode) retries for another five minutes. Leap 16.0 had the same hole in a different place: dracut's livenet module fetches the Agama ISO inside a single initqueue pass — 100 tries, 5 s apart — and in QEMU each try took 92 s with DNS unreachable and 5 minutes with every SYN dropped, so that one pass ran 2½ to 8½ hours before dracut even started counting its passes. The same job hands that loop ten tries instead, under the same curl caps, and opens the shell on the very next pass: the banner came 4 minutes after the first try with DNS down and 6 with every SYN dropped. Resetting the server is what returns you to the boot menu — iPXE is gone once a kernel is running, so there is no way back to it from inside the installer. src/console-ux-test.sh asserts all of that, including the case that caused the original bug: only ttyS0 registered, banner still reaches the video console.
  • A visible, fast download. casper fetches a 3–4 GB ISO with wget, whose progress bar goes to one console — so the other one shows nothing for as long as the fetch takes, which is how a working install gets power-cycled by hand. A watcher injected as part of /conf/param.conf mirrors the download to the consoles wget is not drawing on. The same hook also picks where to fetch from: src/flux-mirror-pick gives the origin a two-second trial and, if it is slow, races Ubuntu mirrors and moves to the fastest one that beats it by a clear margin. A mirror copy is mounted with casper's own matches_uuid check restored, so a mirror that is a different compose is rejected and the origin is used instead — measured on a customer box whose unmetered 10 Gbps port still only pulled 0.8 MB/s from releases.ubuntu.com.

Disks

Automated mode installs to the first disk and wipes every disk in the server — after asking. Picking an OS in AUTOMATED mode opens an Erase every disk and install? screen. No is the default and returns to the OS menu; Yes is the only thing that authorises a wipe (it adds fluxwipe=1 to the kernel command line, and nothing is wiped without it). MANUAL mode never asks and never wipes: the installer is yours to drive.

One rule, src/flux-disks, decides for every entry, so Ubuntu, Debian, the EL family, openSUSE and Proxmox all agree on which disk is "first" (Ubuntu 22.04+ used to take the largest disk, and Leap whatever its proposal settled on):

  • First means the first eligible whole disk in kernel-name order — the order /sys/block sorts in: nvme0n1 before nvme1n1, NVMe before SATA/SAS/RAID volumes (sda, sdb, …), those before virtio (vda). On a box that mixes NVMe with a RAID volume or a BOSS card, the OS therefore goes on nvme0n1.
  • Never touched, never chosen: removable media, anything attached over USB (including the stick this ISO was booted from and BMC virtual media), Fibre Channel and iSCSI LUNs (shared storage is someone else's data), read-only and empty devices, and virtual devices (loop, zram, md, dm, …).
  • The wipe runs before the installer looks at the disks. It stops whatever lives on them (swap, md arrays, LVM, dm-crypt), zeroes the first and last 16 MiB of every partition and of every disk — partition tables (MBR and both GPT copies), RAID metadata, LVM, ZFS labels, LUKS headers and filesystem superblocks — and then discards the whole device on SSD and NVMe, which drops the data itself. It takes seconds to a few minutes, not hours.
  • What it does not do: overwrite the rest of a spinning disk. The old data in the middle of an HDD is unreachable by any OS but recoverable with forensic tools. If that matters, run a dedicated erase (hdparm security erase, nvme format -s1, shred) before installing.
  • A disk that is still busy after all that — something the installer itself depends on — is skipped, not pulled out from under it, and the log says so.
  • No eligible disk at all: nothing is wiped, and the installer stops (d-i at its own disk question) rather than guess.

The installer logs what it chose and what it wiped — FluxBilling: install disk: … and FluxBilling: wiped … in the kernel log (dmesg) and the installer's own log. src/disks-test.sh proves the rule against a fake /sys and /dev under dash, bash and d-i's busybox, and holds every installer's copy of it to the one file.

The Ubuntu 18.04/20.04 and Proxmox entries carry their answer files inside the signed boot-* release images, so they follow this rule once that release is cut with the current src/sign-boot-images.sh; an image cut before it installs to the first disk without wiping the others.

Requirements & limits

  • RAM: Ubuntu 22.04+ stream the full live ISO to RAM — 8 GB+. Proxmox VE streams its full install ISO the same way — 6 GB+. Alma/Rocky/CentOS/Oracle stage2 — 4 GB+. Leap 16.0 — 2.5 GB+.
  • CPU: Alma/Rocky/Oracle 10 and CentOS Stream 10 need x86_64-v3 (Haswell/EPYC or newer). Older Xeons: use the 9.x entries.
  • Internet reachability from the static IP you enter.
  • Password rides the kernel command line: letters, digits and ._-!@#%^*+= are safe; avoid spaces, quotes, ;, \, /.
  • Fallback hostname if the prompt arrives empty: fluxserver. There is no fallback password — if fluxpass= is missing, both accounts are left locked rather than given a known default.
  • Secure Boot must be off. ipxe.efi is built here and is not signed by a Microsoft-trusted CA, so UEFI firmware with Secure Boot enabled refuses to load it. No practical fix exists for a custom iPXE build; disable Secure Boot for the install, and re-enable it afterwards if the installed OS ships a signed shim (Ubuntu, Debian, Alma, Rocky and Leap all do).
  • Tested end-to-end: all automated entries (24 at the time, including the since-removed 25.10), under both legacy BIOS (SeaBIOS) and UEFI (OVMF) — each install ran to completion in KVM, the guest rebooted off its own disk and accepted a root SSH login with the menu-typed password, with hostname, static IP and os-release asserted (48/48 PASS, 2026-08-15). Ubuntu 24.04 additionally verified on physical Dell iDRAC; the other entries share the same verified mechanics but still deserve a hardware smoke test on real NICs and RAID controllers, which QEMU's single virtio disk and slirp network do not exercise.

Security

What is and is not protected, honestly:

  • Packages are verified. APT and DNF check every package against the distro GPG keys, so what lands on disk is signature-checked end to end.
  • Bulk downloads use HTTPS. The Ubuntu ISO, the anaconda stage2 and repos, the Leap live squashfs and install= tree are all fetched by the installer, which carries a full CA bundle.
  • Kernel and initrd fetches are plain HTTP and unverified until the first signed boot-* release ships. The binary now bakes in a set of public root CAs (CERT=/TRUST= in build.sh), so the https fetches iPXE does make — the 22.04 GitHub release, and mirrors that redirect http→https — validate with no ca.ipxe.org dependency; but the plain-http kernel/initrd fetches still trust the network. Run the installer on a trusted management network, and cut the signed release to close the gap for good.
  • Credentials never persist in cleartext. The root password rides the kernel command line, so every family creates its accounts locked, sets the real password through chpasswd (hash only, in /etc/shadow), and scrubs fluxpass= out of the installer logs on first boot. One exception: a manual openSUSE Leap 16.0 install also carries live.password= (the Agama web-UI login) on the command line, and manual mode runs no profile — so nothing installs the scrub. Clear /var/log/agama-installation after a manual Leap 16 install, or use automated mode, which never passes it. Proxmox has no post-install hook a stock ISO can run, so its generated answer.toml carries a SHA-512 crypt hash instead of the password — what /etc/shadow would hold anyway — and the plaintext never exists outside the live installer's kernel command line.
  • The Proxmox install ISO is fetched over plain HTTP — forced, not chosen: download.proxmox.com's TLS certificate does not name that host (it names the cdn.proxmox.com pool), so an https fetch fails hostname validation. The signed boot-* release stages a detached signature for the exact ISO (proxmox-N-iso.sig, fetched for signing over valid https from enterprise.proxmox.com), closing this the same way the kernel/initrd gap closes.
  • Root SSH with password authentication is enabled on every family. That is a deliberate provisioning convenience — harden it immediately after install if the box faces the internet.

To close the kernel/initrd gap, see docs/SIGNED-BOOT.md: mirror and sign the ~350 MB of boot images, bake your own CA fingerprint into the iPXE binary, and let imgverify reject anything tampered with — over plain HTTP, with no dependency on anyone else's PKI.

Building

Needs Docker. Everything is pinned:

./build.sh        # outputs FluxBilling-OS-Installer_v1.6.iso

First run bakes the builder image (~10 min); every rebuild after that is ~15 seconds. The build is reproducible from a clean clone: every toolchain version, iPXE commit and payload URL is pinned in src/builder.Dockerfile and build.sh.

Why we built this

FluxBilling does not use this ISO. Inside the panel, bare-metal deployment and IPAM are fully automated — nothing to attach, nothing to type.

But plenty of machines sit outside a panel: a box you're rebuilding, a one-off install, a rack you don't manage yet, someone else's colo. That is the job this image does, and we release it free because provisioning a server should not require a PXE stack or an afternoon of virtual media.

Billing, DCIM and IPAM for hosting providers — in one place.
Servers, IPs, invoices and clients, with bare-metal deployment fully automated inside the panel. Built like a native app.

→ See the panel

Thanks

Thank you @AlexIancu98 for your contribution.

License

GPL-2.0-or-later — see LICENSE.

The ISO is a modified iPXE binary (copyright Michael Brown and contributors), distributed under the GNU GPL v2 or later with iPXE's Unmodified Binary Distribution Licence exception (COPYING.UBDL). Base: iPXE commit 56a4f695. Every modification is an explicit patch step in src/builder.Dockerfile — config edits, the EFI autoexec stub, and the added fluxcidr command (src/fluxcidr_cmd.c). Corresponding source is this repository; ./build.sh rebuilds the released ISO from it. The embedded answer files are original work under the same terms.

No operating system is redistributed here — with narrow, documented exceptions. Kernels, initrds, install ISOs and repositories are fetched at boot, unmodified, from the vendors' own mirrors, except where a vendor publishes no netboot artifacts at all: the Ubuntu 22.04 kernel/initrd come from a netboot.xyz GitHub release (Canonical never published a netboot tree for that series — see the boot2204 note in fluxbilling.ipxe), and the signed boot-* release described in docs/SIGNED-BOOT.md additionally carries the Oracle Linux kernel/initrd/stage2 and the Proxmox VE installer kernel/initrd, each extracted unmodified from the vendor's official ISO (both are freely redistributable under their respective licenses; sources are the vendors' own repositories). Answer files are injected into the vendor initrd in RAM, on the operator's own machine.

Trademarks. Ubuntu is a trademark of Canonical Ltd; Debian of Software in the Public Interest, Inc; Red Hat and CentOS of Red Hat, Inc; AlmaLinux of the AlmaLinux OS Foundation; Rocky Linux of the Rocky Enterprise Software Foundation; openSUSE of SUSE LLC; Oracle and Oracle Linux of Oracle and/or its affiliates; Proxmox and Proxmox VE of Proxmox Server Solutions GmbH. All marks belong to their respective owners and are used descriptively to identify the operating systems this installer can fetch. This project is not affiliated with, sponsored by or endorsed by any of them, nor by the iPXE project or netboot.xyz.


FluxBilling OS Installer v1.6 — powered by iPXE.

Rendered by GitHub from the repository’s README. Scroll to read the full file.
First trending

Jul 22, 2026

first spotted on the list

Best rank

#23

highest position reached

Appearances

1

times on the trending list

Quality score

100

out of 100

Momentum

21

trend strength indicator

Star velocity

0.12

stars per day since creation

Activity — last 60 days

daily counts, collected every 6 hours
  • Stars
  • Forks
  • Merged PRs
  • Issues
  • Closed issues

Collecting activity data since launch — check back in a few days.

Star history

total stars per snapshot

Not enough snapshots yet — check back soon.

Rank history

position on trending · lower is better

Not enough snapshots yet — check back soon.

3D card for your website

Live HTML card with a glass surface and pointer tilt. Paste the iframe on any website.

<iframe src="https://www.notionpulse.cc/embed/FluxBilling-app/FluxBilling-OS-Installer" width="420" height="240" style="border:0;max-width:100%;background:transparent" loading="lazy" title="FluxBilling-app/FluxBilling-OS-Installer — trending on Open Source Pulse"></iframe>

Stars badge

Show current stars in your README or profile. Auto-updates every 6 hours.

FluxBilling-app/FluxBilling-OS-Installer stars badge
Markdown
[![FluxBilling-app/FluxBilling-OS-Installer](https://www.notionpulse.cc/api/badge/FluxBilling-app/FluxBilling-OS-Installer.svg)](https://www.notionpulse.cc/repo/FluxBilling-app/FluxBilling-OS-Installer)
HTML
<a href="https://www.notionpulse.cc/repo/FluxBilling-app/FluxBilling-OS-Installer"><img src="https://www.notionpulse.cc/api/badge/FluxBilling-app/FluxBilling-OS-Installer.svg" alt="FluxBilling-app/FluxBilling-OS-Installer stars badge" /></a>

Repository of the Day

#23 Repository of the Day

Repository of the Week

#23 Repository of the Week

Repository of the Month

#23 Repository of the Month