master
Four Docker Compose services, fully configured via .env: cpuminer (builds cpuminer-opt from source, sha256d), cpuminer-failover (auto pool failover watchdog), cpuminer-monitor-v2 (web dashboard), cpuminer-tui (terminal dashboard, same data over the monitor's HTTP API). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
cpuminer-rig
A self-hosted solo Bitcoin CPU-mining stack for a small Linux box (built and run on a Raspberry Pi 3). Four independent Docker Compose services:
cpuminer/— the miner itself. Builds cpuminer-opt from source and minessha256dagainst a stratum pool.cpuminer-failover/— a watchdog that probes a primary and fallback pool endpoint and switches the miner between them automatically (with a debounce window in each direction), so a pool outage doesn't need a manual fix.cpuminer-monitor-v2/— a web dashboard (port 8081) showing hashrate, shares, best difficulty, active pool endpoint, device temp, and a live log.cpuminer-tui/— the same data as a terminal dashboard, for people who prefer SSH over a browser.
All four are configured entirely through .env files — no source edits
needed to run your own instance.
Quickstart
git clone <this repo> cpuminer-rig && cd cpuminer-rig
cd cpuminer
cp .env.example .env
# edit .env: set WALLET to your BTC address (or pool username)
docker compose up -d --build # first build compiles from source, several minutes
cd ../cpuminer-failover
cp .env.example .env # defaults are fine for most setups
docker compose up -d --build
cd ../cpuminer-monitor-v2
cp .env.example .env
# edit .env: set DEVICE_IP to this host's real LAN IP (auto-detect only
# sees the container's internal bridge IP)
docker compose up -d --build
cd ../cpuminer-tui
docker compose build
docker compose run --rm tui # interactive, needs a real terminal (ssh -t)
How the pieces talk to each other
cpuminerreads the pool URL to connect to fromcpuminer/data/pool_url.txtat startup (not from an env var directly) — this lets the failover watchdog switch pools by rewriting that file and restarting the container, without needing to touch the compose config.cpuminer-failoverwritescpuminer/data/pool_url.txtandcpuminer/data/status.json(active endpoint, since when, last probe latency for each). It needs read/write access to the Docker socket to restart thecpuminercontainer.cpuminer-monitor-v2readscpuminer/data/status.json(mounted read-only) for pool/endpoint status, and tails thecpuminercontainer's own logs (via the Docker API) for hashrate/shares/temperature.cpuminer-tuiis a pure HTTP client ofcpuminer-monitor-v2's/api/statsand/api/historyendpoints — it doesn't touch Docker or the log files directly.
Because of this chain, bring services up in the order above the first time:
cpuminer creates data/pool_url.txt, cpuminer-failover needs that file
to exist (or will create it from its own default), and
cpuminer-monitor-v2/cpuminer-tui just read what's already there.
Default pools
Unset PRIMARY_URL/FALLBACK_URL in cpuminer-failover/.env fall back to
two public solo-mining pools: public-pool.io (primary) and ckpool.org
(fallback). Override both to point at any stratum-compatible pool.
Notes
cpuminer's Dockerfile buildscpuminer-optfrom source on first build. SetBUILD_CFLAGSincpuminer/.envfor CPU-specific optimization flags (e.g.-march=armv8-a -mtune=cortex-a53on a Pi 3); the default-O3is portable across architectures.cpuminer-failoverneeds read-write access to/var/run/docker.sockto restart the miner container — the only service in this stack that does.cpuminer-tuineedsnetwork_mode: hostto reach the monitor's published port without cross-compose-project Docker network naming issues.
Languages
Python
96.9%
Dockerfile
2.2%
Shell
0.9%