SPEARMINT SPMTC

Spearmint/Articles/Solo mining with ckpool

Mining · setup guide

Solo mining with ckpool: a complete setup guide (any SHA-256 coin)

ckpool in solo mode turns your own full node into a Stratum server: every miner that connects gets work from your node, and whoever solves a block is paid the whole reward by the coinbase, directly to the address in their username. Here is the full setup, from node config to first accepted share.

By , Instant Access · Published 13 September 2026 · Updated 13 September 2026 · ~10 min read

01 Why solo, and what it costs you

Pooled mining exists to smooth variance. A pool with 5% of the network finds a block every twenty or so block-times and splits it, so each participant sees small, frequent payments instead of a rare large one. Solo mining gives that smoothing back. You get the entire block reward and every transaction fee in it, paid by the network itself in the coinbase transaction, with no pool fee and no intermediary holding anything for even a minute. In exchange, you wait — and the wait is random, so you may wait far longer than the average before the first block lands.

There are three reasons people accept that. The first is scale: if you control a meaningful share of a network's hashrate, the variance is already small and a pool fee is pure cost. The second is the network's size: on a young or small chain with a short block interval, a single modern ASIC can expect a block in hours rather than decades, which makes solo entirely practical. The third is principle: some miners would rather verify every rule themselves on their own node than trust a pool's accounting. ckpool's solo mode serves all three.

02 What you need

  • A fully synced full node for the coin you are mining — Bitcoin Core, or a fork such as Spearmint Core — on a Linux machine. Debian or Ubuntu is what ckpool's build instructions assume.
  • ckpool from its git repository. Con Kolivas's ckpool is the reference Stratum server used by many pools and the base for Spearmint's own pool software.
  • At least one SHA-256 miner that speaks Stratum v1, which is every ASIC made in the last decade. CPU mining works for testing and will never find a real block.
  • A coin address whose private key you control. In solo mode this address is your Stratum username and is where the block reward is paid.
  • A LAN where the miner can reach the ckpool machine's Stratum port. Nothing here needs to be reachable from the internet, and nothing should be.

03 Configure the node

ckpool talks to your node over JSON-RPC: getblocktemplate to build work, submitblock to broadcast a solution, and optionally a ZMQ socket to hear about new blocks immediately. The README's stated minimum is server, rpcuser and rpcpassword. Bind RPC to loopback so those credentials are reachable only from the same machine.

# bitcoin.conf (or spearmint.conf) — the parts ckpool needs server=1 rpcuser=ckpool rpcpassword=change-this-to-something-long-and-random rpcbind=127.0.0.1 rpcallowip=127.0.0.1 # optional but recommended: instant new-block notification for ckpool's zmqblock zmqpubhashblock=tcp://127.0.0.1:28332
Never expose RPC RPC with a username and password is full control of the node and, if the node has a wallet, of its keys. rpcbind=127.0.0.1 and rpcallowip=127.0.0.1 keep it on the machine. If ckpool must run on a different host, tunnel RPC over SSH or WireGuard rather than opening the port. Spearmint's own security notes repeat this because it is the mistake that ends mining operations.

Restart the node and confirm it answers. bitcoin-cli getblocktemplate '{"rules":["segwit"]}' should return a large JSON object with a coinbasevalue field; if it complains about not being synced, wait. A node that is still catching up will hand ckpool stale templates and every share will be wasted.

04 Build ckpool

The minimal build needs only a compiler and yasm. The full build adds ZMQ (for instant block notification), Cap'n Proto and libsodium, which the current codebase uses for Stratum V2 support. Solo mining over classic Stratum v1 works with either; take the full build if you want zmqblock.

# dependencies — full build sudo apt install build-essential yasm libzmq3-dev libcapnp-dev capnproto libsodium-dev # fetch and build git clone https://github.com/ckolivas/ckpool.git cd ckpool ./autogen.sh # required when building from git ./configure make # binaries land in src/ — install is optional ls src/ckpool src/ckproxy src/ckpmsg src/notifier

ckpool is the server. ckpmsg sends control messages to a running instance and is how you query its state. notifier is the small helper the node can call via -blocknotify if you prefer that to ZMQ.

05 A working ckpool.conf for solo

ckpool reads ckpool.conf from its working directory unless you pass -c. The file is JSON. The keys below are the ones that matter for solo mode, with the README's defaults noted so you know which lines you can leave out.

