By Glenn Lyvers, 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.
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.
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.
| Key | Meaning | Default |
|---|---|---|
btcd | Array of node connections: url, RPC auth and pass, and optional notify for notifier-based block detection. Mandatory in pool mode. | localhost:8332, user/pass |
serverurl | Address(es) the Stratum server binds to. Use a LAN address or 0.0.0.0 and firewall it. | all interfaces, port 3333 |
mindiff | Floor for vardiff. Leave at 1 for testing; raise it if a large farm floods the log with tiny shares. | 1 |
startdiff | Initial difficulty handed to a new connection before vardiff settles. | 10000 |
maxdiff | Ceiling for vardiff; 0 means none. | 0 |
zmqblock | ZMQ endpoint to hear new blocks instantly, matching the node's zmqpubhashblock. | tcp://127.0.0.1:28332 |
blockpoll | How often, in milliseconds, to poll for a new block if not using ZMQ or the notifier. | 100 |
update_interval | Seconds between Stratum job updates, which is how often new transactions are folded into the template. | 30 |
btcaddress | The coinbase address for pool mode. Ignored in solo mode, because each miner's own username is the coinbase address. | — |
btcsig | Optional text placed in the coinbase — a tag, not a signature in the cryptographic sense. | none |
logdir | Where 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
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.
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.
| Your hashrate | Network 1 PH/s | Network 10 PH/s | Network 100 PH/s |
|---|---|---|---|
| 10 TH/s | 50 min | 8.3 h | 3.5 days |
| 100 TH/s | 5 min | 50 min | 8.3 h |
| 1 PH/s | 30 s | 5 min | 50 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,authorpassinbtcddoes not match the node's RPC settings, or RPC is bound to an address ckpool is not using. Test withcurlorbitcoin-cliusing 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_intervalis 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
zmqpubhashblockendpoint and ckpool'szmqblockdo not match, or the node was built without ZMQ.blockpollwill 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
-Bsolo 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 issrc/ckpooland needs no install. - A minimal
ckpool.confis abtcdentry and aserverurl; 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?
-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?
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?
Can I run ckpool on the same machine as my node?
Why does ckpool need rpcuser and rpcpassword rather than cookie auth?
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
- Con Kolivas, ckpool README — configuration keys, defaults, command-line flags, build steps, and the BTCSOLO description. github.com/ckolivas/ckpool
- Bitcoin Core, bitcoin.conf options and JSON-RPC reference (
getblocktemplate,submitblock, ZMQ notifications). github.com/bitcoin/bitcoin - Spearmint, build log — the ckpool-solo bring-up path and chain identity (port 9333, bech32 HRP
spmtc).