Skip to content

Latest commit

 

History

History
226 lines (177 loc) · 19.9 KB

File metadata and controls

226 lines (177 loc) · 19.9 KB

Configuration

RigForge reads a small config.json in the repo root. It holds only what the script can't infer. The rest (CPU profile, thread count, HugePage sizing) is detected and applied for you.

On first run, if there's no config.json, setup creates a minimal one interactively (it asks for your pool URL and optional stratum password). For an .onion host it explains that you must install and run Tor yourself, defaults socks5 to 127.0.0.1:9050, and offers a validated interactive override (Enter or EOF keeps the default). LAN pools get no proxy prompt or key. You can also pre-create one from config.minimal.json.

Setup validates every field when it parses the config. A malformed pool URL, an out-of-range port, a bad hostname, a non-boolean flag, or an unsafe HOME_DIR stops setup with a message rather than producing a config the miner would reject.


Minimal config

The only required field is the pool. RigForge uses XMRig's native pools array, and a pool only needs its url (a host:port). Everything else falls back to a default:

{
    "pools": [
        { "url": "<YOUR_POOL_HOST>:3333" }
    ]
}

That's a complete config. Replace <YOUR_POOL_HOST>:3333 with your pool's host and port (Pithead's proxy listens on 3333). The interactive first-run setup writes this minimal shape for a LAN pool without a password.

Mining to a public pool like SupportXMR? A url alone isn't enough: public pools also need your Monero wallet as the pool user (and usually a TLS port). See Connecting to a public pool for a copy-paste example.

Two-tier config (like Pithead): keep config.json minimal and add only the keys you want to change. config.reference.json lists every key with its default. Copy in what you need; anything you omit keeps the default. The reference table below documents each key.


Configuration reference

Key naming: the three legacy keys (ACCESS_TOKEN, DONATION, HOME_DIR) keep their historical SCREAMING names forever — renaming them would break deployed fleets, and aliasing would double the documented surface. Every other documented key, and every future one, is lowercase snake_case, matching Pithead. (RIG_NAME is a reserved SCREAMING name seeded by the appliance image build; it is not read by parse_config today, so it isn't in the table below.)

Key Default What it does
pools (required) XMRig's native pools array — the pool(s) to mine to. Each entry needs a url (host:port); every other field falls back to a Pithead default. A pool's user is the rig's dashboard label (defaults to the hostname). List multiple entries for failover. See Pools.
— — Unknown keys warn and are ignored (with a did-you-mean for near-misses) — a typo'd key, especially ACCESS_TOKEN, must never silently not apply. Keys starting with _ are comments.
api "disabled" "enabled" serves the sister API: a second read-only port with XMRig's /1/summary+/2/summary passed through verbatim plus a namespaced rigforge object (tune state, RAPL watts, firmware/health probes, pinned versions), and /health + /tune endpoints. One tiny persistent stdlib server; a systemd timer refreshes its data every 15 s, so requests never touch the miner (see operations › sister API). Gated by ACCESS_TOKEN or any named ACCESS_TOKENS entry; Linux-only. control: "enabled" implies this (control is unobservable without the read feed) — but api is not itself in control's writable key set, so a Pithead stack can never turn it on remotely; it only ever comes on from local config.
api_port 8081 Sister API port (8080 is rejected — that's XMRig's own API).
api_bind "0.0.0.0" Sister API listen address.
control "disabled" "enabled" serves the writable control path (#236): a separate authenticated port that lets a Pithead stack apply config changes through RigForge, so config.json stays the source of truth (the producer for pithead Worker Inspect). Implies api: "enabled" — control has no read side of its own, so Pithead confirms an applied change through the sister API's enriched feed; no need to also set api by hand. Fail-closed: enabling it requires both ACCESS_TOKEN and api_allow_from — a writable API with no token or no pinned source is refused with a hard error. Only pools, DONATION, autotune, watchdog(+watchdog_interval_min), and max_temp_c are writable through it; anything else is rejected. A change touching only watchdog_interval_min and/or max_temp_c applies without restarting XMRig (#381) — every other key restarts it. The remote path additionally refuses to disable watchdog or to unset / out-of-band max_temp_c — a rig's thermal protection can only be removed by a local rigforge.sh apply on the box (#257). Each change is validated, the old config is snapshotted to config-backups/ first, and a change that doesn't come back live is rolled back. The receiver holds no privilege and stages off the request path, so writes never touch mining. Linux-only. See Operations › Control path.
control_port 8082 Control path port (rejects 8080 and the api_port).
control_bind "0.0.0.0" Control path listen address. Pair with api_allow_from (required) to pin who may write.
miner_user "" (root) Run the miner as this dedicated non-root system user (created at setup, nologin). RigForge applies the CPU's MSR preset root-side before start; on families without a known preset the ~10-15% MSR boost is skipped — which is why this ships opt-in. Lowering privilege changes nothing else: HugePages come from the boot reservation, tune/doctor/apply all keep working.
api_allow_from "" (off) Restrict the API port(s) — :8080, :8081 when the sister API is on, :8082 when the control path is on — to a single IPv4 or IPv6 address/CIDR (plus loopback), via an own nftables table (renders ip saddr or ip6 saddr per family). SSH and mining are never touched. For IPv6 to be reachable-and-scoped, set api_bind/control_bind to :: (the servers then bind dual-stack). Needs nft; Linux-only.
ACCESS_TOKEN "" (open) The master bearer token, and the only one XMRig itself carries. Unset leaves the read APIs open. When set, it is the token rendered into XMRig's own :8080 API, the one RigForge's own liveness/rollback probe uses when the control path restores pools after a failed apply, and an accepted bearer on :8081/:8082 like any ACCESS_TOKENS entry. Read-only :8081 also accepts its scoped HMAC-derived read bearer for Pithead 2.0 when the token is a randomly generated 32+ character value (openssl rand -hex 16). Short legacy tokens remain raw-client compatible but get no derived bearer. A stack that probes :8080 directly must hold this one — a named token cannot be honoured there, because XMRig takes exactly one http.access-token. See Pithead Integration.
ACCESS_TOKENS {} (none) Optional name → token map: one token per Pithead stack that consumes this rig, so rotating the bench's token never touches production's and a bench borrow never needs prod's credential (#516). Every entry is accepted on the read-only sister API (:8081) and the writable control path (:8082) exactly as ACCESS_TOKEN is — raw match on both, plus that entry's own scoped HMAC-derived read bearer on :8081 under the same 32+ ASCII character rule. Entries grant no access to XMRig's :8080 and are never used for the control path's pools restore; both stay ACCESS_TOKEN's. Names are yours (e.g. {"prod": "…", "bench": "…"}); values take the same characters ACCESS_TOKEN does (letters, digits, . _ - : @ +). Tokens are read once at service start, so revoking an entry means removing it and running sudo rigforge.sh apply. rigforge.sh doctor reports how many are configured and which one XMRig carries.
DONATION 1 XMRig donate level, an integer 0–100 (percent). Patched into the build (donate.h) and written to the generated config, so it must be a valid integer or setup fails fast. Lowering it below the level the current binary was compiled with needs a rebuild — XMRig clamps the config value to its compiled floor (and autosaves the clamped value), so apply alone cannot lower it. Raising it works with a plain apply.
HOME_DIR DYNAMIC_HOME Where worker files live. DYNAMIC_HOME puts them in data/worker inside the repo; set an absolute path to use <path>/worker instead.
autotune "disabled" Periodic live tuning, as a target: "disabled" (default) installs no timer; "performance" schedules a periodic tune for raw hashrate; "efficiency" schedules one for hashrate-per-watt (needs a power source, built-in RAPL or TUNE_POWER_CMD, else it falls back to performance with a warning). Legacy booleans still parse (true → performance, false → disabled). This key controls the schedule; to run one live pass by hand, use tune --now (or tune --now --long for a full all-knob sweep). See Operations › Live auto-tuning.
watchdog "disabled" "enabled" installs a systemd timer that health-checks the miner every watchdog_interval_min minutes and restarts it when it's wedged — process alive but two consecutive checks see 0 H/s or an unreachable API (the case Restart= can't catch). One bad check never restarts (it could be a restart-in-progress). Legacy booleans parse (true → enabled); a typo hard-errors rather than silently disabling recovery. Linux-only. See Operations › Watchdog.
watchdog_interval_min 5 Watchdog check cadence in minutes (1–1440).
max_temp_c "" (off) Optional thermal cutoff for the watchdog: above this °C the miner is stopped, and started again once the rig cools 5 °C below it (fixed hysteresis). Empty = no thermal logic. The sensor is /sys/class/thermal/thermal_zone0/temp when it exists, else the CPU hwmon (k10temp/coretemp) — and k10temp reports Tctl, a control temperature that runs high by design (a loaded EPYC reads ~90 °C Tctl in normal operation). Check the live reading before choosing a cutoff (THERMAL_ZONE overrides the path). Accepts 40–110.
hugepages_reserve_extra_mb 0 MB of HugePages to leave for the rest of the box when RigForge sizes its reservation — for co-locating a miner on a busy host (e.g. a Pithead stack, whose 2MB pages come from the same kernel pool). RigForge stays the sole writer of the reservation; this key just declares how much of it isn't the miner's. Added to both the boot reservation and the runtime pool. When the box's existing reservation already covers stack + miner, RigForge changes nothing and needs no reboot.
hugepages_pool_ceiling_mb 0 (no ceiling) A hard cap, in MB, on the 2MB HugePages pool RigForge will reserve — the opposite direction from hugepages_reserve_extra_mb, which adds to the computed requirement rather than bounding it. Set it on a RAM-constrained co-resident box: the runtime vm.nr_hugepages write is never grown past the ceiling, and neither is the hugepages= RigForge merges into the GRUB cmdline, so the pool does not come back up over the ceiling after a reboot (the grow-only runtime write could never bring it down again). An odd MB value floors to the 2MB page below (5121 → 5120 MB effective) — a cap rounds toward less memory, never more. The 1GB dataset reservation is a separate pool this key does not bound, so a ceiling below a box's 1GB reservation still leaves it holding more hugepage memory than the ceiling names.
threads "" (auto) A ceiling on the RandomX thread count — min(auto-detected, threads), never a raise. A co-located miner sets it (e.g. nproc-2) to leave the stack its cores. Both the generated cpu.rx and the HugePages sizing honour it, so the reservation matches the threads actually run.
add_to_path false When true, setup installs a rigforge command on your PATH (a symlink in /usr/local/bin) so you can run sudo rigforge <cmd> from any directory. Off by default. uninstall removes it.

How the generated XMRig config is built

You don't write XMRig's config. RigForge generates it in-script and writes it into the worker root as the live config.json the service runs from. There's no template file to keep in sync and no config key for it. Every run (re-runs included) rebuilds the config from four sources:

  1. Your config.json: the pools array (with user/pass/keepalive/tls and failover defaults filled in), the donate-level, and the http API block (bound to the LAN, read-only, open by default; set ACCESS_TOKEN for a bearer token). These are the keys documented in the reference table.
  2. Detected hardware: the per-CPU cpu/randomx tuning (thread count, asm, MSR, NUMA, HugePages). RigForge uses XMRig's own cache-aware auto-detection rather than a CPU-model table, so it stays correct for CPUs it's never seen. See Hardware Requirements.
  3. Static defaults: the fixed knobs every worker shares, emitted directly: autosave, randomx.mode: fast, randomx.init, opencl/cuda off, and the http port 8080.
  4. Tuned overrides (if present): if you've run tune, its winning knobs in tune-overrides.json are merged on top as the final step, so tuning wins for just the keys it sets and your config.json is never edited.

Because the config is rebuilt from these sources every time, editing the generated config.json by hand has no effect. Change your repo-root config.json (or tune) and re-run instead.

Don't put a wallet address in the worker user when using Pithead. The stack handles payouts centrally; the pool user is just a rig label (it defaults to the hostname so you can tell workers apart on the dashboard).


Pools (full control)

The pool target is XMRig's native pools array, passed straight through to XMRig, so you can use any field XMRig supports. Only url is required; every other field has a default, so you specify only what you care about:

Field Default if blank/omitted
url (required) — host:port (e.g. pool.supportxmr.com:443 or your-stack:3333). For an IPv6 literal, use the bracketed [2001:db8::1]:3333 form.
user the machine hostname. For Pithead this is the rig's dashboard label; for a public pool set it to your Monero wallet address (see below).
pass "x" — the stratum password / worker name. For an open Pithead stack the default works; if the operator enabled the stack's p2pool.stratum_password, set this to that secret or the proxy rejects the rig. See Pithead Integration › Stratum authentication.
keepalive true
tls false — set true when you connect on the pool's TLS/SSL port.
tls-fingerprint null (no pin) — the pool cert's SHA-256 as 64 hex chars. XMRig does no CA validation on stratum TLS, so the pin is the only server authentication; without it, TLS encrypts but doesn't authenticate. Requires "tls": true. See Pithead Integration › Stratum over TLS.
socks5 null (direct connection) — dial this pool through a SOCKS5 proxy at host:port, e.g. "127.0.0.1:9050" for a local Tor client. Same address rules as url. XMRig sends the pool's hostname to the proxy rather than resolving it first, so a v3 .onion stratum works with no extra setting. RigForge points the miner at a proxy; running one is yours to arrange.
enabled true

Two common setups follow; pick the one that matches where you're mining.

Connecting to a Pithead stack

Pithead handles pool selection, payouts, and the P2Pool/XvB split centrally, so the worker only needs the stack host and its proxy port (3333). The user is just a label for the dashboard, so don't put a wallet address here:

{
    "pools": [
        { "url": "stack.lan:3333", "user": "garage-rig" }
    ]
}

user is optional (it defaults to the hostname); set it to tell workers apart on the dashboard. See Pithead Integration for discovery and the API token.

Connecting to a public pool (SupportXMR, etc.)

A public pool pays you, so it needs your Monero wallet address as the login (user) and almost always a TLS port. RigForge builds stock upstream XMRig, so it speaks standard Stratum to any RandomX pool. Fill in the pool's endpoint and your wallet:

{
    "pools": [
        {
            "url": "pool.supportxmr.com:443",
            "user": "YOUR_MONERO_WALLET_ADDRESS",
            "pass": "garage-rig",
            "tls": true
        }
    ]
}
  • user is your Monero wallet address. This is who gets paid. Many pools also accept WALLET.workername here to label the rig in their dashboard.
  • pass is a worker name (or just "x"; most public pools ignore the password).
  • url + tls is the pool's stratum endpoint. Use the pool's TLS/SSL port (often :443 or :5555) with "tls": true; a plain, unencrypted port needs no tls. For a self-signed or internal cert, add tls-fingerprint to pin it. Your pool's Getting started / Connect page lists its exact host, ports, and whether it wants wallet or wallet.worker.

Save that as config.json, then sudo ./rigforge.sh apply (a fresh setup picks it up too).

The pool host must be an IP or DNS-resolvable hostname; allow its Stratum port through any firewall.

Backup pools (failover)

List multiple entries. XMRig tries them in order and fails over to the next if one is unreachable, handy for a primary stack with a public-pool fallback:

{
    "pools": [
        { "url": "stack.lan:3333" },
        { "url": "pool.supportxmr.com:443", "tls": true }
    ]
}

Here the worker mines to stack.lan:3333 and falls back to pool.supportxmr.com:443 over TLS, with user/pass/keepalive filled in for both.


Changing settings later

Edit config.json, then apply it in one step:

sudo ./rigforge.sh apply

apply re-reads config.json, regenerates the live XMRig config, and restarts the service, with no recompile. It's the path for a pools change, a new rig label, TLS, failover pools, and the like. (On macOS — deprecated, unsupported and untested since 2026-09-14 — there's no service, so apply regenerates the config and you restart the miner yourself; see Operations › Running on macOS.)

You can also re-run full setup (sudo ./rigforge.sh), but that re-provisions the whole worker (dependencies, build, kernel tuning, service). To avoid interrupting a running miner, a setup re-run on an already-built worker regenerates the config without restarting, so the new config only takes effect on the next restart. To apply an edit, use apply; it does the restart for you. Both are idempotent and skip the recompile when the pinned XMRig is already built.

NOTE: DONATION is also compiled into the XMRig binary at build time, so on an already-built worker neither apply nor a setup re-run changes it; both update only the runtime config. To re-patch the binary, force a rebuild: remove <WORKER_ROOT>/xmrig (or bump the pinned XMRig) and run setup, or run upgrade after bumping the pin.


See also