You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ship bootable USB installers so a user can go from bare server hardware → plug in a USB → a fully-provisioned machine, with little or no manual Linux setup. Two targets:
Each needs a provisioning system: read a user-supplied config off the USB and self-configure on first boot, so deployment is "edit one file, flash, boot."
Why the two targets need different shapes
They look similar ("boot a server, run our software") but are opposites under the hood:
Stack host
RigForge miner
State
Stateful — 100s of GB of Monero/Tari chain data, Tor onion keys, generated secrets
Stateless — no wallet, no chain, nothing to persist
Workload
Docker Compose, 7 services
One process: tuned XMRig → stratum
Needs
apt ecosystem (docker, jq, openssl), GRUB/HugePages tuning, big disk
Reflash-to-update is fine; could even run diskless/RAM-resident
Ideal form
Full distro installed to disk
Minimal/immutable appliance
This difference is the crux of the tooling choice.
Deployment options — the DIY path stays first-class
The installer/image work is additive, not a replacement. We support two ways to deploy, and neither deprecates the other:
Do-it-yourself (existing): bring your own Ubuntu/Debian, git clone, and run ./pithead setup (host) / ./rigforge.sh (miner). Full control over OS, partitioning, existing machines, and bespoke setups — this stays the documented default for people who want it.
Flash-and-go (new, this epic): a prebuilt bootable image you flash to a USB and boot — for people who want zero Linux setup.
Non-goal: removing or degrading the script-based install. pithead / rigforge.sh remain the single source of truth for provisioning logic; the image runs those same steps under the hood, so it's one codebase, two delivery methods (they can't drift apart).
Is Buildroot the right solution?
Not as a single answer. Buildroot fits the miner, not the stack host:
Miner — yes, plausibly. Buildroot produces a tiny, immutable, fixed-function image, can boot diskless from USB into RAM, and reflash-to-update suits a stateless appliance. Cost: XMRig + all tuning must be packaged in-tree, cross-compile toolchain, no runtime package manager, and updates mean rebuilding/reflashing. Proven for real appliances (e.g. Home Assistant OS is Buildroot-based).
Stack host — no. It wants Docker + a large stateful workload + apt-style flexibility, which all fight Buildroot's model (no package manager, reflash updates, heavy from-source rebuilds). Buildroot can run Docker but it's unconventional and high-maintenance here.
So: use different tools per repo. And for the miner, a lighter option than Buildroot may win (see Alpine diskless below).
Options evaluated (with research)
Stack host (install a real distro to disk):
Ubuntu autoinstall (Subiquity + cloud-init) — ⭐ best MVP fit. We already target Ubuntu Server 24.04 and have an idempotent pithead. A standard Ubuntu installer ISO + a noclouduser-data/meta-data on the USB does an unattended install, then late-commands/first-boot runs pithead setup. Lowest effort, reuses everything.
Debian preseed / debian-installer — same idea on Debian; viable, but no advantage over Ubuntu given our target.
bootc / image mode (bootable containers) — build the OS from a Containerfile, install to disk via bootc-image-builder/Anaconda, update from a container registry. Very aligned (our workload is already containers) and synergises with Release & versioning structure (single-product releases via GHCR) #44 (GHCR releases). Newer, RHEL/Fedora-centric — a bigger shift from the Ubuntu+pithead model.
Fedora CoreOS / Flatcar (Ignition) — purpose-built immutable container hosts, provisioned by a first-boot Ignition/Butane config. Great fit for "a server that runs containers," but rewrites our provisioning model and drops the pithead investment.
mkosi — build a bespoke immutable Ubuntu/Debian/Fedora disk image (golden image). Good for a reproducible image; still need a flash/dd deploy path.
Golden disk image + dd — simplest deploy (image is the installer), but hardware variance (disk size, NIC) needs cloud-init/growpart handling.
Miner (minimal appliance):
Alpine diskless mode (apkovl) — ⭐ likely the miner sweet spot. Boots from USB into RAM, config persisted as a small apkovl overlay on the USB. Tiny and immutable like Buildroot but far less effort (no from-source OS build; XMRig via package or a build step).
Buildroot — smallest/most locked-down; best if we want a true embedded appliance and accept the build complexity above.
Miner → ship the same Ubuntu-autoinstall approach first for speed (reuses rigforge.sh), then a true minimal appliance — Alpine diskless (preferred) or Buildroot — for the perf/immutability/diskless win.
One config-injection UX shared by both.
Provisioning / config injection (the "provision system per each")
We support three ways to configure a freshly-booted appliance, leading with the easiest. The web form + config schema are shared with #33 (the day-2 config editor) — build the config UI/API once, invoke it in two contexts (first-boot vs running stack).
First-boot web setup wizard (primary — the dumbed-down path). On boot, if no valid config exists, the appliance serves a small router-style setup page. The user browses to it (printed URL / http://<ip> / *.local), fills a short form (wallets, monero.mode, pool, hostname) → it writes config.json and runs pithead setup, then hands off to the real dashboard. This is the Stack config editor: change any setting from the dashboard, applied via pithead (incl. P2Pool mode hot-swap) #33 config form served in "unprovisioned" mode.
config.json on the USB (pre-seed — power users / fleets). Drop a config.json on the USB config partition (FAT32, editable on any OS); first boot consumes it and skips the wizard. Ideal for flashing many identical rigs.
curl one-liner (headless / automation). A documented curl that POSTs the filled-in config to the setup endpoint — browser-less, scriptable.
Mechanics & considerations:
The wizard runs before the full stack is up (no valid config yet) — a minimal first-boot provisioner mode (a sub-mode of the dashboard, or a tiny separate service) that retires once provisioned. It's a web front-end to pithead's existing ensure_config_exists + setup.
Secure the setup window: the page is LAN-reachable and collects wallet addresses — gate it (only-when-unprovisioned + a token printed to console/serial, or a temporary setup AP).
Miner (rigforge#1) needs ~one field (the stack endpoint): same pattern with a one-field form, or skip the UI via mDNS auto-discovery.
Per-base hooks still run the provisioner at first boot: cloud-init (Ubuntu) · Ignition (CoreOS/Flatcar) · kickstart (bootc) · a first-boot systemd unit (Buildroot/Alpine).
Both pithead and rigforge.sh are already idempotent and config-file driven, so the glue stays thin.
Cross-cutting concerns
UEFI vs legacy BIOS, and Secure Boot (signed shim/bootloader) support.
Destructive disk selection — installing wipes a disk; need a safe target-selection / confirmation story.
AVX2 requirement (both stack mining prep and the miner) — detect and warn/abort.
Networking — DHCP by default; static-IP option for the stack host (the dashboard hostname).
Secrets on the USB — the stack config carries wallet addresses; consider an encrypted config partition or a post-boot prompt.
Updates — stack: apt + pithead upgrade (or image/registry updates if we go bootc); miner: reflash or in-place.
(Stretch) Immutable stack host via bootc / image mode with registry updates.
Acceptance criteria
Booting a prepared USB on bare metal yields a reachable, fully-provisioned stack host (or miner) with only a pre-edited config file and no interactive Linux install.
Documented build → flash → configure → boot steps for each target.
Released image artifacts are checksummed (and ideally signed).
Miner: a documented reflash/update path.
AVX2 / unsupported-hardware is detected and surfaced rather than silently failing.
Goal
Ship bootable USB installers so a user can go from bare server hardware → plug in a USB → a fully-provisioned machine, with little or no manual Linux setup. Two targets:
Each needs a provisioning system: read a user-supplied config off the USB and self-configure on first boot, so deployment is "edit one file, flash, boot."
Why the two targets need different shapes
They look similar ("boot a server, run our software") but are opposites under the hood:
This difference is the crux of the tooling choice.
Deployment options — the DIY path stays first-class
The installer/image work is additive, not a replacement. We support two ways to deploy, and neither deprecates the other:
git clone, and run./pithead setup(host) /./rigforge.sh(miner). Full control over OS, partitioning, existing machines, and bespoke setups — this stays the documented default for people who want it.Non-goal: removing or degrading the script-based install.
pithead/rigforge.shremain the single source of truth for provisioning logic; the image runs those same steps under the hood, so it's one codebase, two delivery methods (they can't drift apart).Is Buildroot the right solution?
Not as a single answer. Buildroot fits the miner, not the stack host:
So: use different tools per repo. And for the miner, a lighter option than Buildroot may win (see Alpine diskless below).
Options evaluated (with research)
Stack host (install a real distro to disk):
pithead. A standard Ubuntu installer ISO + anoclouduser-data/meta-dataon the USB does an unattended install, thenlate-commands/first-boot runspithead setup. Lowest effort, reuses everything.Containerfile, install to disk viabootc-image-builder/Anaconda, update from a container registry. Very aligned (our workload is already containers) and synergises with Release & versioning structure (single-product releases via GHCR) #44 (GHCR releases). Newer, RHEL/Fedora-centric — a bigger shift from the Ubuntu+pithead model.dddeploy path.dd— simplest deploy (image is the installer), but hardware variance (disk size, NIC) needs cloud-init/growpart handling.Miner (minimal appliance):
apkovloverlay on the USB. Tiny and immutable like Buildroot but far less effort (no from-source OS build; XMRig via package or a build step).Recommendation — hybrid + phased
pithead, fastest to ship). Keep bootc / image-mode on the roadmap as the immutable, registry-updated evolution (pairs with Release & versioning structure (single-product releases via GHCR) #44).rigforge.sh), then a true minimal appliance — Alpine diskless (preferred) or Buildroot — for the perf/immutability/diskless win.Provisioning / config injection (the "provision system per each")
We support three ways to configure a freshly-booted appliance, leading with the easiest. The web form + config schema are shared with #33 (the day-2 config editor) — build the config UI/API once, invoke it in two contexts (first-boot vs running stack).
http://<ip>/*.local), fills a short form (wallets,monero.mode, pool, hostname) → it writesconfig.jsonand runspithead setup, then hands off to the real dashboard. This is the Stack config editor: change any setting from the dashboard, applied via pithead (incl. P2Pool mode hot-swap) #33 config form served in "unprovisioned" mode.config.jsonon the USB (pre-seed — power users / fleets). Drop aconfig.jsonon the USB config partition (FAT32, editable on any OS); first boot consumes it and skips the wizard. Ideal for flashing many identical rigs.curlone-liner (headless / automation). A documentedcurlthat POSTs the filled-in config to the setup endpoint — browser-less, scriptable.Mechanics & considerations:
pithead's existingensure_config_exists+setup.pitheadandrigforge.share already idempotent and config-file driven, so the glue stays thin.Cross-cutting concerns
apt+pithead upgrade(or image/registry updates if we go bootc); miner: reflash or in-place.Phasing
pithead setupat first boot. Manual build, documented.rigforge.sh.Acceptance criteria
Open questions
pithead upgrade).Related
Research sources