# ckpool.conf — solo mode against a local node { "btcd" : [ { "url" : "127.0.0.1:8332", "auth" : "ckpool", "pass" : "change-this-to-something-long-and-random", "notify" : true } ], "serverurl" : [ "0.0.0.0:3333" ], "mindiff" : 1, "startdiff" : 10000, "maxdiff" : 0, "zmqblock" : "tcp://127.0.0.1:28332", "blockpoll" : 100, "update_interval" : 30, "logdir" : "logs" }
Keys that matter in solo mode
KeyMeaningDefault
btcdArray of node connections: url, RPC auth and pass, and optional notify for notifier-based block detection. Mandatory in pool mode.localhost:8332, user/pass
serverurlAddress(es) the Stratum server binds to. Use a LAN address or 0.0.0.0 and firewall it.all interfaces, port 3333
mindiffFloor for vardiff. Leave at 1 for testing; raise it if a large farm floods the log with tiny shares.1
startdiffInitial difficulty handed to a new connection before vardiff settles.10000
maxdiffCeiling for vardiff; 0 means none.0
zmqblockZMQ endpoint to hear new blocks instantly, matching the node's zmqpubhashblock.tcp://127.0.0.1:28332
blockpollHow often, in milliseconds, to poll for a new block if not using ZMQ or the notifier.100
update_intervalSeconds between Stratum job updates, which is how often new transactions are folded into the template.30
btcaddressThe coinbase address for pool mode. Ignored in solo mode, because each miner's own username is the coinbase address.
btcsigOptional text placed in the coinbase — a tag, not a signature in the cryptographic sense.none
logdirWhere logs go, relative to the working directory.logs

The point of btcaddress being ignored is worth pausing on. In solo mode there is no pool address anywhere in the system. The template's coinbase is built per miner to pay the address in that miner's username, so a solved block pays its finder directly from the network. ckpool never takes custody of anything; there is nothing to take custody of.

06 Run it

# from the ckpool directory, solo mode, this config, moderately verbose ./src/ckpool -B -c ckpool.conf -l 6 # useful flags -B | --btcsolo solo mode: usernames must be valid addresses; 100% of a solved block goes to the solver -c CONFIG config file (default ckpool.conf) -l LOGLEVEL log verbosity, default 5, 7 is full debug -n NAME name this instance, so you can run more than one -k shut down a running instance with the same name -s SOCKDIR where the control sockets live (default /tmp) -H attempt a handover from a running instance, for restarts without dropping miners

On startup ckpool connects to each btcd entry, checks it is synced, fetches a template, and begins listening on serverurl. Leave it in the foreground the first time so you can watch the log; once it is stable, run it under systemd or in a tmux session with a lower log level.

07 Point your hardware at it

In your miner's web interface, add the ckpool machine as pool 1. The username is your address, optionally followed by a dot and a worker name so you can tell machines apart in the log. The password is ignored; x is the convention.

# ASIC pool settings URL: stratum+tcp://192.168.1.50:3333 Worker: bc1q…your-address….rig01 # or spmtc1… on Spearmint Password: x # cgminer command line, for a test rig or a USB stick miner cgminer -o stratum+tcp://192.168.1.50:3333 -u bc1q…your-address….rig01 -p x

ckpool validates the address with the node before accepting the login, which is why -B insists on a real address rather than an arbitrary name. A mistyped address is rejected at connection, not discovered after a block has paid the wrong person. On a fork with its own address format — Spearmint's bech32 addresses start spmtc1 — the fork's node does that validation, which is one of the small changes a ckpool fork has to carry.

08 Reading the logs

Within a minute of a miner connecting you should see three things in logs/ckpool.log: the connection and authorisation of the worker with its address, a stream of accepted shares as vardiff settles from startdiff toward whatever produces a share every few seconds, and periodic hashrate summaries per worker. Rejected shares at the start are normal while difficulty adjusts; a steady stream of rejects afterwards means the miner is on a stale job, usually a network or firmware issue.

The line you are waiting for is the block solve. ckpool logs the block hash, the height, and the fact that submitblock was accepted. Confirm it independently: bitcoin-cli getblock <hash> on your node should show the block with your address as the coinbase output. The reward is spendable after the coin's maturity period — 100 blocks on Bitcoin and, inherited from it, on Spearmint. Until then it shows as immature in any wallet that tracks the address.

ckpmsg lets you query the running instance without reading logs. Sending it a stats request to the Stratum socket returns current workers, hashrate, and share counts as JSON, which is handy for a dashboard.

09 How long until a block

The expected time between your blocks is the network hashrate divided by yours, multiplied by the block interval. Everything else — luck, orphan rate, difficulty drift — is a second-order correction to that one line.

