Goal
Ship an immutable, flashable image (ISO / raw disk image) that turns a bare machine into a fully-tuned RigForge miner: flash a USB → boot → mining, with no OS install, no package setup, and no manual tuning. Long-term this — not a scripted install onto a general-purpose distro — is the target deployment for RigForge.
Companion to the stack-host installer epic: p2pool-starter-stack/pithead#77. That issue covers the stateful Docker stack host; this issue is the miner half, and the miner is where an immutable image fits best.
Why immutable is the right model for the miner
The miner is a stateless compute appliance — one tuned XMRig process pointed at a stratum endpoint, no wallet, no chain, nothing to persist. That makes immutability a near-perfect fit:
- Reflash-to-update is ideal. Nothing to migrate, so "pull new image, reflash" beats in-place upgrades. No drift; every rig is byte-identical.
- Tuning baked in at boot. HugePages (1 GB + 2 MB) need kernel cmdline params + a reboot; an image bakes them into the bootloader so they're active on first boot — this removes
rigforge.sh's "reboot for HugePages to take effect" step entirely. Same for the MSR module, NUMA layout, hugetlbfs mounts, memlock, and the cpupower performance governor.
- Smaller surface, headless-friendly. A read-only single-purpose image is simpler and safer than a full distro, and is meant to run blind on a box with no monitor.
- "Borrow a machine to mine" UX. A diskless/USB-resident image can run without touching the host's disk — boot from USB, mine, pull the stick, the machine is untouched.
Deployment options — the DIY path stays first-class
This image is additive. RigForge keeps both ways to deploy:
- Do-it-yourself (existing): on a machine you already run (Ubuntu/Debian/macOS),
git clone + sudo ./rigforge.sh — full control, no reflashing.
- Flash-and-go (new, this issue): a prebuilt immutable image you flash to a USB and boot.
Non-goal: deprecating rigforge.sh. It stays the install-onto-existing-OS path and the source of the tuning logic the image bakes in — one codebase, two delivery methods, not a fork.
Approaches (immutable-first)
- Alpine diskless mode (apkovl) — ⭐ likely the fastest path to a real immutable image. Boots from USB into RAM (read-only base); the XMRig service + config ride in a small
apkovl overlay on the USB. Minimal build effort, tiny footprint.
- Buildroot — smallest and most locked-down: read-only squashfs rootfs + a writable overlay/partition for config. The build pipeline compiles upstream XMRig and bakes in all tuning. Most control, most effort (cross-compile toolchain, packaging XMRig + tuning, reflash-only updates). Proven for real appliances.
- mkosi — build a bespoke immutable image (read-only
/usr) on an Alpine/Debian base, output as .raw/.iso. Flexible middle ground.
- bootc / image mode — build the appliance from a
Containerfile, ship as a disk image, update from a container registry. Heavier base for a single-process appliance, but the registry-update path is attractive (and mirrors a possible stack direction).
- (Interim only) Ubuntu autoinstall ISO running
rigforge.sh — fastest to stand up but not immutable; useful only as a stepping stone while the real image is built.
Recommendation: target an immutable image. Prototype quickly with Alpine diskless to validate the boot-and-mine flow + tuning, then evaluate Buildroot for the final locked-down appliance. Keep rigforge.sh as the "install onto an existing Ubuntu/Debian/macOS box" path — the image is the new flash-and-go path, not a replacement for the script.
Config / zero-config UX
The miner needs essentially one input: the stack/pool endpoint (plus an optional rig label, which can default to the hostname). Options, ideally support more than one:
- Writable config partition — a one-line file on a FAT partition the user edits before booting (
P2POOL_NODE_HOSTNAME).
- Kernel cmdline param — pass the endpoint at boot.
- mDNS zero-config — RigForge already resolves
<host>.local; the image could auto-discover the stack with no config at all on a typical LAN.
What to bake into the image
- Upstream XMRig, compiled at build time (with the
DONATION patch applied), plus a CPU-profile-aware config.
- HugePages 1 GB + 2 MB via kernel cmdline;
hugetlbfs mount; raised memlock.
- MSR kernel module + hardware-prefetcher control; NUMA binding;
cpupower performance governor.
- XMRig as a managed service (systemd or Buildroot init) with log rotation and auto-restart.
- AVX2 detection at boot — warn/halt clearly on unsupported CPUs.
Build & release
- CI builds the image and publishes checksummed (ideally signed)
.iso/.raw artifacts per release.
- Document the reflash-to-update path.
- Version the image independently of the stack (RigForge is its own repo); include a "known-good stack version" compatibility note rather than coupling versions.
Cross-cutting concerns
- UEFI + legacy BIOS, and Secure Boot.
- Diskless USB-run vs install-to-disk — decide whether to support one or both (diskless is the standout UX for the miner).
- Multi-rig: one image, per-rig identity via hostname/label so workers are distinguishable on the dashboard.
- Headless: must fully provision and recover with no console attached.
Acceptance criteria
Open questions
- Buildroot vs Alpine diskless for the final image.
- Diskless USB-run vs install-to-disk (or both)?
- Config: file-on-partition vs kernel cmdline vs mDNS zero-config (or a combination)?
- Independent image versioning vs a stack-compatibility note.
Relationship
Research sources
Goal
Ship an immutable, flashable image (ISO / raw disk image) that turns a bare machine into a fully-tuned RigForge miner: flash a USB → boot → mining, with no OS install, no package setup, and no manual tuning. Long-term this — not a scripted install onto a general-purpose distro — is the target deployment for RigForge.
Why immutable is the right model for the miner
The miner is a stateless compute appliance — one tuned XMRig process pointed at a stratum endpoint, no wallet, no chain, nothing to persist. That makes immutability a near-perfect fit:
rigforge.sh's "reboot for HugePages to take effect" step entirely. Same for the MSR module, NUMA layout, hugetlbfs mounts, memlock, and thecpupowerperformance governor.Deployment options — the DIY path stays first-class
This image is additive. RigForge keeps both ways to deploy:
git clone+sudo ./rigforge.sh— full control, no reflashing.Non-goal: deprecating
rigforge.sh. It stays the install-onto-existing-OS path and the source of the tuning logic the image bakes in — one codebase, two delivery methods, not a fork.Approaches (immutable-first)
apkovloverlay on the USB. Minimal build effort, tiny footprint./usr) on an Alpine/Debian base, output as.raw/.iso. Flexible middle ground.Containerfile, ship as a disk image, update from a container registry. Heavier base for a single-process appliance, but the registry-update path is attractive (and mirrors a possible stack direction).rigforge.sh— fastest to stand up but not immutable; useful only as a stepping stone while the real image is built.Recommendation: target an immutable image. Prototype quickly with Alpine diskless to validate the boot-and-mine flow + tuning, then evaluate Buildroot for the final locked-down appliance. Keep
rigforge.shas the "install onto an existing Ubuntu/Debian/macOS box" path — the image is the new flash-and-go path, not a replacement for the script.Config / zero-config UX
The miner needs essentially one input: the stack/pool endpoint (plus an optional rig label, which can default to the hostname). Options, ideally support more than one:
P2POOL_NODE_HOSTNAME).<host>.local; the image could auto-discover the stack with no config at all on a typical LAN.What to bake into the image
DONATIONpatch applied), plus a CPU-profile-aware config.hugetlbfsmount; raisedmemlock.cpupowerperformance governor.Build & release
.iso/.rawartifacts per release.Cross-cutting concerns
Acceptance criteria
Open questions
Relationship
STACK_HOST:3333stratum, no wallet in the worker config.Research sources