diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8badb7..711353d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,20 @@ # Contributing to Pithead -This guide covers the workflow for contributing bug fixes, docs changes, and features. +The workflow for contributing bug fixes, docs changes, and features. ## Before you start -- **Found a bug or have an idea?** Open an issue first. For anything beyond a small fix, - discuss it in an issue before writing code. It saves time and avoids - surprises at review. -- Check the [open issues](https://github.com/p2pool-starter-stack/pithead/issues) to see - if someone's already on it. +- Open an issue before writing code for anything beyond a small fix. Discuss the approach + there first. +- Check the [open issues](https://github.com/p2pool-starter-stack/pithead/issues) for existing + work on the same thing. ## Dev environment The dashboard uses [uv](https://docs.astral.sh/uv/) for dependency management; a hashed -`uv.lock` pins every transitive dependency so installs are reproducible build-to-build. Its -Python tooling ([`ruff`](https://docs.astral.sh/ruff/) lint + format, -[`pre-commit`](https://pre-commit.com/)) lives in the `dev` extra. Install uv, then from the -repo root: +`uv.lock` pins every transitive dependency for reproducible installs. Its Python tooling +([`ruff`](https://docs.astral.sh/ruff/) lint + format, [`pre-commit`](https://pre-commit.com/)) +lives in the `dev` extra. Install uv, then from the repo root: ```bash uv sync --project build/dashboard --extra dev # deps + tooling into build/dashboard/.venv, from the lock @@ -24,12 +22,13 @@ uv run --project build/dashboard pre-commit install ``` `make test` and `make lint-py` run through uv automatically (no venv to activate); `pre-commit` -then runs `ruff` (plus a few hygiene hooks) on your changed files. If you change dependencies in +runs `ruff` (plus a few hygiene hooks) on your changed files. If you change dependencies in `build/dashboard/pyproject.toml`, run `uv lock` and commit the updated `uv.lock`. ## Development workflow -1. Fork the repo and create a branch off `main`. +1. Fork the repo and create a branch off `develop` (the integration branch; `main` holds released + commits only). 2. Make your change. Keep it focused: one logical change per PR. 3. Run the full test suite locally: @@ -58,7 +57,7 @@ then runs `ruff` (plus a few hygiene hooks) on your changed files. If you change Bigger, infra-dependent suites run separately: `make test-mini-stack` (tier-3 docker) and `make test-integration` (tier-4 live, against a real box; start with `--check`). -4. **Add or update tests** for your change. Cover the *intent* (a behavior/contract), not just +4. Add or update tests for your change. Cover the *intent* (a behavior/contract), not just the line. The [Testing Guide](docs/testing-guide.md) has per-change recipes; the [Testing Strategy](docs/testing-strategy.md) explains the tiers. 5. Update the docs in [`docs/`](docs/) (and the README, if relevant) for any @@ -66,10 +65,10 @@ then runs `ruff` (plus a few hygiene hooks) on your changed files. If you change ## Opening a pull request -- Target the `main` branch and fill out the PR template. +- Target the `develop` branch and fill out the PR template. - Link the issue your PR addresses (e.g. `Closes #123`). - Make sure `make test` passes; CI runs the same checks. -- PRs require review before merging; the right reviewers are requested automatically via +- PRs require review before merging; reviewers are requested automatically via [CODEOWNERS](.github/CODEOWNERS). ## Style diff --git a/README.md b/README.md index 0f662d9..5b4ba61 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ ![Platform: Ubuntu 24.04](https://img.shields.io/badge/Platform-Ubuntu%2024.04-E95420?logo=ubuntu&logoColor=white) ![Tor](https://img.shields.io/badge/Networking-Tor--first-7D4698?logo=torproject&logoColor=white) -Pithead is a containerized stack for running a private [Monero](https://www.getmonero.org/) full -node, [P2Pool](https://github.com/SChernykh/p2pool), and [Tari](https://www.tari.com/) merge mining. -An interactive setup script takes you from clone to mining in a few minutes. +Docker Compose stack for Monero + Tari merge mining on [P2Pool](https://github.com/SChernykh/p2pool), +with a [Monero](https://www.getmonero.org/) full node, [Tari](https://www.tari.com/) base node, and +a Tor daemon. The `pithead` script renders config, provisions Tor, and drives docker-compose. @@ -26,25 +26,22 @@ An interactive setup script takes you from clone to mining in a few minutes. ## What it does -- ⛏️ **Zero-fee, decentralized payouts.** Mines Monero on [P2Pool](https://p2pool.io/): no pool - operator, no fees, rewards paid straight to your own wallet. Every hash also merge-mines Tari at - no extra power or config cost. -- 🧠 **XvB yield optimizer.** An algorithmic engine watches the XMRvsBeast raffle and shifts - hashrate to catch bonus rounds. It donates only the minimum needed to hold your tier and returns - every spare cycle to your own P2Pool payouts. -- πŸ§… **Tor-first networking.** A built-in Tor daemon gives Monero, Tari, and P2Pool onion addresses, - so your router stays closed and your home IP is never advertised to an inbound peer. Two outbound - yield paths still touch clearnet in v1.0; the [privacy guide](docs/privacy.md) maps every - connection and how to harden it. -- πŸ”Œ **One endpoint for every rig.** Point all your workers at a single address. Wallets and per-rig - pool config stay out of the miner; the stack routes the hashrate. -- πŸ“Š **Live dashboard.** Shows hashrate, your P2Pool/XvB split, the PPLNS window, and every worker - update, served over HTTPS on your LAN. -- πŸš€ **Interactive setup.** A script handles dependencies, config, Tor, and (on Linux) RandomX - kernel tuning. It asks before touching GRUB, then offers to start the stack. -- πŸ”’ **Hardened defaults.** Least-privilege containers, SHA256-verified binaries, pinned versions, - localhost-only RPC, and least-privilege Docker socket proxies (a read-only one for stats, plus a - separate start/stop-only one for node-down worker failover). +- ⛏️ **P2Pool payouts, Tari merge mined.** Mines Monero on [P2Pool](https://p2pool.io/): no pool + operator, no fee, rewards paid to your own wallet. Every hash merge-mines Tari on the same work. +- 🧠 **XvB switching engine.** Watches the XMRvsBeast raffle and shifts hashrate to hold your tier, + donating the minimum needed and routing the rest to your P2Pool payouts. +- πŸ§… **Tor-first networking.** A built-in Tor daemon gives Monero, Tari, and P2Pool onion addresses; + a host firewall drops any direct clearnet dial from the stack. Two outbound paths still touch + clearnet in v1.0 β€” the [privacy guide](docs/privacy.md) maps every connection and how to harden it. +- πŸ”Œ **One endpoint for every rig.** Point all workers at a single address on port `3333`. No wallet + address in the miner config; the stack routes the hashrate. +- πŸ“Š **Live dashboard.** Hashrate, the P2Pool/XvB split, the PPLNS window, and per-worker updates, + served over HTTPS on your LAN. +- πŸš€ **Interactive setup.** `pithead setup` checks dependencies, writes config, provisions Tor, and + (on Linux) tunes HugePages for RandomX. It prompts before any GRUB change, then offers to start. +- πŸ”’ **Hardened defaults.** Non-root containers, SHA256-verified binaries, pinned image digests, + localhost-only RPC, and two scoped Docker socket proxies: a read-only one for stats and a + separate start/stop-only one for node-down worker failover. --- @@ -66,16 +63,15 @@ cp config.minimal.json config.json # then set your Monero + Tari payout addres > payout addresses. Full sizing in [Hardware Requirements](docs/hardware.md). `setup` checks dependencies (and offers to install them on Ubuntu), asks for your wallet -addresses, provisions Tor, tunes the kernel for RandomX, and offers to start the stack. Then: +addresses, provisions Tor, tunes HugePages for RandomX, and offers to start the stack. Then: 1. Open the dashboard at `https://` (the script prints the exact URL). -2. Let it sync. On first boot the dashboard shows Sync Mode while your Monero and Tari nodes catch - up to the network, then switches to the live view automatically once synced. p2pool and the - proxy stay parked until then, so the sync logs stay clean. -3. Connect your miners by pointing any [XMRig](https://github.com/xmrig/xmrig) rig at - `YOUR_STACK_IP:3333` (no wallet address needed). New to mining? - [RigForge](https://github.com/p2pool-starter-stack/rigforge) provisions a tuned worker in one - command. +2. Wait for the initial sync. On first boot the dashboard shows Sync Mode while the Monero and Tari + nodes catch up, then switches to the live view once both are synced. p2pool and the proxy stay + parked until then. +3. Point any [XMRig](https://github.com/xmrig/xmrig) rig at `YOUR_STACK_IP:3333` β€” no wallet + address in the miner. [RigForge](https://github.com/p2pool-starter-stack/rigforge) provisions a + tuned worker in one command.
Pithead β€” live mining dashboard tour diff --git a/SECURITY.md b/SECURITY.md index dbaf8db..6fd003c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,11 +1,10 @@ # Security Policy -This is the security policy for Pithead: supported versions, how to report a vulnerability, +The security policy for Pithead: supported versions, how to report a vulnerability, and the stack's default security posture. Pithead runs a Monero full node, P2Pool, Tari merge mining, and a dashboard on your -hardware, and it handles wallet payout addresses. We appreciate reports that help keep -operators safe. +hardware, and it handles wallet payout addresses. ## Supported versions @@ -22,24 +21,27 @@ Make sure you're running an up-to-date checkout before reporting an issue. **Please do not open a public issue for security problems.** Use GitHub's private vulnerability reporting instead: go to the **Security** tab and -click **"Report a vulnerability"**. This opens a private advisory visible only to the -maintainers, where we can triage and coordinate a fix and disclosure with you. +click **Report a vulnerability**. This opens a private advisory visible only to the +maintainers, for triage and coordinated disclosure. -When you report, it helps to include: +Include: - A description of the issue and its impact. - Steps to reproduce, and the affected component (node, P2Pool, proxy, dashboard, Tor, `pithead` script, etc.). - Any relevant logs or configuration (redact wallet addresses and secrets). -We aim to acknowledge reports promptly and will keep you posted as we work on a fix. - ## Security posture -The stack is hardened by default: least-privilege containers (every service runs as a **non-root -user**, not uid 0; leaf services run with `no-new-privileges` and drop all Linux capabilities; the -internet-facing and Docker-socket-facing ones also use a read-only root filesystem), -SHA256-verified and version-pinned binaries, -localhost-only RPC, a LAN-scoped (and narrowable) stratum port, scoped Docker socket proxies, -and Tor for all node networking. If you find a gap in any of these, that's the kind of -report we want. +The stack's defaults: + +- Least-privilege containers: every service runs as a non-root user (not uid 0); leaf services + run with `no-new-privileges` and drop all Linux capabilities; internet-facing and + Docker-socket-facing services also use a read-only root filesystem. +- SHA256-verified, version-pinned binaries. +- Localhost-only RPC. +- LAN-scoped (and narrowable) stratum port. +- Scoped Docker socket proxies. +- Tor for all node networking. + +Report any gap in these. diff --git a/build/dashboard/README.md b/build/dashboard/README.md index 665ac13..40cff61 100644 --- a/build/dashboard/README.md +++ b/build/dashboard/README.md @@ -25,12 +25,14 @@ Everything is served from `/static`: the vendored Preact, htm and Chart.js (`sta the app modules and `dashboard.css`. Nothing is inlined and the libraries are eval-free, so the page runs under a strict Content-Security-Policy with no `'unsafe-inline'`/`'unsafe-eval'`. -Testing: the Python API, where all the logic and formatting live, is fully unit-tested. The pure -client logic (worker sort, tooltip formatting, hero-KPI selection in `static/logic.mjs`) is -unit-tested with Node's built-in runner -(`node --test build/dashboard/tests/frontend/*.test.mjs`) β€” no -`package.json`/`node_modules`/build step, so the repo stays Node-free. Component rendering has no -unit tests by design; it's covered by a manual browser smoke test. +Testing: the Python API, where the logic and formatting live, is unit-tested. The client-side +tests run under Node's built-in runner (`node --test build/dashboard/tests/frontend/`) β€” no +`package.json`/`node_modules`/build step, so the repo stays Node-free. They cover the pure logic +(`logic.test.mjs`: worker sort, tooltip formatting, hero-KPI selection), the chart helpers +(`chart.test.mjs`: `withAlpha`, `padYAxis`), the topology geometry (`topology.test.mjs`), and +component rendering (`components.test.mjs`: every card driven through `App` against a real +`build_state()` fixture, via a DOM-free vnode walker). The DOM-bound wiring (Chart.js canvas, +the SVG topology component) needs a browser and is left to a manual smoke test. ## Layout @@ -42,6 +44,7 @@ mining_dashboard/ β”œβ”€β”€ collector/ # local stats collectors (pools, system, docker logs) β”œβ”€β”€ service/ # algo_service (XvB switching), data_service (aggregation), storage_service (SQLite), β”‚ # metrics (typed computed domain values consumed by the view layer) +β”œβ”€β”€ sim/ # donation_model (the XvB donation simulator; property-tested, #284) β”œβ”€β”€ web/ # server.py (transport: / shell + /api/state + middleware), β”‚ # views.py (build_state: the JSON state object), templates/index.html β”‚ # (static shell), static/ (Preact app + dashboard.css + vendored libs) @@ -64,8 +67,8 @@ uv sync --extra test pytest # quick run pytest --cov=mining_dashboard --cov-report=term-missing --cov-fail-under=80 -# pure client logic (needs only Node >= 18, no install): -node --test tests/frontend/*.test.mjs +# client-side tests (needs only Node >= 18, no install): +node --test tests/frontend/ ``` Or from the repo root: `make test-dashboard`. The same Python suite runs in the Docker test stage: diff --git a/docs/README.md b/docs/README.md index bd0f169..961f338 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,9 +2,8 @@ Guides for running, configuring, and operating Pithead. -New here? Start with the [Getting Started](getting-started.md) guide. It takes you from a fresh -Ubuntu machine to a synced, mining stack in a handful of commands. The other guides go deeper on -individual topics once you're running. +Start with [Getting Started](getting-started.md): it takes a fresh Ubuntu host to a synced, mining +stack. The other guides cover individual topics once you're running. ## Guides diff --git a/docs/architecture.md b/docs/architecture.md index 4b811e3..263b53d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,21 +1,21 @@ # Architecture -This doc describes the nine containerized services the stack runs under Docker Compose and how they -fit together. +The stack runs nine containerized services under Docker Compose. This doc lists each service and how +they connect. -Together they give you a private Monero full node, decentralized P2Pool mining, Tari merge mining, a -single worker endpoint, and a monitoring dashboard. Everything runs behind Tor, with no public port -forwarding required. +The services provide a Monero full node, P2Pool sidechain mining, Tari merge mining, a single worker +endpoint, and a monitoring dashboard. All node P2P and transaction traffic routes over Tor; no public +port forwarding is required. ## The services | # | Service | Role | |---|---|---| | 1 | **Monerod** | The Monero daemon (full node). Configured for restricted RPC and Tor transaction broadcasting. | -| 2 | **P2Pool** | The decentralized mining sidechain, with support for Main, Mini, and Nano pools. | +| 2 | **P2Pool** | The mining sidechain. Supports Main, Mini, and Nano pools. | | 3 | **Tari Base Node** | The Minotari node, merge-mined alongside Monero. | -| 4 | **XMRig Proxy** | A single connection point for all your mining hardware; the switching engine reconfigures it on the fly. | -| 5 | **Tor** | A centralized anonymity layer providing SOCKS5 proxies and hidden services (onion addresses) for the other containers. | +| 4 | **XMRig Proxy** | The single stratum endpoint (`:3333`) all mining hardware connects to; the switching engine reconfigures it at runtime. | +| 5 | **Tor** | Provides SOCKS5 proxies and hidden services (onion addresses) for the other containers. | | 6 | **Dashboard** | The web monitoring UI and the algorithmic switching engine. | | 7 | **Docker Proxy** | A **read-only** proxy onto the Docker socket so the dashboard can read container stats/logs β€” no write access. | | 8 | **Docker Control** | A second, minimal socket proxy scoped to **only** `start`/`stop` (nothing else β€” not create/kill/exec/reads), so the dashboard can reject workers when a node is down (Issue #31), hold p2pool + xmrig-proxy until the chains finish syncing (Issue #35), and switch a clearnet-syncing node back to Tor once it's synced (Issue #234). Kept separate so its write grant can't widen the read-only proxy. | @@ -89,18 +89,18 @@ Monero node isn't started, and P2Pool talks to your external node instead. ## Privacy by design -The stack is Tor-first. A dedicated Tor daemon provides hidden services (onion addresses) for -Monero, Tari, and P2Pool, so inbound connectivity needs no public IPv4 port forwarding. Monero and -Tari route their P2P and transaction traffic over Tor, and the clearnet DNS lookups those nodes used -to leak are closed (monerod checkpoints/blocklist/update-check, Tari DNS seeds + Pulse). The node's -RPC is bound to localhost by default; opt into LAN access explicitly via `monero.rpc_lan_access`. +The stack is Tor-first. The Tor daemon provides hidden services (onion addresses) for Monero, Tari, +and P2Pool, so inbound connectivity needs no public IPv4 port forwarding. Monero and Tari route their +P2P and transaction traffic over Tor, and the clearnet DNS lookups those nodes formerly leaked are +closed (monerod checkpoints/blocklist/update-check, Tari DNS seeds + Pulse). The node's RPC binds to +`127.0.0.1` by default; set `monero.rpc_lan_access: true` for LAN access. -Two outbound yield paths used clearnet in v1.0 and could reveal your home IP: P2Pool's outbound -sidechain peers and XvB donation mining. As of v1.1 both are Tor by default, each with a documented -opt-out for operators who'd trade privacy for yield (measured at ~10 % of yield on `mini`; see the -[Tor-vs-clearnet benchmark](benchmarks/tor-vs-clearnet.md)). Install and image pulls still reveal -your IP once. See [Privacy & network egress](privacy.md) for the complete connection-by-connection -map and how to lock down the rest. +Two outbound yield paths used clearnet in v1.0 and exposed the host IP: P2Pool's outbound sidechain +peers and XvB donation mining. As of v1.1 both route over Tor by default, each with an opt-out +(measured cost ~10 % of yield on `mini`; see the +[Tor-vs-clearnet benchmark](benchmarks/tor-vs-clearnet.md)). The one-time install and image pulls +reveal the host IP once. See [Privacy & network egress](privacy.md) for the connection-by-connection +map and the remaining lock-down steps. ## Security posture @@ -135,12 +135,10 @@ map and how to lock down the rest. ## Algorithmic switching -The stack plays the XvB raffle for you, with no per-rig pool juggling. Rather than asking you to -configure each rig for a different pool, it manages hashrate distribution centrally: all your -workers connect to a single endpoint, the `xmrig-proxy` service on port `3333`, and the dashboard's -decision engine continuously reallocates that hashrate between P2Pool (your own zero-fee Monero + -Tari payouts) and XMRvsBeast (XvB) bonus rounds. It donates only the minimum needed to hold your -target tier and hands every spare cycle back to P2Pool, so you don't over-donate. +The dashboard distributes hashrate centrally rather than requiring per-rig pool configuration. All +workers connect to one endpoint, the `xmrig-proxy` service on port `3333`, and the decision engine +reallocates that hashrate between P2Pool (zero-fee Monero + Tari payouts) and XMRvsBeast (XvB) bonus +rounds. It donates the minimum needed to hold the target tier and routes the rest to P2Pool. ### How the engine decides @@ -177,9 +175,8 @@ target tier and hands every spare cycle back to P2Pool, so you don't over-donate to P2Pool. The controller edits the proxy config only; your workers keep their existing connection to `3333` and need no changes. -You stay in your chosen XvB tier with minimal donation, and every spare cycle mines Monero + Tari on -P2Pool. The dashboard's hashrate chart shades the P2Pool/XvB split over time so you can watch the -controller work. +The result: the chosen XvB tier holds with minimal donation, and remaining hashrate mines Monero + +Tari on P2Pool. The dashboard's hashrate chart shades the P2Pool/XvB split over time. --- diff --git a/docs/configuration.md b/docs/configuration.md index f026072..05dec1b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,15 +1,15 @@ # Configuration -`config.json` is the single source of truth for the stack. The interactive `setup` writes a minimal -one for you. After that, change the stack by editing `config.json` and running `./pithead apply`. +`config.json` is the stack's only config file. `./pithead setup` writes a minimal one. To change the +stack afterward, edit `config.json` and run `./pithead apply`. ## The minimal config -Only your two wallet addresses are required. Every other key is optional and falls back to a default: -the node runs locally, on the `main` pool, with a secure dashboard, and the local node's RPC -credentials are auto-generated. Leave a key out unless you want to change it. +The two wallet addresses are the only required keys. Every other key is optional and falls back to a +default: the node runs locally, on the `main` pool, with a secure dashboard, and the local node's RPC +credentials are auto-generated. Omit a key to keep its default. -A fresh `config.json` is just this (see [`config.minimal.json`](../config.minimal.json)): +A fresh `config.json` is this (see [`config.minimal.json`](../config.minimal.json)): ```json { @@ -22,12 +22,11 @@ A fresh `config.json` is just this (see [`config.minimal.json`](../config.minima } ``` -For the full shape with every key and its default, see -[`config.reference.json`](../config.reference.json) and copy in only the keys you -want to override. +For every key and its default, see [`config.reference.json`](../config.reference.json) and copy in +only the keys you want to override. -> The string `"auto"` anywhere means "let the stack pick the default": a default path, the -> machine's hostname, a derived donor id, and so on. +> The string `"auto"` means "let the stack pick the default": a default path, the machine's +> hostname, a derived donor id, and so on. --- @@ -39,11 +38,9 @@ want to override. `apply` is safe to run anytime: - It previews what will change, diffing your edited `config.json` against the running configuration. -- It warns before anything disruptive. Switching the Monero node local↔remote, toggling pruning, - changing a payout address, exposing the RPC to your LAN, or moving a data directory each trigger a - confirmation prompt. -- It then regenerates the `.env`, Caddy, and Tari configs and recreates only the containers that - need it. +- It prompts to confirm before anything disruptive: switching the Monero node local↔remote, toggling + pruning, changing a payout address, exposing the RPC to your LAN, or moving a data directory. +- It regenerates the `.env`, Caddy, and Tari configs and recreates only the containers that need it. - It does not re-provision Tor, touch GRUB, or rotate the proxy token. If nothing changed, it does nothing. @@ -161,9 +158,9 @@ and sets ownership automatically (Monero/Tari/P2Pool to your user, Tor to the co ## Exposing the dashboard safely -The dashboard is built for a trusted private network: the home or office LAN the appliance sits on. -By default it has no login: anyone who can reach the host can open it. That's the right trade-off -for a single-user box behind your router, and it stays the default. +The dashboard targets a trusted private network: the home or office LAN the appliance sits on. By +default it has no login; anyone who can reach the host can open it. That is the default for a +single-user box behind your router. Add a login (and keep HTTPS on) whenever the dashboard is reachable by anyone you don't fully trust. For example: diff --git a/docs/dashboard.md b/docs/dashboard.md index 124b2dd..a34b7d3 100644 --- a/docs/dashboard.md +++ b/docs/dashboard.md @@ -1,18 +1,18 @@ # The Dashboard -The dashboard is a single web page that monitors every service, charts your hashrate, and shows -the decisions made by the algorithmic XvB switching engine. Caddy serves it over HTTPS at -`https://` (the URL is printed when the stack starts). +A single web page that monitors every service, charts hashrate, and shows the XvB switching engine's +decisions. Caddy serves it over HTTPS at `https://` (the URL is printed when the stack +starts); with `dashboard.secure: false` it serves plain HTTP. -The dashboard has two states. While your nodes catch up to the network it shows Sync Mode. Once -both chains are synced it switches automatically to the full operational view. +The dashboard has two states. While the nodes catch up to the network it shows Sync Mode. Once both +chains are synced it switches to the operational view. --- ## Sync Mode The dashboard shows Sync Mode the first time you start the stack, or any time the Monero or Tari -node is still catching up. A `Syncing…` badge appears next to the hostname, the headline reads +node is still catching up. A `Syncing...` badge appears next to the hostname, the headline reads *"System is currently synchronizing with the network,"* and no hashrate is routed yet. @@ -20,30 +20,28 @@ node is still catching up. A `Syncing…` badge appears next to the hostname, th Sync Mode -Sync Mode gives each chain its own progress card so you can see exactly where things stand: +Sync Mode gives each chain its own progress card: -- **Monero Sync**: current verified block height vs. the network tip, with the number of blocks - remaining. A green check means this chain is fully caught up. It also shows whether the node is - running Pruned or Full and its on-disk DB size (also in the **XMR Network** panel of the - operational view), so you can confirm a reused chain matches your `monero.prune` setting. +- **Monero Sync**: verified block height vs. the network tip, with blocks remaining. A green check + means the chain is caught up. It also shows Pruned or Full mode and the on-disk DB size (also in + the **XMR Network** panel of the operational view), so you can confirm a reused chain matches your + `monero.prune` setting. - **Tari Sync**: the same, as a percentage ring, for the Minotari chain. -The top bar shows live host telemetry throughout: CPU, load average, RAM, HugePages (so you can -confirm RandomX optimization is active), and disk usage. Useful for watching resources during the -initial download. +The top bar shows live host telemetry throughout: CPU, load average, RAM, HugePages (to confirm +RandomX optimization is active), and disk usage, for watching resources during the initial download. -A Monero or Tari node can't mine until it has downloaded and verified the blockchain. On a first -run that takes from a few hours to over a day depending on your hardware, disk, and network. Sync -Mode makes the progress visible. Once the required chains report fully synced, the dashboard swaps -Sync Mode for the operational view and mining begins. No refresh or restart needed. +A Monero or Tari node cannot mine until it has downloaded and verified the blockchain. On a first +run that takes a few hours to over a day, depending on hardware, disk, and network. Once the required +chains report synced, the dashboard swaps Sync Mode for the operational view and mining begins β€” no +refresh or restart needed. -While the chains are syncing, the dashboard keeps `p2pool` and `xmrig-proxy` stopped (a -`Miner held (sync)` badge shows next to the hostname) and starts them automatically once they're -ready. Running p2pool against an unsynced node achieves nothing and floods Tari's logs with -merge-mining chatter that buries the messages you'd want while debugging a sync. Releasing the -miner is one-way: once it starts it stays up. By default the stack waits for both Monero and Tari. -With [`dashboard.tari_required: false`](configuration.md) it waits only for Monero and starts -mining while Tari finishes syncing in the background. +While the chains sync, the dashboard keeps `p2pool` and `xmrig-proxy` stopped (a `Miner held (sync)` +badge shows next to the hostname) and starts them once the chains are ready. Running p2pool against +an unsynced node does nothing and floods Tari's logs with merge-mining chatter. Releasing the miner +is one-way: once it starts it stays up. By default the stack waits for both Monero and Tari. With +[`dashboard.tari_required: false`](configuration.md) it waits only for Monero and mines while Tari +finishes syncing in the background. > **Want to skip most of the wait?** Point the stack at an existing synced blockchain, or connect > to a remote node. See [Configuration β€Ί Reusing an existing node](configuration.md#reusing-an-existing-node). @@ -59,45 +57,41 @@ You can also follow sync progress from the command line: ## The operational view -Once both nodes are synced, the dashboard shows the full operational view. +Once both nodes are synced, the dashboard shows the operational view. Operational dashboard β€” Simple view -The page updates live every 30 seconds, refreshing each panel in place rather than reloading the -whole page. Your scroll position, the column you've sorted the worker table by, and the chart all -stay put between updates. +The page updates every 30 seconds, refreshing each panel in place rather than reloading. Scroll +position, the worker-table sort column, and the chart stay put between updates. ### Top bar -A persistent status strip across the top shows the hostname, host telemetry (CPU, load, RAM, -HugePages, disk), your total hashrate, and 1h / 24h routed averages for both P2Pool and XvB so you -can read your split. Next to the disk readout, an `XMR Pruned` / `XMR Full` badge shows the Monero -node's blockchain mode. +A status strip across the top shows the hostname, host telemetry (CPU, load, RAM, HugePages, disk), +total hashrate, and 1h / 24h routed averages for both P2Pool and XvB (your split). Next to the disk +readout, an `XMR Pruned` / `XMR Full` badge shows the Monero node's blockchain mode. -When the dashboard host is a name (not already an IP), the machine's IP address shows beside it as -`hostname @ ip` (e.g. `pithead.local @ 192.168.1.42`). This is a reliable way back in when the -hostname doesn't resolve from your phone or another machine on the LAN. +When the dashboard host is a name (not already an IP), the machine's IP shows beside it as +`hostname @ ip` (e.g. `pithead.local @ 192.168.1.42`), a way back in when the hostname doesn't +resolve from a phone or another LAN machine. -A small version badge sits beside the hostname so you know which build is running. A released -build shows the version (e.g. `v1.3.0`); a development or working-tree build shows a dashed -`dev Β· branch @ commit` marker instead, so it's never mistaken for a release. It appears on every -screen, including Sync Mode, which makes it easy to confirm what you're on when sharing a -screenshot in a bug report. On a `dev` build but would rather run a published release? See +A version badge sits beside the hostname. A released build shows the version (e.g. `v1.3.0`); a +development or working-tree build shows a dashed `dev Β· branch @ commit` marker instead, so it is not +mistaken for a release. It appears on every screen, including Sync Mode, so a screenshot in a bug +report shows the build. To switch a `dev` build to a published release, see [Switching a source checkout to release images](operations.md#switching-a-source-checkout-to-release-images). -When a newer Pithead release is out, a clickable `New release vX.Y.Z available β†—` badge appears -next to the version badge, linking to the GitHub release. It's a heads-up only. It never updates -anything; you upgrade with `./pithead upgrade` when you're ready. The check is on by default and -routed over Tor (so it can't reveal your IP). Turn it off with `dashboard.check_for_updates: false` -(see [Configuration](configuration.md#configuration-reference)). +When a newer Pithead release is out, a clickable `New release vX.Y.Z available β†—` badge appears next +to the version badge, linking to the GitHub release. It never updates anything; upgrade with +`./pithead upgrade` when ready. The check is on by default and routed over Tor, so it does not reveal +your IP. Turn it off with `dashboard.check_for_updates: false` (see +[Configuration](configuration.md#configuration-reference)). ### Hero band -A strip of headline KPIs sits just below the top bar, so the numbers that matter read the moment -the page loads: +A strip of headline KPIs sits below the top bar: | KPI | Meaning | |---|---| @@ -115,43 +109,39 @@ bar (after a short debounce, so a momentary blip doesn't flap). Sync state is re `get_info` RPC and Tari's gRPC, so "down" means the node itself is unreachable, not just that a log line changed. -A red `⚠ DB write failing` badge appears if the dashboard can't write to its own SQLite database (a -full or read-only disk, a permissions problem). The dashboard keeps serving live data, but hashrate -history, shares, and stats won't survive a restart until it's fixed. It's surfaced rather than lost -silently. - -While a node is down, the dashboard also rejects workers so they fail over to the backup pools -you've configured, instead of sitting idle on a stack that can't mine for them. A sustained outage -stops the `xmrig-proxy` container (a `Workers rejected` badge shows) and a confirmed recovery -restarts it. monerod is required to mine, so a monerod outage always rejects. Tari is merge-mining -gravy, so whether a Tari outage rejects follows [`dashboard.tari_required`](configuration.md): when -it's `true` (default) a Tari outage rejects too; set it `false` to keep mining Monero straight -through a Tari outage. (Rejection never triggers for a remote monerod, since the stack doesn't -manage that node.) - -**Non-blocking Tari.** With `tari_required: false`, a Tari-only (re)sync no longer takes over the +A red `⚠ DB write failing` badge appears if the dashboard can't write to its SQLite database (full +or read-only disk, permissions problem). The dashboard keeps serving live data, but hashrate history, +shares, and stats won't survive a restart until it's fixed. + +While a node is down, the dashboard rejects workers so they fail over to the backup pools you've +configured, rather than sitting idle on a stack that can't mine. A sustained outage stops the +`xmrig-proxy` container (a `Workers rejected` badge shows) and a confirmed recovery restarts it. +monerod is required to mine, so a monerod outage always rejects. Whether a Tari outage rejects +follows [`dashboard.tari_required`](configuration.md): `true` (default) rejects on a Tari outage; +`false` keeps mining Monero through it. Rejection never triggers for a remote monerod, since the +stack doesn't manage that node. + +**Non-blocking Tari.** With `tari_required: false`, a Tari-only (re)sync doesn't take over the screen: the operational view stays up, mining continues, and a `Tari syncing` badge shows Tari's progress until it catches up and merge mining resumes. ### Hashrate chart -A time-series chart of your hashrate with selectable ranges (1h / 24h / 1w / 1mo) that switch -without reloading the page. The shaded bands show how hashrate was split between P2Pool and XvB -over time, so you can see the switching engine at work. +A time-series chart of hashrate with selectable ranges (1h / 24h / 1w / 1mo) that switch without +reloading. Shaded bands show the P2Pool/XvB split over time. An **Avg** control picks the hashrate-averaging window the chart plots: `1 Min` / `10 Min` / -`1 Hr` / `12 Hr` / `24 Hr` (the native windows xmrig-proxy reports). This is independent of the -Range control. The range sets how much *time* the x-axis spans; the averaging window sets how -*smooth* each plotted point is. Short windows (1–10 min) react quickly, so a rig dropping or -joining shows up within a poll or two. Long windows (12–24 h) ride out the noise to show the -underlying trend. Your choice is remembered across reloads. Two things to know: - -- `10 Min` is the default and matches the dashboard's headline hashrate, so the chart looks the - same as before unless you change it. -- The longer windows need that much rig uptime to fill. Right after a (re)start, `12 Hr`/`24 Hr` - read low and climb until enough history exists. Per-window history is also kept only *going - forward* from the version that introduced this control, so those lines are flat at the far-left - edge of a long range until new data accumulates. That's expected, not a fault. +`1 Hr` / `12 Hr` / `24 Hr` (the native windows xmrig-proxy reports). It is independent of the Range +control: the range sets how much *time* the x-axis spans; the averaging window sets how *smooth* each +plotted point is. Short windows (1–10 min) react within a poll or two, so a rig dropping or joining +shows up fast. Long windows (12–24 h) ride out the noise to show the trend. The choice is remembered +across reloads. Two things to know: + +- `10 Min` is the default and matches the dashboard's headline hashrate. +- The longer windows need that much rig uptime to fill. Right after a (re)start, `12 Hr`/`24 Hr` read + low and climb until enough history exists. Per-window history is kept only *going forward* from the + version that introduced this control, so those lines are flat at the far-left edge of a long range + until new data accumulates. Expected, not a fault. ### Overview @@ -175,30 +165,29 @@ The summary panel pulls the key numbers together: ### Workers Alive A live table of every connected rig: worker name, IP, uptime, and per-worker hashrate over several -windows (e.g. 10s / 60s / 15m), so you can spot a rig that has dropped off or is underperforming. -A worker that's connected but whose direct API is unreachable still counts (with proxy-derived -hashrate); a worker whose miner has stopped drops out of the total. On a narrow screen the table -scrolls sideways within its card, so its columns stay readable rather than stretching the page. - -Each rig also shows its accepted and rejected share counts (with invalid shares folded into the -rejected column as `3 (+2 inv)` when present). A rig whose reject rate climbs past ~5% gets a red -**⚠** flag next to its rejected count. That's a quick way to catch a rig submitting stale or bad -shares (bad overclock, flaky network, clock drift) rather than earning. Every column is sortable, -so you can click **Rejected** to float the worst offenders to the top. The shares are cumulative -since the proxy last started, so a brief early-run blip clears itself as good shares accumulate. - -Below the table, a **Proxy totals** line sums the whole stack's share health as reported by the -xmrig-proxy: total accepted / rejected (with the aggregate reject %) / invalid shares submitted -upstream, plus the best difficulty any of your shares has hit. It's hidden until the proxy has -submitted its first shares. +windows (e.g. 10s / 60s / 15m), for spotting a rig that has dropped off or is underperforming. A +worker whose direct API is unreachable still counts (with proxy-derived hashrate); a worker whose +miner has stopped drops out of the total. On a narrow screen the table scrolls sideways within its +card so columns stay readable. + +Each rig shows accepted and rejected share counts (invalid shares folded into the rejected column as +`3 (+2 inv)` when present). A rig whose reject rate climbs past ~5% gets a red **⚠** flag next to its +rejected count β€” a rig submitting stale or bad shares (bad overclock, flaky network, clock drift) +rather than earning. Every column is sortable; click **Rejected** to float the worst offenders to the +top. Shares are cumulative since the proxy last started, so a brief early-run blip clears as good +shares accumulate. + +Below the table, a **Proxy totals** line sums the stack's share health as reported by xmrig-proxy: +total accepted / rejected (with aggregate reject %) / invalid shares submitted upstream, plus the +best difficulty any share has hit. Hidden until the proxy submits its first shares. ### Simple vs. Advanced view -A **Simple / Advanced** toggle sits above the chart. **Simple** (the default) keeps the page to -the essentials: the chart, the Overview summary, and the worker table. **Advanced** swaps the -Overview for a set of cards that break out the same data in more detail: **My P2Pool Node Stats**, -**Global P2Pool Stats**, **XvB Donation Stats**, **XMR Network**, **Tari Merge Mining**, and the -**P2Pool Earnings (estimated)** calculator below. Your choice is remembered across reloads. +A **Simple / Advanced** toggle sits above the chart. **Simple** (the default) shows the chart, the +Overview summary, and the worker table. **Advanced** swaps the Overview for cards that break out the +same data in more detail: **My P2Pool Node Stats**, **Global P2Pool Stats**, **XvB Donation Stats**, +**XMR Network**, **Tari Merge Mining**, and the **P2Pool Earnings (estimated)** calculator below. The +choice is remembered across reloads. @@ -208,8 +197,8 @@ Overview for a set of cards that break out the same data in more detail: **My P2 ### P2Pool Earnings (estimated) A P2Pool mining calculator (Advanced view). It estimates the XMR earned from P2Pool mining only, -turning your P2Pool hashrate and the live Monero network figures into a rough payout estimate. It -is deliberately scoped to P2Pool. It is **not** an XvB or a Tari calculator: +from your P2Pool hashrate and the live Monero network figures. It is scoped to P2Pool β€” **not** an +XvB or a Tari calculator: - **XvB donations are excluded.** Hashrate you route to XvB earns no P2Pool payout, so it isn't counted. The default is your P2Pool 1h-average hashrate, the *same* `P2Pool (1h)` figure shown @@ -241,16 +230,16 @@ is deliberately scoped to P2Pool. It is **not** an XvB or a Tari calculator: self-signed certificate, so your browser shows a one-time "connection is not private" warning. Accept it to proceed. To use plain HTTP instead, set `dashboard.secure: false` and run `./pithead apply`. -- **Reaching it from another machine.** Use the hostname/IP of the stack server. If your hostname - doesn't resolve on your LAN, set `dashboard.host` in `config.json` to an address that does. -- **Adding a login.** By default the dashboard has no password, which is fine for a private LAN - appliance. If the box is shared or reachable beyond your LAN, set `dashboard.auth.password` (keep +- **Reaching it from another machine.** Use the stack server's hostname/IP. If the hostname doesn't + resolve on your LAN, set `dashboard.host` in `config.json` to an address that does. +- **Adding a login.** The dashboard has no password by default, fine for a private LAN appliance. If + the box is shared or reachable beyond your LAN, set `dashboard.auth.password` (keep `dashboard.secure: true`) and run `./pithead apply` to put a login prompt in front of it. See [Configuration β€Ί Exposing the dashboard safely](configuration.md#exposing-the-dashboard-safely). -- **On your phone.** The dashboard is responsive. Open the same URL on a phone and the layout - reflows to a single column with a stacked header, so you can check on the stack from the couch. -- **Stuck on Sync Mode?** That usually just means the chain is still downloading. Check - `./pithead logs monerod` / `./pithead logs tari` for steady progress; see +- **On your phone.** The layout is responsive. Open the same URL and it reflows to a single column + with a stacked header. +- **Stuck on Sync Mode?** The chain is still downloading. Check `./pithead logs monerod` / + `./pithead logs tari` for steady progress; see [Operations β€Ί Troubleshooting](operations.md#troubleshooting) if a node looks stalled. For how the switching engine decides the P2Pool/XvB split, see diff --git a/docs/faq.md b/docs/faq.md index 5ee442d..3758646 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,8 +1,7 @@ # FAQ -Common questions about what Pithead is, what it does, and how it compares to wiring the pieces -together yourself. New here? Start with [Getting Started](getting-started.md); the deeper "why" -lives in [Architecture](architecture.md). +Answers to common questions about Pithead, checked against the code. Start with +[Getting Started](getting-started.md); the design is in [Architecture](architecture.md). --- @@ -10,10 +9,10 @@ lives in [Architecture](architecture.md). ### vs. doing it yourself -You can run a private Monero + P2Pool + Tari setup by hand; plenty of people do, and the -underlying projects ([monerod](https://www.getmonero.org/), [P2Pool](https://github.com/SChernykh/p2pool), -[XMRig](https://github.com/xmrig/xmrig)) are excellent. Doing it yourself means standing up and -maintaining each piece and the wiring between them: +You can run a private Monero + P2Pool + Tari setup by hand on top of +[monerod](https://www.getmonero.org/), [P2Pool](https://github.com/SChernykh/p2pool), and +[XMRig](https://github.com/xmrig/xmrig). Doing it yourself means standing up and maintaining each +piece and the wiring between them: - A Monero full node with restricted RPC, ZMQ, and Tor transaction broadcasting. - P2Pool pointed at that node, with an onion address for inbound peers. @@ -21,53 +20,45 @@ maintaining each piece and the wiring between them: - Each rig configured for the pool, plus a plan for what happens when the node goes down. - Some way to see hashrate, sync progress, and your PPLNS window. -Pithead automates that stack in one command and adds the parts that are tedious to build -yourself: +Pithead runs that stack from one command and adds the parts that are tedious to build yourself: - Tor-first networking. A built-in Tor daemon gives Monero, Tari, and P2Pool hidden-service - (onion) addresses, so there's no public port forwarding and Monero/Tari traffic runs over Tor. A - couple of outbound yield paths still use clearnet today; see + (onion) addresses, so there is no public port forwarding and Monero/Tari traffic runs over Tor. + A couple of outbound yield paths still use clearnet; see [Privacy & network egress](privacy.md) for the full map and how to harden them. - One endpoint for every rig. All workers point at a single `xmrig-proxy` endpoint on `:3333`. - There's nothing per-rig to configure: no wallet address, no pool URL juggling. See + Nothing is configured per rig: no wallet address, no pool URL. See [Connecting Miners](workers.md). -- Algorithmic XvB switching. A feedback controller splits your hashrate between P2Pool and - XMRvsBeast (XvB) bonus rounds, donating only the minimum needed to hold your target tier and - routing the rest to P2Pool. See [Architecture β€Ί Algorithmic switching](architecture.md#algorithmic-switching). -- Node-down worker failover. If monerod goes down, the stack stops `xmrig-proxy` so your miners - fail over to their backup pools instead of mining into a void. See +- Algorithmic XvB switching. A feedback controller splits hashrate between P2Pool and XMRvsBeast + (XvB) bonus rounds, donating the minimum needed to hold your target tier and routing the rest to + P2Pool. See [Architecture β€Ί Algorithmic switching](architecture.md#algorithmic-switching). +- Node-down worker failover. If monerod goes down, the stack stops `xmrig-proxy` so miners fail + over to their backup pools. See [Configuration β€Ί `dashboard.tari_required`](configuration.md#configuration-reference). -- A dashboard that tells you things. Live hashrate, sync progress, the PPLNS window, per-worker - stats, and your P2Pool/XvB split, served over HTTPS on your LAN. See - [The Dashboard](dashboard.md). +- Dashboard. Live hashrate, sync progress, the PPLNS window, per-worker stats, and the P2Pool/XvB + split, served over HTTPS on your LAN. See [The Dashboard](dashboard.md). - Hardened defaults. Least-privilege containers, SHA256-verified and version-pinned binaries, localhost-only RPC, and split read-only / start-stop Docker socket proxies. See [Architecture β€Ί Security posture](architecture.md#security-posture). -If you enjoy hand-wiring infrastructure, the manual route is a good learning exercise. If you want -a private, multi-rig, merge-mining stack running with less of that work, that's what Pithead is -for. - ### vs. Gupax [Gupax](https://github.com/gupax-io/gupax) is a desktop GUI for mining Monero on P2Pool. It runs on -Windows, macOS, and Linux, has a `--daemon` headless mode, and manages more than it used to: P2Pool -and XMRig by default, plus optional tabs for a local Monero node, a proxy for external miners, and -XvB hashrate-splitting. If you mine on one machine and want a friendly app to drive it, Gupax is a -great choice. +Windows, macOS, and Linux, has a `--daemon` headless mode, and manages P2Pool and XMRig by default, +plus optional tabs for a local Monero node, a proxy for external miners, and XvB hashrate-splitting. -Pithead is a different form factor β€” an always-on server stack rather than a desktop app you launch -on your mining PC. The two overlap more than they once did: both can run your own node, take -external miners through a proxy, and split hashrate to the XvB raffle. Where Pithead goes further: +Pithead is an always-on server stack rather than a desktop app. The two overlap β€” both can run your +own node, take external miners through a proxy, and split hashrate to the XvB raffle. Where they +differ: - **Tor-first by default.** Monero, Tari, and P2Pool reach the network over onion addresses with no extra setup. Gupax ships no built-in Tor; a community Docker image adds an optional hidden service. -- **Tari merge-mining.** A second payout from the same hashes. Gupax doesn't merge-mine Tari. -- **Built to run unattended.** Nine version-pinned containers on a dedicated Linux box, node-down - worker failover, and a LAN web dashboard β€” not an app you keep open on your desktop. +- **Tari merge-mining.** A second payout from the same hashes. Gupax does not merge-mine Tari. +- **Runs unattended.** Nine version-pinned containers on a dedicated Linux box, node-down worker + failover, and a LAN web dashboard. -Pick Gupax to mine from one machine. Pick Pithead to run the whole operation yourself β€” node, -privacy, dashboard, and a fleet of workers β€” as a server you set up once. +Gupax mines from one machine. Pithead runs the node, privacy, dashboard, and a fleet of workers as +a server you set up once. --- @@ -75,10 +66,10 @@ privacy, dashboard, and a fleet of workers β€” as a server you set up once. ### Is my home IP exposed? -Mostly not. With the Tor defaults, the only time your IP leaves the box is the one-time install. -A built-in Tor daemon gives Monero, Tari, and P2Pool hidden-service (onion) addresses, so inbound -connections need no port forwarding and don't reveal your IP. Monero and Tari route P2P and -transaction traffic over Tor, and their old clearnet DNS lookups are closed. +With the Tor defaults, the only time your IP leaves the box is the one-time install. A built-in +Tor daemon gives Monero, Tari, and P2Pool hidden-service (onion) addresses, so inbound connections +need no port forwarding and do not reveal your IP. Monero and Tari route P2P and transaction +traffic over Tor, and their old clearnet DNS lookups are closed. The two former clearnet yield paths are Tor-by-default as of v1.1, each with a yield-vs-privacy opt-out: @@ -107,10 +98,10 @@ That's local network traffic, not an internet-facing port. See ### Is the XvB donation mandatory? Will it cost me? -It's optional, and the engine is designed to minimize what you give up. XvB switching is on by -default but can be turned off (`xvb.enabled: false`). When it's on, the decision engine donates -only enough hashrate to hold your target tier and routes everything else to P2Pool. Because the -XvB raffle picks winners at random, donating above a tier's threshold earns nothing extra. See +It's optional. XvB switching is on by default and turns off with `xvb.enabled: false`. When on, +the decision engine donates only enough hashrate to hold your target tier and routes everything +else to P2Pool. Because the XvB raffle picks winners at random, donating above a tier's threshold +earns nothing extra. See [Architecture β€Ί Algorithmic switching](architecture.md#algorithmic-switching) and the `xvb.*` keys in [Configuration](configuration.md#configuration-reference). diff --git a/docs/getting-started.md b/docs/getting-started.md index 61a1a76..15e240d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,7 +1,7 @@ # Getting Started -This guide takes a fresh machine to a synced, mining stack. One script, `pithead`, drives the -process; most of it runs on its own. +Install and first-run setup, from a fresh Ubuntu host to a synced, mining stack. The `pithead` +script drives every step. > **TL;DR** > diff --git a/docs/hardware.md b/docs/hardware.md index e884463..f784494 100644 --- a/docs/hardware.md +++ b/docs/hardware.md @@ -1,14 +1,13 @@ # Hardware Requirements -Hardware sizing for the stack host. The stack involves two kinds of machine, with very different -needs: +Hardware sizing for the stack host. The stack runs on two kinds of machine with different needs: 1. The stack host: the one machine that runs `./pithead` and the Docker stack (Monero node, P2Pool, - Tari, the XMRig proxy, the dashboard, Tor). It does not mine. It runs the nodes and coordinates - everything; the actual hashing happens elsewhere. + Tari, the XMRig proxy, the dashboard, Tor). It does not mine β€” it runs the nodes and coordinates; + the hashing happens elsewhere. 2. Worker rigs: one or more separate machines running [XMRig](https://github.com/xmrig/xmrig). These - do the real RandomX hashing and point at the stack host's port `3333`. A worker can be the same - machine as the host, but treating them separately is what lets you scale hashrate. + do the RandomX hashing and point at the stack host's port `3333`. A worker can be the same machine + as the host, but keeping them separate is what scales hashrate. Size the host for nodes, storage, and uptime; size the workers for CPU mining performance. @@ -36,30 +35,33 @@ Size the host for nodes, storage, and uptime; size the workers for CPU mining pe ### Where these numbers come from -The host runs several services in one box, so its requirement is the sum of what each service needs, -plus headroom for the OS. Here's the per-component breakdown, taken from each project's own guidance: +The host runs several services in one box, so its requirement is the sum of what each service needs +plus headroom for the OS. Per-component breakdown, from each project's own guidance: | Service | RAM it wants | Disk | Notes | |---|---|---|---| | **[Monero node](https://docs.getmonero.org/running-node/)** (`monerod`) | **4 GB** minimum; more RAM = bigger DB cache and faster sync | **~100 GB** pruned Β· **~265 GB** full β€” and growing | SSD strongly recommended. Not run at all in remote-node mode. | | **[P2Pool](https://github.com/SChernykh/p2pool)** | **~2.3 GB** for the RandomX dataset it uses to verify blocks fast (`--light-mode` skips it, saving ~2 GB, but verifies slower) | tiny (sidechain state) | Needs a 64-bit CPU with **AVX2** and a synced `monerod`. | -| **[Tari base node](https://www.tari.com/integration-guide)** (`minotari_node`) | **4 GB** minimum, **8 GB+** recommended; grows over time | **~135 GB** SSD β€” and growing | The single largest disk consumer. Tari's chain rivals a *full* Monero node, so budget for it whether or not you prune Monero. The stack caps its memory so growth can't take the host down. | +| **[Tari base node](https://www.tari.com/integration-guide)** (`minotari_node`) | **4 GB** minimum, **8 GB+** recommended; grows over time | **~140 GB** SSD β€” and growing | The largest single disk consumer once Monero is pruned (~140 GB vs a pruned Monero node's ~100 GB), so budget for it whether or not you prune Monero. The stack caps its memory so growth can't take the host down. | | **XMRig proxy Β· Tor Β· Caddy Β· dashboard Β· Docker** | a few hundred MB combined | a few GB (Docker images) | These coordinate and serve the UI. They don't mine, so no special CPU. | Add the three heavy services' RAM (Monero 4 GB, P2Pool ~2.3 GB, Tari 4 GB) plus a couple of GB for -the OS, page cache, and supporting containers, and you land on the 16 GB minimum above. - -Disk is dominated by the two chains. A pruned Monero node (~100 GB) plus the Tari node (~135 GB) and -a few GB for P2Pool and the OS put a pruned host near ~250 GB today; a *full* Monero node (~265 GB) -instead of pruned pushes that toward ~400 GB. The surprise for most people is Tari: its chain rivals -a full Monero node, so pruning Monero doesn't shrink it. (A *freshly synced* pruned node is ~100 GB, -but pruning an existing full chain doesn't reclaim the space until you compact it with `mdb_copy -c`, -so until then it sits at full size.) - -Both chains keep growing, roughly ~100+ GB/year combined (Tari, a young chain, grows fastest; Monero -adds tens of GB/year). That's why the table above lists a ~300 GB (pruned) / ~500 GB (full) minimum -but recommends much more: for a set-and-forget host, put it on a 2–4 TB SSD and you won't think about -disk for years. (Current sizes are measured on live deployments, not estimates.) +the OS, page cache, and supporting containers, and you reach the 16 GB minimum above. + +Disk is dominated by the two chains. A pruned Monero node (~100 GB) plus the Tari node (~140 GB) and +a few GB for P2Pool and the OS put a pruned host near ~250 GB; a *full* Monero node (~265 GB) instead +of pruned pushes that toward ~410 GB. Pruning Monero doesn't shrink Tari, so budget for Tari +regardless. (A *freshly synced* pruned node is ~100 GB, but pruning an existing full chain doesn't +reclaim space in place β€” run `monero-blockchain-prune` to write a new pruned DB; until then it sits +at full size.) + +Both chains keep growing, ~100+ GB/year combined (Tari, a young chain, grows fastest; Monero adds +tens of GB/year). That's why the table lists a ~300 GB (pruned) / ~500 GB (full) minimum but +recommends more: for a set-and-forget host, put it on a 2–4 TB SSD. Disk figures are measured on live +deployments (a pruned node at ~102 GB Monero + ~139 GB Tari; a full node at ~266 GB Monero). The +per-service **RAM** figures are provisioning minimums β€” steady-state resident memory is much lower +(`monerod` and P2Pool a few hundred MB each, since their large data lives in the shared HugePages and +in reclaimable page cache; Tari 2–4 GB and climbing), so size for the minimums, not today's usage. > NOTE: Monero and P2Pool both want large memory pages for RandomX, so they share one ~6 GB > HugePages reservation rather than each adding their own. See [Memory](#memory) for what that means @@ -67,42 +69,39 @@ disk for years. (Current sizes are measured on live deployments, not estimates.) ### CPU -The host CPU runs the nodes, P2Pool's block verification, the proxy, and the dashboard. It is not -your miner, so it doesn't need to be a high-end mining chip. Two things matter: +The host CPU runs the nodes, P2Pool's block verification, the proxy, and the dashboard. It is not the +miner, so it need not be a high-end mining chip. Two things matter: -- AVX2 is strongly recommended. P2Pool verifies blocks with RandomX, which runs far better with - AVX2; setup warns *"AVX2 not detected. Mining performance will be poor."* if it's missing. (P2Pool - also requires a 64-bit CPU; ARMv7 and older aren't supported.) -- More cores speed up the first sync. Monero parallelizes block verification during the initial - sync: `monero.prep_blocks_threads` defaults to `auto` = host cores βˆ’ 2, clamped to 4–8. So 6–10 - cores let it use the full thread budget while leaving headroom for the rest of the stack. After the - initial sync, steady-state CPU load is low. +- AVX2 is strongly recommended. P2Pool verifies blocks with RandomX, which runs far better with AVX2; + setup warns *"AVX2 not detected. Mining performance will be poor."* if it's missing. (P2Pool also + requires a 64-bit CPU; ARMv7 and older aren't supported.) +- More cores speed up the first sync. Monero parallelizes block verification during the initial sync: + `monero.prep_blocks_threads` defaults to `auto` = host cores βˆ’ 2, clamped to 4–8. So 6–10 cores use + the full thread budget while leaving headroom for the rest of the stack. Steady-state CPU load + after the initial sync is low. ### Memory -16 GB is the practical floor with the default configuration. The budget breaks down as: +16 GB is the practical floor with the default configuration. The budget: -- ~6 GB reserved for HugePages. RandomX wants large pages, so setup configures - `vm.nr_hugepages=3072` (3072 Γ— 2 MB = 6 GB), shared by `monerod` and P2Pool. This RAM is carved out - of the kernel up front and is invisible to container memory stats; it's gone whether or not it's - fully used at any moment. -- Tari (4 GB+, growing) gets an auto-sized safety ceiling (`tari.mem_limit: auto`) so a genuine - runaway restarts cleanly instead of taking the host down. On a 16 GB host that ceiling lands around - 7.5 GB; on 32 GB, around 19 GB. +- ~6 GB reserved for HugePages. RandomX wants large pages, so setup configures `vm.nr_hugepages=3072` + (3072 Γ— 2 MB = 6 GB), shared by `monerod` and P2Pool. This RAM is carved out of the kernel up front + and is invisible to container memory stats; it's gone whether or not it's fully used. +- Tari (4 GB+, growing) gets an auto-sized ceiling (`tari.mem_limit: auto`) so a runaway restarts + cleanly instead of taking the host down. On a 16 GB host that ceiling is ~7.5 GB; on 32 GB, ~19 GB. - The OS, page cache, and the lighter containers take the rest. -On a 16 GB machine this all fits but is tight, which is exactly why Tari is capped. 32 GB is -recommended if you run a full (unpruned) node, drive a lot of workers, or want long uptimes without -Tari's growth ever pressing on the cap. +On a 16 GB machine this fits but is tight, which is why Tari is capped. Use 32 GB if you run a full +(unpruned) node, drive many workers, or want long uptimes without Tari's growth pressing on the cap. -> Running with only 8 GB? It can boot only if you disable HugePages (`./pithead setup -> --skip-optimize`), which frees the 6 GB reservation, but it leaves very little headroom and hurts -> RandomX verification performance. Not recommended; prefer 16 GB+. +> Running with only 8 GB? It boots only if you disable HugePages (`./pithead setup --skip-optimize`), +> which frees the 6 GB reservation, but leaves little headroom and hurts RandomX verification +> performance. Prefer 16 GB+. ### Disk The two blockchains dominate, and an SSD is strongly recommended: initial-sync verification and the -node databases do a lot of random I/O that punishes spinning disks. What to provision: +node databases do heavy random I/O that punishes spinning disks. What to provision: | | Pruned (default) | Full (`monero.prune: false`) | |---|---|---| @@ -112,16 +111,14 @@ node databases do a lot of random I/O that punishes spinning disks. What to prov | **Plan for** | **~300 GB+ SSD** | **~500 GB+ SSD** | Both chains keep growing, ~100+ GB/year combined (Tari, a young chain, grows fastest), so leave -plenty of headroom: the *recommended* 1 TB+ (pruned) / 2 TB+ (full) sizes exist for exactly that, and -a 2–4 TB SSD is the true set-and-forget choice. Note that Tari's chain (~135 GB) is the largest -single item and is the same whether or not you prune Monero, so pruning only saves disk on the Monero -side. Pruning (the default) keeps a fully validating Monero node at a fraction of the size and is the -right choice for almost everyone. +headroom: the *recommended* 1 TB+ (pruned) / 2 TB+ (full) sizes exist for that, and a 2–4 TB SSD is +the set-and-forget choice. Tari's chain (~135 GB) is the largest single item and is the same whether +or not you prune Monero, so pruning only saves disk on the Monero side. Pruning (the default) keeps a +fully validating Monero node at a fraction of the size. -> `setup` pre-flights these. Before committing to a sync, `./pithead setup` checks free disk and -> total RAM against the minimums on this page (~300 GB pruned / ~500 GB full disk, 16 GB RAM) and -> warns if the host falls short; it never blocks. `./pithead doctor` re-runs the same disk and RAM -> checks on demand, so you can re-verify a host at any time. +> `setup` pre-flights these. Before a sync, `./pithead setup` checks free disk and total RAM against +> the minimums on this page (~300 GB pruned / ~500 GB full disk, 16 GB RAM) and warns if the host +> falls short; it never blocks. `./pithead doctor` re-runs the same disk and RAM checks on demand. You can put any service's data on a dedicated disk by pointing its `*.data_dir` at an absolute path, e.g. to keep the Monero blockchain on a separate SSD. See @@ -132,14 +129,14 @@ e.g. to keep the Monero blockchain on a separate SSD. See - Always-on broadband. All upstream traffic (Monero, Tari, P2Pool) goes over Tor, with no public port forwarding required; the stack uses hidden services for inbound peers. - Initial sync is the heavy part. The first run downloads and verifies both chains over Tor (slower - than clearnet): ~100 GB pruned / ~265 GB full for Monero, plus ~135 GB for Tari. This can take - anywhere from a few hours to a day or more. You can avoid it by + than clearnet): ~100 GB pruned / ~265 GB full for Monero, plus ~135 GB for Tari. This takes a few + hours to a day or more. Avoid it by [reusing an existing synced node](configuration.md#reusing-an-existing-node), or speed it up with an [optional clearnet initial sync](privacy.md#optional-clearnet-initial-sync-off-by-default) (default off, privacy-relevant) that downloads over clearnet and then returns to Tor. - Steady state is light. Once synced, bandwidth is modest. -- LAN reachability for workers. Each worker rig connects to the host on port 3333 over your local - network (plain stratum, not Tor). If the host has a firewall, allow inbound `3333` from your LAN. +- LAN reachability for workers. Each worker rig connects to the host on port 3333 over the local + network (plain stratum, not Tor). If the host has a firewall, allow inbound `3333` from the LAN. ### Operating system & dependencies @@ -158,8 +155,7 @@ e.g. to keep the Monero blockchain on a separate SSD. See ## Lighter-footprint options -The defaults assume a self-hosted, pruned, HugePages-tuned local node. You can trade some of that -away: +The defaults assume a self-hosted, pruned, HugePages-tuned local node. You can trade some away: | Want to… | Do this | Saves | |---|---|---| @@ -179,16 +175,15 @@ away: ## Sizing examples - Small home setup (pruned): a 6-core / 16 GB / 240 GB SSD mini-PC as the host, HugePages on, with - one or two workers pointed at it. Comfortable for getting started. + one or two workers pointed at it. - Full node + several workers: an 8-core / 32 GB / 600 GB SSD host running an unpruned node, feeding a handful of dedicated mining rigs. Headroom for Tari growth and long uptimes. -- Minimal / reuse-an-existing-node: point the stack at a Monero node you already run (remote mode), - and the host needs only enough for Tari, P2Pool, the proxy, dashboard, and Tor; far less disk and +- Minimal / reuse-an-existing-node: point the stack at a Monero node you already run (remote mode); + the host then needs only enough for Tari, P2Pool, the proxy, dashboard, and Tor β€” far less disk and RAM. -> Sizing the miners that connect to this host is a separate exercise; their CPU is what determines -> hashrate. See RigForge's -> [Hardware Requirements](https://github.com/p2pool-starter-stack/rigforge#-hardware-requirements). +> Sizing the miners that connect to this host is separate; their CPU determines hashrate. See +> RigForge's [Hardware Requirements](https://github.com/p2pool-starter-stack/rigforge#-hardware-requirements). --- diff --git a/docs/integration-testing.md b/docs/integration-testing.md index 25aa534..0a7f680 100644 --- a/docs/integration-testing.md +++ b/docs/integration-testing.md @@ -8,8 +8,7 @@ gate described in [Releasing](releasing.md) (issue The other suites are client-side and never touch a daemon: the `pithead` shell tests stub out `docker`/`sudo`, the compose test only checks `docker compose config` interpolation, and the dashboard pytest mocks its clients. They prove the code is correct. They can't prove that a -real `apply β†’ sync-gate β†’ mine β†’ status` flow works on a real host. That's what this suite is -for. +real `apply β†’ sync-gate β†’ mine β†’ status` flow works on a real host. This suite proves that. > This live matrix is tier 4 of a four-tier plan. The runtime situations a healthy box can't > show (cold sync, node-down, unhealthy containers, XvB tiers) are simulated more cheaply at @@ -31,9 +30,9 @@ The suite lives under [`tests/integration/`](../tests/integration/): ## How it works -The suite assumes the box is already deployed and synced with miners connected. The point of a -dedicated test server is that the full Monero and Tari nodes are synced once and reused, so each -scenario runs in minutes instead of waiting days for a chain sync. +The suite assumes the box is already deployed and synced with miners connected. A dedicated test +server syncs the full Monero and Tari nodes once and reuses them, so each scenario runs in minutes +instead of waiting days for a chain sync. Given that, the harness moves between matrix scenarios with non-interactive `pithead apply -y`, which: diff --git a/docs/monitoring.md b/docs/monitoring.md index 9b21c84..e1533d3 100644 --- a/docs/monitoring.md +++ b/docs/monitoring.md @@ -103,7 +103,7 @@ secret-handling and Tor-reachability notes): [Configuration β€Ί reference](confi > Auto-provisioning the check via the Healthchecks.io Management API (so you wouldn't have to > copy the URL by hand) was considered but deliberately left out: it would mean storing a -> powerful API key in your config. Manual setup keeps it simple, secret-free, and works +> high-privilege API key in your config. Manual setup keeps it simple, secret-free, and works > equally well with a self-hosted instance. --- diff --git a/docs/operations.md b/docs/operations.md index b8232ba..b11ee6d 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -1,6 +1,6 @@ # Operations & Maintenance -Everything you do to the stack runs through `pithead`. Run `./pithead help` to see the full list. +Command reference for `pithead`, the CLI that manages the stack. Run `./pithead help` for the same list. ## Command reference @@ -50,22 +50,22 @@ finish their initial sync. Check the dashboard to see which. ./pithead restart ``` -**Change a setting:** edit `config.json`, then `./pithead apply`. See +**Change a setting:** edit `config.json`, then run `./pithead apply`. See [Configuration β€Ί Changing settings later](configuration.md#changing-settings-later). -**Reboot resilience:** every service runs with `restart: unless-stopped`, so the whole stack comes -back on its own after a reboot or power loss, *provided the Docker daemon itself starts at boot*. -On Ubuntu's packaged Docker that's the default, but a custom/rootless install (or -`setup --skip-deps`) may leave it disabled. `./pithead doctor` checks this and warns if Docker -isn't boot-enabled; the fix is `sudo systemctl enable --now docker`. +**Reboot resilience:** every service runs with `restart: unless-stopped`, so the stack restarts +after a reboot or power loss, provided the Docker daemon starts at boot. Ubuntu's packaged Docker +enables this by default; a custom/rootless install (or `setup --skip-deps`) may leave it disabled. +`./pithead doctor` checks this and warns if Docker isn't boot-enabled. Fix it with +`sudo systemctl enable --now docker`. --- ## Updating the stack -How you update depends on how you installed (see [Getting Started](getting-started.md#2-get-the-code)). +The update path depends on how you installed (see [Getting Started](getting-started.md#2-get-the-code)). -**Release bundle (the default):** from your install directory, re-download the latest bundle over it, +**Release bundle (the default):** from the install directory, re-download the latest bundle over it, then upgrade. `upgrade` **pulls** the new published images: ```bash @@ -82,15 +82,14 @@ git pull Either way, `upgrade` re-renders the generated config (`.env`, the Caddyfile, and the Tari config) for the new release *before* pulling/rebuilding, so a release that changes a config template or adds an -`.env` var takes effect, not just the new image. Your data directories and `config.json` are untouched, -so your blockchain sync and settings are preserved across upgrades. +`.env` var takes effect, not just the new image. Data directories and `config.json` are untouched, so +blockchain sync and settings survive an upgrade. ### Switching a source checkout to release images -If you cloned the repo (so the dashboard badge reads `dev Β· branch @ commit`) and would rather run the -**published, tested images** (a clean version badge, a working update-checker, and no local build), -convert the install in place. Your `config.json`, `.env`, Tor onion keys, and data directories are all -preserved: +A cloned repo builds `:dev` images locally and shows a `dev Β· branch @ commit` version badge. To run +the published images instead (clean version badge, working update-checker, no local build), convert the +install in place. `config.json`, `.env`, the Tor onion keys, and data directories are preserved: ```bash ./pithead backup -y # safety snapshot: config.json, .env, onion keys, dashboard db (chains excluded) @@ -101,11 +100,10 @@ rm -f build/*/Dockerfile # remove the image Dockerfiles β†’ pithead switches ``` `pithead` chooses build-vs-pull by whether the image Dockerfiles are present (`build//Dockerfile`). -Deleting them is what flips it from building `:dev` locally to pulling the published `:vX.Y.Z`. To go -back to building from source, `git checkout vX.Y.Z` (or `git pull`) restores the Dockerfiles, then -`./pithead upgrade` rebuilds locally again. The new validation in `upgrade` will refuse to start on a -non-primary Monero payout address, so confirm yours is a `4…`/95-char address first (see -[Configuration](configuration.md)). +Deleting them flips it from building `:dev` locally to pulling the published `:vX.Y.Z`. To go back to +building from source, `git checkout vX.Y.Z` (or `git pull`) restores the Dockerfiles, then +`./pithead upgrade` rebuilds locally. `upgrade` refuses to start on a non-primary Monero payout address, +so confirm yours is a `4…`/95-char address first (see [Configuration](configuration.md)). > **Moving the install?** Data directories are stored as absolute paths in `.env`, so relocating or > copying the stack to a different path (or running a second checkout) points it at a *different, @@ -117,44 +115,39 @@ non-primary Monero payout address, so confirm yours is a `4…`/95-char address ## Backups -Your important state lives in the data directories (by default under `./data/`, or wherever you -pointed each `*.data_dir`; see [Configuration β€Ί Data directories](configuration.md#data-directories)): +State lives in the data directories (by default under `./data/`, or wherever each `*.data_dir` +points; see [Configuration β€Ί Data directories](configuration.md#data-directories)): -- **`config.json`**: your settings (keep a copy somewhere safe; it's `chmod 600`). -- **`data/tor/`**: your onion service keys. Back these up if you want to keep the same onion - addresses across a rebuild. -- **`data/monero/`**, **`data/tari/`**: the blockchains. Large, but backing them up saves a - re-sync; they can also be re-downloaded from the network if lost. -- **`data/dashboard/`**: the dashboard's database, your hashrate history and settings. Small but - irreplaceable (it doesn't re-sync), so it's part of the default `backup`. +- **`config.json`**: settings. `chmod 600`; keep a copy off-host. +- **`data/tor/`**: onion service keys. Back up to keep the same onion addresses across a rebuild. +- **`data/monero/`**, **`data/tari/`**: the blockchains. Large; backing them up saves a re-sync, + but they re-download from the network if lost. +- **`data/dashboard/`**: the dashboard database (hashrate history and settings). Small and + irreplaceable β€” it does not re-sync β€” so it is part of the default `backup`. -Stop the stack (`./pithead down`) before copying data directories so files are in a consistent -state. +Stop the stack (`./pithead down`) before copying data directories by hand, so files are consistent. ### `backup` / `restore` -Rather than copying files by hand, let `pithead` do it for you: +Instead of copying files by hand, run: ```bash ./pithead backup ``` -That's it. This saves the things you can't get back: your `config.json`, your secrets (`.env`), -your `Caddyfile` (if you have one), the Tor onion address keys, and the dashboard's database (your -hashrate history and settings), into a small, timestamped file under `backups/`. -It's quick and small because your blockchains are **not** included (they just re-sync). The archive -is locked down to `chmod 600`, and `pithead` prints its path when it's done. Before it writes -anything, it checks there's room; if free space looks tight, it asks before going ahead so a backup -can't quietly fill your disk. +This writes a timestamped `tar.gz` under `backups/` holding the irreplaceable state: `config.json`, +`.env` (secrets), the `Caddyfile` (if present), the Tor onion keys, and the dashboard database +(hashrate history and settings). Blockchains are excluded (they re-sync), so the archive is small. +The archive is `chmod 600`, and `pithead` prints its path when done. Before writing, `backup` checks +free space and prompts if it looks tight. -If the stack is running, `backup` offers to briefly stop it for a clean copy and start it again -when it's done. Pass `-y` / `--yes` to skip the prompts (the low-space warning and the -stop-the-stack question) and just back up. +If the stack is running, `backup` stops it for a consistent copy and restarts it when done. Pass +`-y` / `--yes` to skip both prompts (low-space warning, stop-the-stack question). -**Optional extras** (you usually don't need these): +Include the blockchains (larger, slower) with: ```bash -./pithead backup --with-chains # also include the blockchain data β€” much bigger and slower +./pithead backup --with-chains # also include the blockchain data ``` To recover (on a new machine, or after a wipe) copy the archive back and run: @@ -165,36 +158,33 @@ To recover (on a new machine, or after a wipe) copy the archive back and run: ./pithead up ``` -`restore` always **asks before it overwrites anything**, so you can change your mind (pass -`-y` / `--yes` to skip that prompt). It puts the files back where they belong and sorts out the -Tor key ownership for you, so your onion address comes back exactly as it was, and your hashrate -history and dashboard settings come back too. +`restore` prompts before overwriting anything (pass `-y` / `--yes` to skip). It puts the files back, +fixes Tor key ownership so the onion address returns unchanged, and restores hashrate history and +dashboard settings. -> **Note:** After a restore, the dashboard's HTTPS certificate is regenerated, so your browser -> may show its "not trusted" warning once. That's expected; accept it as you did on first setup. +> NOTE: After a restore, Caddy regenerates the dashboard's HTTPS certificate, so the browser shows +> its "not trusted" warning once. Accept it as on first setup. --- ## Troubleshooting **The dashboard is stuck on Sync Mode.** -This usually just means a chain is still downloading. Confirm steady progress: +A chain is still downloading. Confirm steady progress: ```bash ./pithead logs monerod ./pithead logs tari ``` -If a node looks genuinely stalled (no new blocks over a long period), restart it with -`./pithead restart`. To avoid the wait entirely, point the stack at an existing synced -blockchain or a remote node. See +If a node is stalled (no new blocks over a long period), restart it with `./pithead restart`. To +skip the wait, point the stack at an existing synced blockchain or a remote node. See [Configuration β€Ί Reusing an existing node](configuration.md#reusing-an-existing-node). **Tari shows high memory use.** -Usually nothing to worry about; most of it is reclaimable disk cache, not a leak. Tari has an -auto-sized memory limit (`tari.mem_limit`) that keeps a genuine runaway from affecting the rest of -the stack. Only change it if Tari restarts repeatedly (give it more) or you want to free RAM for -other apps (give it less), then run `./pithead apply`. +Most of it is reclaimable disk cache, not a leak. Tari runs under an auto-sized memory limit +(`tari.mem_limit`) that caps a runaway from affecting the rest of the stack. Change it only if Tari +restarts repeatedly (raise it) or you need RAM for other apps (lower it), then run `./pithead apply`. **Browser warns "your connection is not private."** Expected with `dashboard.secure: true`: Caddy uses a self-signed certificate. Accept the warning @@ -205,8 +195,8 @@ Check that each rig points at `YOUR_STACK_IP:3333` and that port `3333` is reach worker (firewall on the stack host?). See [Connecting Miners](workers.md). **Hashrate reads zero or the chart is blank.** -Give it a minute after a worker connects for stats to populate. Confirm the worker is actually -hashing (`./pithead logs xmrig-proxy`). +Stats take about a minute to populate after a worker connects. Confirm the worker is hashing +(`./pithead logs xmrig-proxy`). **P2Pool can't connect to a remote node.** The node must be set up for mining: **ZMQ publishing enabled** (`zmq-pub`) and its RPC reachable @@ -217,10 +207,10 @@ by P2Pool. Public "open node" endpoints don't qualify; use a node you run and co Persistent HugePages require a GRUB change and a **reboot**. Re-run `./pithead setup` (without `--skip-optimize`) and reboot when prompted. -**Something looks broken in the dashboard data and you want a clean slate.** +**The dashboard data looks broken and you want a clean slate.** `./pithead reset-dashboard` wipes and recreates the dashboard and P2Pool data. This is -**destructive**: you'll lose P2Pool sidechain state and dashboard history (your blockchains and -wallets are unaffected). Pass `-y` / `--yes` to skip the confirmation prompt. +**destructive**: it drops P2Pool sidechain state and dashboard history (blockchains and wallets are +unaffected). Pass `-y` / `--yes` to skip the confirmation prompt. --- diff --git a/docs/privacy.md b/docs/privacy.md index 5c695a2..910de4b 100644 --- a/docs/privacy.md +++ b/docs/privacy.md @@ -155,10 +155,10 @@ stops the (already Tor-routed, #163) stats fetch. ## Optional clearnet initial sync (off by default) Routing everything over Tor is correct for ongoing operation, but it makes the one-time initial -blockchain sync (IBD) painfully slow: Tor circuits are bandwidth-capped and flaky, so a full Monero -sync can crawl at near-zero blocks/sec and stall for long stretches, and Tari's large chain is no -better. The standard pattern for Tor-based nodes is to sync once over clearnet (fast), then lock back -to Tor. This stack supports that as an explicit, default-off opt-in (#183). +block download (IBD) slow: Tor circuits are bandwidth-capped, so a full Monero sync can drop to +near-zero blocks/sec and stall for long stretches, and Tari's chain is no faster. The standard +pattern for Tor-based nodes is to sync once over clearnet, then return to Tor. The stack supports this +as an explicit, default-off opt-in (#183). Per-component flags in `config.json`, both `false` by default: @@ -201,12 +201,11 @@ be explicitly opted into. ### It switches back to Tor automatically (#234) -You don't have to babysit it. The dashboard already tracks each chain's sync state; the first time a -clearnet node reports fully synced, it switches that node back to Tor for you. It writes a persistent -"sync complete" marker and restarts the daemon, which comes back up Tor-only. From then on the node -stays on Tor across restarts, `apply`, and reboots (the marker, not the flag, is the source of truth, -so a restart can never silently re-expose a synced node). Monero and Tari transition independently, -each as soon as *it* finishes. +The dashboard tracks each chain's sync state. The first time a clearnet node reports fully synced, the +dashboard writes a persistent "sync complete" marker and restarts the daemon, which comes back up +Tor-only. From then on the node stays on Tor across restarts, `apply`, and reboots (the marker, not +the flag, is the source of truth, so a restart can never silently re-expose a synced node). Monero and +Tari transition independently, each as soon as *it* finishes. You can leave `clearnet_initial_sync: true` in `config.json`; it's effectively spent once the sync completes. (To deliberately re-sync over clearnet later, e.g. after wiping a chain, toggle the flag @@ -214,7 +213,7 @@ off and on again with `./pithead apply`, which re-arms it.) ### It is loud and always-visible -You can't enable this by accident or miss that it's active: +The active state is surfaced in four places, so it can't be enabled by accident or missed: - `./pithead apply` prints a `⚠`-flagged, disruptive-change confirmation describing exactly what becomes exposed before it recreates the daemon. @@ -257,7 +256,7 @@ single-purpose appliance. One consequence is worth recording explicitly: - [ ] Keep `:3333` off the public internet: firewall it to your LAN, set `p2pool.stratum_bind`, and/or require a `p2pool.stratum_password` (`pithead doctor` flags public-IP exposure). -- [ ] Route P2Pool outbound through Tor by editing its compose `command:` (above) if you accept the latency. +- [ ] Leave `p2pool.clearnet` off (the default) to keep P2Pool outbound peers on Tor (#165). - [ ] Set `xvb.enabled: false` if you don't want any XvB egress. - [ ] Leave `monero.clearnet_initial_sync` / `tari.clearnet_initial_sync` off (the default) to keep all node P2P on Tor. If you do use a clearnet sync, the dashboard switches each node back to Tor automatically once it's synced; `pithead doctor` flags it while exposed and clears when done. - [ ] Run the initial install/build behind a VPN or `torsocks`. diff --git a/docs/release-server.md b/docs/release-server.md index 0445281..5aec32d 100644 --- a/docs/release-server.md +++ b/docs/release-server.md @@ -1,8 +1,8 @@ # The Release / Validation Server -This page covers how a build is validated end-to-end before release, why that needs a dedicated -server, what GitHub Actions does for free on every PR, and how to harden the server. It is the -operational companion to [Releasing](releasing.md) (the version/promote pipeline) and +How a build is validated end-to-end before release, why that needs a dedicated server, what +GitHub Actions runs on every PR, and how to harden the server. Operational companion to +[Releasing](releasing.md) (the version/promote pipeline) and [Integration Testing](integration-testing.md) (the harness it runs). ## Can GitHub Actions do the full end-to-end? (no) @@ -33,8 +33,8 @@ So the split is clean: | **Tiers 1–3** (logic, wiring, control plane, hardening) | GitHub-hosted runners | free (public repo) | every PR, the merge gate | | **Tier 4** (real synced Monero+Tari, real merge-mining, prune/full DB, TLS/Tor, the config matrix, the staging smoke test) | the dedicated server | your hardware | pre-release / on-demand, the release gate | -The hosted runners catch the vast majority of regressions before merge. The dedicated server -proves the things only reality can, and it's the blocking pre-release gate. +The hosted runners catch most regressions before merge. The dedicated server proves what only +real chains can, and it is the blocking pre-release gate. ## Validating PRs on the dedicated server (possible, but security-loaded) diff --git a/docs/releasing.md b/docs/releasing.md index 778bc82..11a683a 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -1,27 +1,24 @@ # Releasing -How Pithead is versioned and released. This page documents the agreed process -([#44](https://github.com/p2pool-starter-stack/pithead/issues/44)). The pipeline it describes -is implemented as [`scripts/release.sh`](../scripts/release.sh). Run it from the build/test -server with `make release` (preview a run with `make release ARGS="--dry-run"`). The one -remaining piece is wiring `${STACK_VERSION}` into `docker-compose.yml` so installs pull the -published images rather than building; see [Status](#status) below. +How Pithead is versioned and released +([#44](https://github.com/p2pool-starter-stack/pithead/issues/44)). The pipeline is +implemented as [`scripts/release.sh`](../scripts/release.sh). Run it from the build/test +server with `make release` (preview a run with `make release ARGS="--dry-run"`). ## One product, one version Pithead is versioned and released as a single product, not as individual components. The components are upstream projects pinned and integrated, not authored here: `p2pool` -(`ARG P2POOL_VERSION`), `xmrig-proxy`, `monerod`, and `tari` -(`quay.io/tarilabs/minotari_node:vX-mainnet`). The only first-party code is the dashboard -plus the orchestration (`pithead`, `docker-compose.yml`, configs). The unit of value, and the -thing the integration matrix validates, is the composed, tested-together set. So a release is -one artifact with one version, one changelog, one upgrade path, and one "new version available" -signal. +(`ARG P2POOL_VERSION`), `xmrig-proxy` (`ARG XMRIG_PROXY_VERSION`), `monerod` +(`ARG MONERO_VERSION`), and `tari` (`quay.io/tarilabs/minotari_node:v5.3.1-mainnet`, +pinned by digest in `docker-compose.yml`). The first-party code is the dashboard plus the +orchestration (`pithead`, `docker-compose.yml`, configs). The integration matrix validates the +composed set. A release is one artifact with one version, one changelog, one upgrade path, and +one "new version available" signal. -The one accepted trade-off: hot-swapping a single component to a version not tested together -isn't supported. Power users can still override an ARG or image tag locally, but that -combination isn't a supported release. +Trade-off: swapping a single component to a version not tested together is unsupported. You can +override an ARG or image tag locally, but that combination is not a supported release. ## Single source of truth @@ -34,37 +31,37 @@ The product version lives in a top-level [`VERSION`](../VERSION) file: plain tex - The dashboard's `pyproject.toml` is kept in lockstep (packaging metadata only); a shell test fails if it drifts from `VERSION`. -> NOTE: for the first real release, `VERSION` is `0.1.0`. Bump it to the version you want to -> publish first (the `pyproject.toml` metadata must match, enforced by the drift-guard test). +> NOTE: `VERSION` is `1.0.3`. Set it to the version you want to publish; the `pyproject.toml` +> metadata must match, enforced by the drift-guard test. ## Component pins = an ingredients manifest -Every component stays pinned (build ARGs and image tags), but the pins are the ingredients -lockfile of each product release, not independent releases: +Every component stays pinned (build ARGs and image tags). The pins are the ingredients lockfile +of each product release, not independent releases: -- Surface them in the dashboard as "what's inside vX.Y.Z" (component info is already shown). +- The dashboard surfaces them as "what's inside vX.Y.Z" (component info is already shown). - Bumping any component, including a security patch such as a `monerod` CVE, is a normal stack - release: bump the pin β†’ cut a stack patch β†’ re-run the integration gate β†’ ship. No loss of - patch agility; the bundle ships re-tested. + release: bump the pin β†’ cut a stack patch β†’ re-run the integration gate β†’ ship. The bundle + ships re-tested. ## Published images: GHCR, single-tag model -Images are published to GitHub Container Registry (`ghcr.io/p2pool-starter-stack/*`), which is -free for public images: unlimited free pulls and no Docker Hub-style rate limits. +Images are published to GitHub Container Registry (`ghcr.io/p2pool-starter-stack/*`). Public +images pull without a Docker Hub-style rate limit. -"One product" doesn't mean one image; the stack is inherently multi-container. Every built image -(`dashboard`, `p2pool`, `xmrig-proxy`, `monero`, `tor`) is published, all tagged with the single -stack version, and compose references one `${STACK_VERSION}`. Users `docker compose pull` a -coherent set with one knob, removing the old "git pull + rebuild" upgrade path. The version is -the bundle, not the layers. +The stack is multi-container. Every built image (`pithead-dashboard`, `pithead-p2pool`, +`pithead-xmrig-proxy`, `pithead-monero`, `pithead-tor`) is published, all tagged with the single +stack version, and compose references one `${STACK_VERSION}`. `docker compose pull` fetches the +set with one knob, replacing the "git pull + rebuild" upgrade path. The version is the bundle, +not the layers. ## Release process Releases are cut on a private build/test server that runs the full Monero and full Tari nodes (the integration-test environment from [#54](https://github.com/p2pool-starter-stack/pithead/issues/54)). A single entry point, -`make release` (or `pithead release`), runs the whole pipeline. Nothing is promoted or published -until every gate is green. +`make release` (or `pithead release`), runs the pipeline. Nothing is promoted or published until +every gate is green. > How to provision and harden that server, why end-to-end validation can't run on GitHub-hosted > runners (and what does run free on every PR), and the safe self-hosted-runner setup are covered @@ -119,17 +116,15 @@ a single, validated bundle. - Patches: security and component bumps ship as normal patch releases, re-validated through the same gate. -## Install & upgrade UX - -The goal is one command: +## Install & upgrade - Install: download the release's compose bundle (or `git checkout vX.Y.Z`) β†’ `./pithead setup`. - Images are pulled from GHCR. No local build, no compile wait. + Images are pulled from GHCR; no local build. - Upgrade: the dashboard shows "vX.Y.Z available" - ([#59](https://github.com/p2pool-starter-stack/pithead/issues/59)) β†’ the user runs - `./pithead upgrade` β†’ it pulls the new single-tagged images and recreates only what changed. -- Trust: every published version is one immutable, #54-validated bundle; release notes list - exactly what's inside and what changed. + ([#59](https://github.com/p2pool-starter-stack/pithead/issues/59)) β†’ run `./pithead upgrade` β†’ + it pulls the new single-tagged images and recreates only what changed. +- Every published version is one immutable, #54-validated bundle; release notes list what's + inside and what changed. ## Status diff --git a/docs/test-server-architecture.md b/docs/test-server-architecture.md index b7d68b9..22bcffc 100644 --- a/docs/test-server-architecture.md +++ b/docs/test-server-architecture.md @@ -4,6 +4,8 @@ How the Pithead reference test server (the reference box) is structured, and how another box. The synced chains are the slow-to-acquire asset (days to sync); everything else is reproducible in minutes from the repo. +See also [Releasing](releasing.md) and [Release / Validation Server](release-server.md). + ## What this server is A single box that runs the live Pithead stack against real, synced chains and serves three jobs: @@ -63,15 +65,15 @@ A 1 TB NVMe holds the pruned bench with ~650 GB to spare, room for a full node a > The fix is to put the chains on a fast NVMe SSD. Add an m.2 PCIe NVMe and migrate the chains > onto it; mount the data dir by UUID via fstab (ext4, `noatime`, `nofail`) and keep the OS on a > separate disk. monerod then opens the ~266 GB pruned LMDB in seconds and the full integration -> matrix runs green. Compaction to ~95 GB is a minutes-long `mdb_copy -c /lmdb ` if ever -> wanted (the chain is correctly pruned; the extra size is reclaimable free-page bloat, not a full -> chain); stage the matching `mdb_copy` (LMDB 0.9.70, from Monero's vendored source) at -> `~/pithead-testbench/bin/mdb_copy`. CoW snapshots would still need btrfs/zfs on the NVMe (if it's -> ext4); see below. +> matrix runs green. Compaction to ~95 GB uses +> [`compact-chain.sh`](../tests/integration/compact-chain.sh) +> (`monero-blockchain-prune --copy-pruned-database`) β€” the chain is correctly pruned; the extra +> size is reclaimable free-page bloat, not a full chain. Stock `mdb_copy -c` does not work: Monero +> ships a patched LMDB and stock `mdb_copy` rejects the format (`MDB_VERSION_MISMATCH`). CoW +> snapshots need btrfs/zfs on the NVMe (if it's ext4); see below. A second m.2 NVMe (PCIe) with btrfs/zfs additionally enables copy-on-write snapshots: instant, -near-free chain clones for isolated/parallel test runs, the upgrade that helps a busy multi-agent -bench. +near-free chain clones for isolated/parallel test runs. ## Directory layout diff --git a/docs/testing-guide.md b/docs/testing-guide.md index d69ec20..5d8ca6c 100644 --- a/docs/testing-guide.md +++ b/docs/testing-guide.md @@ -1,9 +1,10 @@ # Testing Guide (for developers) -How to test a change you just made. The [Testing Strategy](testing-strategy.md) explains why the -tiers exist; the generated [Test Inventory](test-inventory.md) lists what exists today. +Where to put a test for a change you just made, and how to run it. The +[Testing Strategy](testing-strategy.md) explains why the tiers exist; the generated +[Test Inventory](test-inventory.md) lists what exists today. -## Philosophy +## Principles - Test the intent, not the line. A test pins down a behavior or contract β€” "a pruned node displays Pruned", "the gate holds until both chains sync", "an old DB migrates without losing @@ -11,7 +12,7 @@ tiers exist; the generated [Test Inventory](test-inventory.md) lists what exists Don't add a test purely to move the coverage number. - The 80% coverage gate is a floor, not a target. Uncovered defensive error-handling is fine; uncovered behavior (a migration path, a retention rule, a decision branch) is a gap. -- Tests are real code. They're linted (`shellcheck`), version-controlled with the change they +- Tests are real code. They are linted (`shellcheck`), version-controlled with the change they protect, and listed in the inventory. A CI drift check fails if you add or remove a test without regenerating it. @@ -35,7 +36,7 @@ make test-integration ARGS="--host user@box --dir pithead --check" # tier-4 li | Dashboard logic (a decision, metric, `/api/state` field) | `build/dashboard/tests/**/test_*.py` (pytest) | 1 | | Frontend logic (worker sort, formatting) | `build/dashboard/tests/frontend/*.test.mjs` (`node --test`) | 1 | | A client that parses a daemon (monerod RPC, Tari gRPC) | `tests/integration/fakes/test_contract.py` (+ extend the fakes) | 2 | -| The control plane (sync-gate #35, failover #31) | `tests/service/test_data_service.py` (+ a `mini-stack` scenario) | 1 + 3 | +| The control plane (sync-gate #35, failover #31) | `build/dashboard/tests/service/test_data_service.py` (+ a `mini-stack` scenario) | 1 + 3 | | `pithead` CLI behavior | `tests/stack/run.sh` | 1 | | A compose **security/hardening** invariant (caps, `no-new-privileges`, no secret in a healthcheck, socket-proxy scope) | the #90 section of `tests/stack/test_compose.sh` | 1 | | A new `config.json` axis | one row in `tests/integration/scenarios.sh` | 4 | @@ -94,7 +95,7 @@ Add a scenario to `tests/integration/mini-stack/run-mini-stack.sh`: drive the fa ## Gotchas learned on real hardware The live harness was first run against a real synced, mining box. These are the calibration lessons -now baked into the tests. Keep them in mind. +now baked into the tests. - A synced local monerod shows `state: "loading"` in `/api/state`, not `"done"` β€” it has no target height once caught up. Assert "synced" via monerod's own `get_info.synchronized` (the harness's diff --git a/docs/testing-strategy.md b/docs/testing-strategy.md index c3111fb..d11b36e 100644 --- a/docs/testing-strategy.md +++ b/docs/testing-strategy.md @@ -1,12 +1,12 @@ # Testing Strategy -How Pithead simulates every situation the stack can be in, and which layer proves each one. This -is the map behind the [integration suite](integration-testing.md); read that for how to run the -live matrix, and this for what we test where, and why. +Maps every runtime situation the stack can be in to the tier that proves it. This is the map +behind the [integration suite](integration-testing.md); read that for how to run the live matrix, +and this for what is tested where. The stack's runtime behaviour is a state machine: syncing β†’ held β†’ released; healthy β†’ down β†’ rejected β†’ recovered β†’ readmitted; XvB tiers; container health. A healthy, already-synced box only -ever shows one corner of it, so we simulate the rest at the cheapest layer that can prove each +shows one corner of it, so the rest is simulated at the cheapest tier that can prove each situation honestly. ## The four tiers @@ -18,23 +18,22 @@ situation honestly. | **3 β€” Mini-stack** | `tests/integration/mini-stack/` (real dashboard + docker-control vs fake daemons) | The control plane **end-to-end with real containers**: hold/release and reject/readmit actually stopping/starting `p2pool`/`xmrig-proxy`, driven deterministically | CI with Docker (`make test-mini-stack`) | | **4 β€” Live matrix** | `tests/integration/run.sh` against a real, synced box | What only reality proves: real merge-mining, prune/full DB size, Caddy TLS, Tor onions, HugePages, plus fault injection for real container health verdicts | Manual / release gate (`make test-integration`) | -Why this shape, and whether to use stubs: stubs already do most of the work. The dashboard has -~140 unit tests that drive the hard runtime states with mocked clients. More mocks for the same -logic would be duplication. What stubs can't prove is wiring: that the real clients parse real -daemon output (tier 2), that the dashboard's stop/start moves real containers (tier 3), and that -real daemons sync/merge-mine and real containers go unhealthy (tier 4). So the strategy is stubs -for logic, controllable fake daemons for the control-plane wiring, and the real box for the -irreducibly-real. Each situation is tested once, at the lowest tier that's honest. +Stubs do most of the work. The dashboard unit tests drive the hard runtime states with mocked +clients; more mocks for the same logic would duplicate them. What stubs can't prove is wiring: +that the real clients parse real daemon output (tier 2), that the dashboard's stop/start moves +real containers (tier 3), and that real daemons sync/merge-mine and real containers go unhealthy +(tier 4). So: stubs for logic, controllable fake daemons for the control-plane wiring, the real +box for the irreducibly-real. Each situation is tested once, at the lowest tier that is honest. -The fakes are the key enabler. Because the whole control plane is env-configurable -(`MONERO_RPC_URL`, `TARI_GRPC_ADDRESS`, `DOCKER_CONTROL_URL`, `NODE_DOWN_AFTER_SEC`, -`UPDATE_INTERVAL`, …), we point the real code at tiny controllable servers and drive the entire -state machine in seconds, in CI, with no chain and no test box. +The fakes are the enabler. The whole control plane is env-configurable (`MONERO_RPC_URL`, +`TARI_GRPC_ADDRESS`, `DOCKER_CONTROL_URL`, `NODE_DOWN_AFTER_SEC`, `UPDATE_INTERVAL`, …), so the +real code points at small controllable servers and drives the entire state machine in seconds, in +CI, with no chain and no test box. ## Scenario catalog -Every situation we care about, what triggers it, and the tier(s) that cover it. βœ… = covered -today; β–Ά = exercised by the live matrix / mini-stack when run. +Every situation, its trigger, and the tier(s) that cover it. βœ… = covered today; β–Ά = exercised by +the live matrix / mini-stack when run. ### A. Configuration permutations @@ -126,9 +125,9 @@ make test-integration ARGS="--host user@box --dir pithead --lifecycle --fault-in ## Production-readiness posture -What gates a merge vs. a release, the engineering standards every test holds to, and the gaps we -know about. The full enumerated coverage is in the generated [Test Inventory](test-inventory.md) -(kept honest by a CI drift check). +What gates a merge vs. a release, the standards every test holds to, and the known gaps. The full +enumerated coverage is in the generated [Test Inventory](test-inventory.md), kept current by a CI +drift check. ### What runs where @@ -150,7 +149,7 @@ pre-release gate (see [Releasing](releasing.md)) because it needs the real synce ### Engineering standards -Every scenario, at every tier, holds to the same discipline. +Every scenario, at every tier, holds to the same rules. - Deterministic, no sleep-and-hope. Wait on real readiness signals β€” container health, `pithead status`, dashboard sync %, miner-released β€” with timeouts. The only fixed sleeps are @@ -171,13 +170,12 @@ Every scenario, at every tier, holds to the same discipline. ### Flake policy Integration scenarios quarantine, never blind-retry. A scenario that fails intermittently is -marked and investigated, not wrapped in a retry loop that hides a real race. The waiters have -generous timeouts so a slow-but-correct stack passes while a genuinely broken one fails fast with -artifacts. +marked and investigated, not wrapped in a retry loop that hides a real race. The waiters have wide +timeouts so a slow-but-correct stack passes while a broken one fails fast with artifacts. -### Known gaps (honest) +### Known gaps -These are deliberately not yet covered and are the road to full production confidence. +Not yet covered. The road to full production confidence. - First green run on real hardware. βœ… Two of the three real-environment tiers are green: the live harness `--check` (tier 4 read path, 22/22 against a synced, mining box) and the fake-daemon diff --git a/docs/workers.md b/docs/workers.md index 6c9b98b..23fc4d3 100644 --- a/docs/workers.md +++ b/docs/workers.md @@ -1,20 +1,19 @@ # Connecting Miners -How to point miners at the stack. Every miner you own connects to one endpoint, and the stack routes -their combined hashrate: pool selection, payouts, and the P2Pool/XvB split are handled centrally. -Miners stay simple; all the coordination lives here. +How to point miners at the stack. Every miner connects to one endpoint; the stack handles pool +selection, payouts, and the P2Pool/XvB split centrally. The endpoint is the `xmrig-proxy` service on port `3333`. -> You do not put a wallet address in your miner config. Payouts are managed by the P2Pool service on -> the stack. Miners only need to know where the stack is. +> Do not put a wallet address in your miner config. The P2Pool service on the stack handles payouts. +> Miners only need to know where the stack is. --- ## Already have miners? Connect them If you already run [XMRig](https://github.com/xmrig/xmrig) (or any RandomX miner), point it at the -stack and you're done. Use the machine running the stack as the host, on port `3333`: +stack host on port `3333`: ```json { @@ -27,19 +26,18 @@ stack and you're done. Use the machine running the stack as the host, on port `3 } ``` -That's the whole pool config. Start the miner and it appears in the dashboard's Workers Alive table +That is the whole pool config. Start the miner; it appears in the dashboard's Workers Alive table within a few seconds. -- `user` is just a label for the rig. Use its hostname so you can tell workers apart on the - dashboard. (No wallet address; see above.) -- Point all your rigs at the same `YOUR_STACK_IP:3333`. The stack aggregates them; there's nothing - per-rig to configure beyond the label. +- `user` is a label for the rig. Use its hostname to tell workers apart on the dashboard. (No wallet + address; see above.) +- Point every rig at the same `YOUR_STACK_IP:3333`. The stack aggregates them; nothing per-rig to + configure beyond the label. - `YOUR_STACK_IP` is the stack host's IP or a DNS-resolvable hostname. For a stable address on a home LAN, set a DHCP reservation (or a static IP) for the stack host. -- Add a backup pool for automatic failover. List a second entry in `pools` (a public pool, or another - stack). If your Monero node goes down or is still syncing, the stack briefly stops accepting work so - your rigs fail over to the backup automatically, then switch back the moment it recovers. You never - sit idle on a stalled node. +- Add a backup pool for failover. List a second entry in `pools` (a public pool, or another stack). + If the Monero node goes down or is still syncing, the stack stops accepting work so rigs fail over + to the backup, then switch back when it recovers. ### Miner version & compatibility @@ -176,12 +174,12 @@ URL, status, and likely fix, so a misconfigured API reads differently from an of ## New to mining? Start with RigForge -If you don't have miners set up yet, or you want the best hashrate without hand-tuning, use +If you don't have miners set up yet, use [RigForge](https://github.com/p2pool-starter-stack/rigforge), the companion miner kit for this stack. -RigForge turns a fresh machine into a tuned worker in one command: it builds XMRig from source, -applies CPU- and kernel-level tuning (HugePages, MSR, NUMA), and runs it as a managed service. During -setup it asks for your stack's hostname and wires up the `3333` connection for you. +RigForge builds XMRig from source, applies CPU- and kernel-level tuning (HugePages, MSR, NUMA), and +runs it as a managed service. During setup it asks for your stack's hostname and configures the +`3333` connection. ```bash git clone https://github.com/p2pool-starter-stack/rigforge.git diff --git a/images/launch/README.md b/images/launch/README.md index 798647c..bc4f946 100644 --- a/images/launch/README.md +++ b/images/launch/README.md @@ -1,6 +1,6 @@ # Launch assets -Marketing/launch visuals for the Pithead dashboard (Issue #80). Static views ship in dark and light +Launch visuals for the Pithead dashboard (Issue #80). Static views ship in dark and light themes (`*-light.png`), so docs can serve a theme-adaptive ``. | Asset | Files | What |