# expected time to a block T = (network_hashrate / your_hashrate) × block_interval # examples — network figures are illustrative, not current readings 100 TH/s on a 1,000 EH/s network at 600 s blocks: (1,000,000,000 / 100) × 600 s ≈ 6 × 10⁹ s ≈ 190 years 100 TH/s on a 10 PH/s network at 30 s blocks: (10,000 / 100) × 30 s = 3,000 s = 50 minutes
Illustrative expected time to a block — 30-second block interval
Your hashrateNetwork 1 PH/sNetwork 10 PH/sNetwork 100 PH/s
10 TH/s50 min8.3 h3.5 days
100 TH/s5 min50 min8.3 h
1 PH/s30 s5 min50 min

Block finding is a Poisson process, so the average is not the typical experience. The probability of having found no block after one expected interval is about 37%; after three intervals it is still 5%. Plan for that before deciding solo is for you, and remember that on a network with per-block difficulty adjustment the network hashrate in the denominator can change by orders of magnitude between one hour and the next.

10 Common errors

  • ckpool exits immediately complaining it cannot connect to bitcoind. The url, auth or pass in btcd does not match the node's RPC settings, or RPC is bound to an address ckpool is not using. Test with curl or bitcoin-cli using the same credentials.
  • "Not synced" or templates with a stale height. The node is still catching up. Wait; do not mine against it.
  • Miner connects but is never authorised. The username is not a valid address for this chain. In solo mode there is no fallback; fix the address.
  • Every share rejected as stale. The miner is not receiving new jobs. Check that update_interval is sane, that nothing on the path is dropping long-lived TCP connections, and that the miner's firmware is not pointed at a backup pool at the same time.
  • Hashrate in the log is a fraction of the ASIC's rating. Usually vardiff still settling, or a share difficulty ceiling set too low by maxdiff. Give it ten minutes before concluding anything.
  • ZMQ never fires. The node's zmqpubhashblock endpoint and ckpool's zmqblock do not match, or the node was built without ZMQ. blockpoll will still catch new blocks within about 100 ms, so this is a small loss, not a failure.

11 How Spearmint uses this

Spearmint's own bring-up path is ckpool in solo mode against a local Spearmint Core node, exactly as above with the node's ports and address format changed. It is how the team's pre-launch mining is done, and it is what the run a node page recommends to anyone who would rather not use a pool at all. The public pool, when it opens, is a fork of the same ckpool codebase running in pool mode with PPLNS accounting on top — the build log tracks that work — but the solo path stays available and documented because a network is more robust when mining does not have to go through anyone.

12 Key takeaways

  • ckpool's -B solo mode builds work from your own node and pays a solved block's full reward to the address in the solver's username; no pool address exists and nothing is held.
  • The node needs server=1, rpcuser, rpcpassword, and RPC bound to 127.0.0.1. Never expose RPC.
  • Build with ./autogen.sh && ./configure && make; the binary is src/ckpool and needs no install.
  • A minimal ckpool.conf is a btcd entry and a serverurl; the README defaults cover the rest.
  • Expected time to a block is network hashrate ÷ your hashrate × block interval — and 37% of the time you will still be waiting after that.
  • Solo is practical on small, short-interval chains and for large operators on any chain; for a single machine on a large network it is a lottery.

13 Questions

What is ckpool solo mode?
Started with the -B or --btcsolo flag, ckpool builds block templates from your own node and requires every Stratum username to be a valid coin address. If a connected miner solves a block, 100% of that block's reward is paid by the coinbase to the address in that miner's username. There is no pool share accounting and nothing is held by anyone.
Do I need a full node to solo mine?
Yes. ckpool calls your node's getblocktemplate RPC to build work and submitblock to broadcast a solved block. The node must be fully synced, run with server=1, and expose RPC to ckpool on localhost only.
How long will it take to find a block solo?
On average, network hashrate divided by your hashrate, multiplied by the block interval. A single machine on a large network is measured in years or centuries; the same machine on a small chain with a short block time can be measured in hours. The wait is random, so half the time it is longer than the average.
Can I run ckpool on the same machine as my node?
Yes, and it is the simplest and safest layout: RPC stays on 127.0.0.1 and only the Stratum port needs to be reachable by your miners. Only the Stratum port should ever be exposed on your LAN, and nothing should be exposed to the internet.
Why does ckpool need rpcuser and rpcpassword rather than cookie auth?
ckpool's btcd configuration takes an explicit auth and pass pair for each node. Set rpcuser and rpcpassword in your node's configuration to match, and bind RPC to localhost so the credentials are never reachable from outside the machine.

Related on this site

Sources

  1. Con Kolivas, ckpool README — configuration keys, defaults, command-line flags, build steps, and the BTCSOLO description. github.com/ckolivas/ckpool
  2. Bitcoin Core, bitcoin.conf options and JSON-RPC reference (getblocktemplate, submitblock, ZMQ notifications). github.com/bitcoin/bitcoin
  3. Spearmint, build log — the ckpool-solo bring-up path and chain identity (port 9333, bech32 HRP spmtc).