This is the Miningcore distribution maintained for BTCPool.co.uk
SOLO mining service. The source repository is hosted by NINJAK1DD, and the dev branch is its
primary integration branch. It builds on the
upstream Miningcore project and retains credit to
the original authors and contributors.
Production status: the software targets the supported .NET 10 LTS runtime, but production deployment still requires the operational controls below. Read Production operation and the live mainnet validation record before using real funds.
- High-performance asynchronous Stratum servers.
- Multiple pools and currencies in one cluster; see the bundled coin definitions and the Scrypt definition provenance.
- Native proof-of-work validation with fixed difficulty and variable difficulty (vardiff).
- SOLO, PPLNS and PROP payout schemes, plus transactional Bitcoin-family PPS accounting.
- Bitcoin direct-coinbase SOLO is enabled by default: when a miner finds a Bitcoin block, the block pays that miner directly and pays the pool only its configured fee or donation. Miningcore does not hold the miner's block reward first. Canonical BTC coinbases also use the BIP 54-forward-compatible shape and list payment outputs before the witness commitment.
- PostgreSQL-backed shares, blocks, balances, statistics and payment processing.
- Fail-closed share accounting with bounded queues, an emergency recovery journal and queue metrics.
- Protected payout ownership and reconciliation for interrupted or uncertain wallet submissions.
- Cluster-wide, exclusive Stratum listener reservation with address-aware safe port reuse.
- Share relays for advanced distributed pool deployments.
- REST API and WebSocket notifications, with bearer-authenticated, route-isolated administration and dedicated Prometheus listeners.
- Typed public API projections that keep wallet credentials and listener secrets out of responses.
- Integrated banning, TLS options, native log rotation and administrative notifications.
- Litecoin parent-chain and Dogecoin AuxPoW merged mining with independently selected SOLO, PPS, PROP or PPLNS accounting per pool.
- Versioned Ubuntu release archives, non-root containers and source-build paths.
This path installs the verified prebuilt release on a new Ubuntu 26.04 x64 host, creates PostgreSQL, prepares the configuration, and runs Miningcore under systemd. Run each block only after the preceding check succeeds. Ubuntu 22.04 uses its separately built compatibility archive and different runtime packages; Ubuntu 24.04 is a source-build target. Use the release guide for those paths or for an upgrade/rollback.
Important
This quick start pins the v0.3.0 stable release. To install another published version, select it
from the releases page and substitute that tag
in every command below. Release candidates should be tested on regtest or a controlled staging
pool before they are trusted with real funds.
. /etc/os-release
printf 'OS=%s %s\nARCH=%s\n' "$ID" "$VERSION_ID" "$(uname -m)"Continue with this quick path only when it prints OS=ubuntu 26.04 and ARCH=x86_64. Then install
the framework, native runtime providers, PostgreSQL and download tools:
sudo apt-get update
sudo apt-get install -y \
aspnetcore-runtime-10.0 \
ca-certificates \
curl \
libboost-locale1.90.0 \
libboost-regex1.90.0 \
libboost-serialization1.90.0 \
libgmp10 \
libsodium23 \
libzmq3-dev \
openssl \
postgresql
sudo systemctl enable --now postgresql
sudo systemctl is-active postgresqlSelect the release and download it into private temporary storage:
export MININGCORE_VERSION=v0.3.0
export MININGCORE_UBUNTU=26.04
MININGCORE_QUICKSTART_READY=
download_dir="$(mktemp -d "${TMPDIR:-/tmp}/miningcore-release.XXXXXXXX")"
archive_name="miningcore-${MININGCORE_VERSION}-linux-x64-ubuntu-${MININGCORE_UBUNTU}.tar.gz"
release_url="https://github.com/NINJAK1DD/miningcore/releases/download/${MININGCORE_VERSION}"
curl --fail --location --output "$download_dir/$archive_name" \
"$release_url/$archive_name"
curl --fail --location --output "$download_dir/SHA256SUMS" \
"$release_url/SHA256SUMS"
if (cd "$download_dir" && \
sha256sum --ignore-missing --check --strict SHA256SUMS); then
export MININGCORE_QUICKSTART_READY=1
echo "READY: $archive_name is verified"
else
echo "STOP: release download or checksum verification failed" >&2
fiDo not continue unless the checksum command reports the selected archive as OK. If the GitHub CLI
is installed, also verify the release provenance:
if [ "${MININGCORE_QUICKSTART_READY:-}" = 1 ]; then
gh attestation verify "$download_dir/$archive_name" --repo NINJAK1DD/miningcore
else
echo "STOP: no release archive passed checksum verification" >&2
fiMININGCORE_INSTALL_READY=
if [ "${MININGCORE_QUICKSTART_READY:-}" = 1 ]; then
release_dir="/opt/miningcore-${MININGCORE_VERSION}-linux-x64-ubuntu-${MININGCORE_UBUNTU}"
install_miningcore_release() {
{ id -u miningcore >/dev/null 2>&1 ||
sudo useradd --system --home-dir /var/lib/miningcore \
--shell /usr/sbin/nologin miningcore; } || return
sudo mkdir -p /opt || return
sudo tar -xzf "$download_dir/$archive_name" -C /opt || return
test -d "$release_dir" || return
sudo install -d -m 0750 -o root -g miningcore /etc/miningcore || return
sudo install -d -m 0750 -o miningcore -g miningcore \
/var/lib/miningcore /var/log/miningcore || return
if [ ! -e /etc/miningcore/config.json ]; then
sudo install -m 0640 -o root -g miningcore \
"$release_dir/config.example.json" /etc/miningcore/config.json || return
else
echo "Keeping existing /etc/miningcore/config.json"
fi
cat "$release_dir/BUILD-INFO" || return
LD_LIBRARY_PATH="$release_dir" "$release_dir/Miningcore" --version || return
sudo ln -sfnT "$release_dir" /opt/miningcore || return
}
if install_miningcore_release; then
MININGCORE_QUICKSTART_READY=
export MININGCORE_INSTALL_READY=1
echo "READY: installed $release_dir and updated /opt/miningcore"
else
echo "STOP: installation failed; /opt/miningcore was not changed" >&2
fi
else
echo "STOP: no verified release archive is available to install" >&2
fiThe version output must match the selected tag and include its source commit. Keep
/opt/miningcore as the stable symlink; future upgrades install another immutable versioned
directory before changing that link. Continue only after the block prints READY and exports
MININGCORE_INSTALL_READY=1; the verified-download latch is consumed after a successful install.
Create a dedicated role without putting its password on the command line:
MININGCORE_DATABASE_READY=
role_exists=
database_exists=
if role_exists="$(sudo -u postgres psql -X -A -t -v ON_ERROR_STOP=1 \
-d postgres -c "SELECT 1 FROM pg_roles WHERE rolname = 'miningcore';")" &&
database_exists="$(sudo -u postgres psql -X -A -t -v ON_ERROR_STOP=1 \
-d postgres -c "SELECT 1 FROM pg_database WHERE datname = 'miningcore';")"; then
if [ "$role_exists" = 1 ] || [ "$database_exists" = 1 ]; then
echo "STOP: the miningcore role or database already exists; use the upgrade runbook" >&2
elif sudo -u postgres createuser --pwprompt miningcore &&
sudo -u postgres createdb --owner=miningcore miningcore &&
sudo -u postgres psql --single-transaction -v ON_ERROR_STOP=1 \
-d miningcore -f /opt/miningcore/migrations/createdb.sql &&
psql -h 127.0.0.1 -U miningcore -d miningcore \
-c 'SELECT current_database(), current_user;'; then
export MININGCORE_DATABASE_READY=1
echo "READY: created and verified the miningcore database"
else
echo "STOP: database provisioning failed; inspect PostgreSQL before retrying" >&2
fi
else
echo "STOP: unable to inspect existing PostgreSQL roles and databases" >&2
fiOn a successful fresh provision, the verification command prompts for the new password, must report
database/user miningcore, and the block exports MININGCORE_DATABASE_READY=1. Existing database
operators should stop here and follow the
upgrade and migration runbook instead of running
the new-database schema over live data.
The installed config.example.json is the fully annotated reference. Smaller reviewed pool,
multi-coin, merged-mining and relay files are under /opt/miningcore/examples/; copy one over the
starter only when it matches the intended topology.
Skip this subsection if the configuration does not run Bitcoin SOLO. In v0.3.0, a canonical
Bitcoin pool using payoutScheme: "SOLO" defaults to direct settlement: the block pays the address
from the authorized miner username and pays each positive pool fee/donation recipient separately.
Miningcore does not receive and hold the miner's reward first. The mode requires the matching
direct-settlement database schema.
If you deliberately substituted the older v0.2.1 release in this quick start, skip this entire
subsection: that binary does not implement soloCoinbasePayout. Upgrade the binary and database
before relying on the v0.3.0 default. Only a fresh database created from v0.3.0-rc.1 or later has
the required schema from createdb.sql. For a database created by v0.2.1 or earlier—or any pre-PR
#135 build—explicitly set soloCoinbasePayout: false until the verified candidate migration has
completed; use the direct-SOLO database migration,
not createdb.sql and not a migration beneath the old /opt/miningcore symlink.
The guarded command blocks in this section require an account for which sudo -v succeeds. If a
command-specific sudoers policy intentionally denies general credential validation, have an
administrator perform the equivalent protected-file steps instead of weakening these checks.
For a new Bitcoin SOLO pool, install the reviewed
bitcoin_direct_solo_pool.json contract before editing:
direct_solo_source=/opt/miningcore/examples/bitcoin_direct_solo_pool.json
direct_solo_backup=
if sudo -v &&
sudo test -f "$direct_solo_source" &&
sudo test -f /etc/miningcore/config.json &&
sudo test ! -L /etc/miningcore/config.json &&
direct_solo_backup="$(sudo mktemp \
/etc/miningcore/config.json.before-direct-solo.XXXXXXXX)" &&
sudo cp --preserve=mode,ownership,timestamps \
/etc/miningcore/config.json "$direct_solo_backup" &&
sudo install -m 0640 -o root -g miningcore \
"$direct_solo_source" /etc/miningcore/config.json; then
echo "READY: installed the direct-SOLO example; previous config: $direct_solo_backup"
else
echo "STOP: direct-SOLO example installation failed; backup: ${direct_solo_backup:-not created}" >&2
false
fiAfter choosing this direct-SOLO example, continue only after this block prints READY. Keep the
reported backup until the commissioned configuration and rollback plan have been verified.
While editing below, keep both cluster- and pool-level payment processing enabled, retain
payoutScheme: "SOLO", replace the pool wallet, daemon credentials and positive recipient address,
and explicitly set soloCoinbasePayout: true. Miners must authorize with a valid network-matching
BITCOIN_ADDRESS.worker username. Complete the direct-SOLO guide,
including its regtest/preflight procedure, before admitting production miners. The default applies
only to canonical Bitcoin SOLO; every other coin and payout scheme remains unchanged.
After choosing the configuration, edit the protected file:
sudoedit /etc/miningcore/config.jsonBefore continuing:
- replace every active placeholder marker (
CHANGE_MEorREPLACE_WITH_) in wallet, RPC, PostgreSQL, SMTP, TLS and licence values; - use the PostgreSQL password created above and keep daemon/wallet RPC listeners private;
- remove unused pools or leave them explicitly disabled;
- preserve a non-null
paymentProcessingobject on every pool; - use unique pool IDs and Stratum ports, and create one payout wallet per enabled coin;
- set
logging.logBaseDirectoryto/var/log/miningcore; - set
shareRecoveryFileto/var/lib/miningcore/recovered-shares.txtandshareRecoveryStateDirectoryto/var/lib/miningcore; and - keep direct examples
SOLOunless the PPS operator checklist is complete.
After choosing an example and completing any optional direct-SOLO changes, run this final
fail-closed check. Continue only when it prints READY; a placeholder match or an inspection error
returns a nonzero status:
quickstart_placeholder_status=0
if sudo -v &&
sudo test -f /etc/miningcore/config.json &&
sudo test -r /etc/miningcore/config.json &&
sudo test ! -L /etc/miningcore/config.json; then
sudo awk '
/^[[:space:]]*\/\// { next }
/CHANGE_ME|REPLACE_WITH_/ { print NR ":" $0; found = 1 }
END { exit found ? 0 : 3 }
' /etc/miningcore/config.json || quickstart_placeholder_status=$?
case "$quickstart_placeholder_status" in
0) echo 'STOP: replace every active placeholder before starting Miningcore' >&2; false ;;
3) echo 'READY: no active placeholders remain' ;;
*) echo 'STOP: could not inspect /etc/miningcore/config.json' >&2; false ;;
esac
else
echo 'STOP: could not inspect /etc/miningcore/config.json' >&2
false
fiMiningcore does not install or manage the full nodes and payout wallets named by pools[].daemons.
Install each daemon from its authoritative project, verify its release, bind RPC to a private
interface, use a unique strong RPC credential, and allow the node to synchronize fully. Create the
pool payout wallet, encrypt and back it up, and test the documented restore procedure away from
production. Do not expose daemon RPC or wallet RPC to the internet.
Coin-specific RPC, wallet and extension requirements vary. Start with the chosen file in the
example index, then check the matching definition in
the installed /opt/miningcore/coins.json file (repository
source) and the daemon's pinned/released documentation. Miningcore must
not be started until every enabled pool's daemon and wallet endpoint is reachable using the
credentials in /etc/miningcore/config.json.
Skip this for a first or small pool. List partitioning is an advanced multipool optimization. On a new, still-empty database, it may be enabled before the first Miningcore start; on any database that already contains shares, use the complete backup/restore procedure in Advanced share-table partitioning.
The appendix deletes and rebuilds shares, so first preserve even the empty baseline:
umask 077
MININGCORE_PARTITION_READY=
partition_backup="$HOME/miningcore-before-partition.dump"
share_count=
partitioned_share_table_count=
if sudo -u postgres pg_dump -Fc -d miningcore > "$partition_backup" &&
pg_restore --list "$partition_backup" > /dev/null &&
share_count="$(sudo -u postgres psql -X -A -t -v ON_ERROR_STOP=1 \
-d miningcore -c 'SELECT count(*) FROM public.shares;')" &&
partitioned_share_table_count="$(sudo -u postgres psql -X -A -t \
-v ON_ERROR_STOP=1 -d miningcore \
-c "SELECT count(*) FROM pg_partitioned_table WHERE partrelid = \
'public.shares'::regclass;")"; then
if [ "$share_count" != 0 ]; then
echo "STOP: shares is not empty; use the full partition migration runbook" >&2
elif [ "$partitioned_share_table_count" != 0 ]; then
echo "STOP: shares is already partitioned; keep its current layout or use the full" \
"partition migration runbook" >&2
elif sudo -u postgres psql -v ON_ERROR_STOP=1 -d miningcore \
-f /opt/miningcore/migrations/createdb_postgresql_11_appendix.sql; then
export MININGCORE_PARTITION_READY=1
echo "READY: rebuilt the empty shares table as a partitioned table"
else
echo "STOP: partition appendix failed; restore or investigate before continuing" >&2
fi
else
echo "STOP: backup or shares-table inspection failed; appendix not run" >&2
fiContinue with partition creation only after the block prints READY and exports
MININGCORE_PARTITION_READY=1. Any backup, validation, table-inspection or appendix failure leaves
that latch empty and must be investigated before retrying. Rerunning this conversion against an
already partitioned shares table is refused so its existing partition layout remains intact.
Create one partition for every pool ID that the configuration can record. Replace the example table
name and value; the value must exactly match pools[].id:
sudo -u postgres psql -v ON_ERROR_STOP=1 -d miningcoreSET ROLE miningcore;
CREATE TABLE public.shares_bitcoin_solo
PARTITION OF public.shares
FOR VALUES IN ('bitcoin-solo');
RESET ROLE;
\qRepeat the CREATE TABLE statement for each pool, including an auxiliary pool whose direct Stratum
listener is disabled. Miningcore fails startup when a required partition is missing.
Generate the administrative API token outside config.json, protect it, then install the supplied
unit:
sudo install -m 0600 -o root -g root /dev/null \
/etc/miningcore/miningcore.env
token="$(openssl rand -hex 32)"
printf 'MININGCORE_ADMIN_API_TOKEN=%s\n' "$token" |
sudo tee /etc/miningcore/miningcore.env >/dev/null
unset token
sudo cp /opt/miningcore/systemd/miningcore.service \
/etc/systemd/system/miningcore.service
sudo systemctl daemon-reloadBefore enabling Miningcore with a local PostgreSQL database, configure persistent PostgreSQL startup/shutdown ordering. The v0.3.0 archives predate the helper: for this pinned quick start, follow the guide's manual setup. Archives from the release containing this change onward include the helper; for those releases, run the following after installing the unit and before enabling it:
sudo /opt/miningcore/systemd/configure-postgresql-ordering.shResolve any error or ambiguous cluster selection before continuing. Confirm the selected cluster
serves Miningcore's database. Once a unit is selected, use --dry-run to inspect current dependencies;
for reviewed intentional extras such as an exporter, see the ordering guide's exact-name
--allow-remaining UNIT option. Remove obsolete cluster references instead of acknowledging them.
Remote-database deployments should follow the guide's remote setup
and removal guidance instead. Rerun the helper whenever the PostgreSQL major version or cluster unit
name changes. For v0.3.0, update the manual drop-in and reload systemd after such changes.
After the applicable ordering setup and verification succeed, enable Miningcore:
sudo systemctl enable --now miningcore
sudo systemctl status miningcore --no-pager -lThe unit runs as the unprivileged miningcore account, creates persistent state/log directories,
allows Miningcore's bounded clean shutdown to finish, and prevents an unsafe automatic restart
after dual persistence failure (exit status 74).
AutoMapper 16 is dual-licensed under RPL-1.5 or Lucky Penny commercial terms, including a free
Community tier for qualifying users. Determine and document the applicable path for your deployment;
if that path provides a key, configure it now in a separate root-only environment file and systemd
drop-in. Do not place the key in config.json, the packaged unit, shell history or source control.
Obtain a key through the official
AutoMapper licensing and pricing page and
Lucky Penny registration, then follow the
Lucky Penny licence-key guide for choosing the correct environment
variable, secure installation, validation, rotation and Docker instructions. That guide helps you
configure a key; it does not determine which licence terms apply to your deployment.
Before starting a remotely hosted pool, configure the provider firewall and host firewall without locking out the administration path. Permit only the intended Stratum/TLS and public API ports. Keep PostgreSQL, daemon/wallet RPC, the administrative API and metrics private or explicitly allow-listed; place public HTTP traffic behind the documented TLS reverse proxy.
sudo journalctl -u miningcore --since '10 minutes ago' --no-pager
sudo ss -ltnp
curl --fail --max-time 5 http://127.0.0.1:4000/api/health-check
curl --fail --max-time 5 http://127.0.0.1:4000/api/pools
curl --fail --max-time 5 http://127.0.0.1:4002/metrics --output /dev/null
sudo -u postgres psql -d miningcore -c \
'SELECT poolid, count(*) FROM shares GROUP BY poolid ORDER BY poolid;'Use the configured ports if they differ. Read the full startup log and require every intended daemon to be synchronized, every wallet to be backed up and usable, and every intended pool to be online. Connect one representative miner, confirm accepted shares reach PostgreSQL, then test a clean stop and start before opening the service to production traffic. Continue with Production operation for firewall, TLS, reverse-proxy, backup, monitoring and recovery requirements.
| I want to… | Read… |
|---|---|
| Install, upgrade or roll back a release | Release guide |
| Choose a ready-to-edit pool or relay topology | Example configuration index |
| Configure pools, logging and recovery storage | Configuration guide |
| Operate and monitor a production service | Operator handbook |
| Diagnose a startup, mining, payout or storage problem | Troubleshooting guide |
| Set up, back up or recover PostgreSQL | Database and recovery guide |
| Use advanced share-table partitioning | Partitioning runbook |
| Back up and restore payout wallets | Wallet backup runbook |
| Use the API, WebSocket events or metrics | API guide |
| Secure and call administrative routes | Administrative API security |
| Review AutoMapper licensing or configure a Lucky Penny key | Lucky Penny licence-key guide |
| Deploy distributed Stratum/recorder roles | Share-relay guide |
| Enable direct Bitcoin-family PPS | PPS operator guide |
| Pay Bitcoin SOLO miners directly in the coinbase | Bitcoin direct-SOLO guide |
| Prepare a v0.2.1-or-earlier/pre-PR #135 database for default direct-coinbase SOLO | Direct-SOLO database migration |
| Validate a new deployment before miners | Operator preflight |
| Migrate an existing .NET 6 deployment | .NET 6 to .NET 10 migration guide |
| Enable Litecoin–Dogecoin merged mining | Merged-mining guide |
| Configure and commission DigiByte direct mining | DigiByte guide |
| Evaluate the separate Bitcoin BLAKE2b hard-fork chain | BLAKE2b operator guide and compatibility boundary |
| Review newly added Scrypt daemon contracts | Scrypt coin definitions |
| Review Bitcoin-family BIP310 mask safety | Version rolling |
The complete documentation index also links dependency, licensing and validation references.
Canonical Bitcoin SOLO pools use direct coinbase settlement by default. Each authorized
address.worker receives destination-specific SV1 work whose coinbase pays the miner directly and
places each positive pool fee/donation in a separate output, so Miningcore does not custody the
miner's block reward first. BTC-only, SOLO, database, topology and address contracts fail closed
before work begins. Existing databases must apply the additive migration before accepting the new
default, or explicitly set soloCoinbasePayout: false to retain custodial settlement. Complete the
Bitcoin direct-SOLO guide before using the
copy-first example. BIP 54-forward-compatible
coinbase shape is independently enabled by default for every canonical Bitcoin pool; the guide
documents the temporary bip54Coinbase: false full-shape compatibility fallback.
PPS credits each valid share when its PostgreSQL accounting transaction commits. A later confirmed, stale or orphaned block does not add or reverse that liability, so the operator—not the miner—owns block variance and must maintain a monitored liquidity reserve. Support is currently restricted to audited Bitcoin-family pools, including either chain in the integrated Litecoin/Dogecoin topology.
Existing databases need the candidate-idempotency, payout-ownership and share-accounting migrations
before PPS is enabled. The reviewed direct examples remain SOLO by default so copying one cannot
silently opt the operator into a financial liability. Follow the PPS operator guide
for the configuration change, commissioning checks, exact ledger, monitoring and recovery boundary.
Merged mining exposes the Litecoin Stratum endpoint to miners and submits qualifying copies of the
same Scrypt proof to Dogecoin. Both pools must be enabled and have their own payout wallet address.
Each independently selects SOLO, PPS, PROP or PPLNS; mixed combinations are supported.
Non-SOLO Dogecoin accounting requires requireAuxAddress: true. PPS transfers block variance and
liquidity risk to the operator, so read the reserve and migration guidance before enabling it. PPS
statistical shares default to seven-day retention and exactly-once accounting receipts to a 30-day
replay horizon; size or archive them using the database guide.
The Litecoin pool points to the Dogecoin pool with this block:
"mergedMining": {
"enabled": true,
"auxPoolId": "doge-solo",
"addressParameter": "doge",
"requireAuxAddress": true,
"auxiliaryTemplatePollTimeoutMs": 500
}Miners connect to the Litecoin Stratum port. Put the Litecoin payout address in the username and the Dogecoin payout address in the password:
Username: YOUR_LTC_ADDRESS.rig01
Password: doge=YOUR_DOGE_ADDRESS
Example ccminer command without a requested starting difficulty:
ccminer -a scrypt -o stratum+tcp://pool.example:3032 -u YOUR_LTC_ADDRESS.rig01 -p "doge=YOUR_DOGE_ADDRESS"A concrete syntax example using valid-format documentation addresses is shown below. These addresses have no usable private key and must never be used to receive mining rewards:
ccminer -a scrypt -o stratum+tcp://pool.example:3032 -u Lbr1z8RSnJSTdxyrZUeSSLSJMVLbxT9KHZ.rig01 -p "doge=DMmAGB4G146gvAUJ7vehi5Y92Qhd7TSMS2"To request difficulty 65536, combine the ordinary d= password option with the DOGE address:
ccminer -a scrypt -o stratum+tcp://pool.example:3032 -u YOUR_LTC_ADDRESS.rig01 -p "d=65536;doge=YOUR_DOGE_ADDRESS"Do not put the DOGE address in the username or connect merged miners to the auxiliary DOGE port. The pool validates both addresses before authorising the worker. See the commented configuration example and read the complete merged-mining guide before enabling it.
Download a release archive and SHA256SUMS from the
releases page, verify it, and follow the
prebuilt installation and upgrade guide. The binary is framework-dependent and
therefore still needs the documented .NET 10 and native runtime dependencies. No Windows or generic
cross-distribution binary compatibility is claimed. Use the primary Ubuntu 26.04 archive on 26.04;
use the separately built compatibility archive on 22.04. Ubuntu 24.04 operators should build from
source rather than use either distribution-specific archive.
Already running Miningcore on .NET 6? Read the .NET 6 to .NET 10 operator migration guide before changing the runtime, application files, service or database. It covers release archives, source deployments and containers, including rollback planning and preserving an existing configuration.
Run the script matching the installed operating system from the repository root. The script installs
the native build dependencies and .NET SDK, then publishes Miningcore into build/.
| Operating system | Command | Guidance |
|---|---|---|
| Debian 12 | ./build-debian-12.sh |
Recommended script path |
| Ubuntu 26.04 LTS x64 | ./build-ubuntu-26.04.sh |
Primary release/source target |
| Ubuntu 24.04 LTS x64 | ./build-ubuntu-24.04.sh |
Tested source-build compatibility target |
| Ubuntu 22.04 LTS x64 | ./build-ubuntu-22.04.sh |
Tested source and compatibility archive |
For example:
chmod +x build-debian-12.sh
./build-debian-12.sh
ls build/MiningcoreThese scripts install the .NET 10 SDK and publish the net10.0 application. Ubuntu 24.04 and 26.04
use Canonical's native .NET 10 packages without Microsoft's APT feed or the Ubuntu 22.04
dotnet/backports PPA. GitHub Actions
(workflow source) is the authoritative automated build-and-test path.
Interactive builds retain .NET's concise progress and elapsed-time display; a separate private
MSBuild log is audited and removed when the helper exits, while warnings remain visible and fatal.
The standard MSBUILDTERMINALLOGGER=off environment setting remains available for accessibility,
terminal compatibility and log-processing requirements.
Windows is supported for development and testing, not recommended for hosting a production pool.
- Install the .NET 10 SDK.
- Install Visual Studio Build Tools with the Desktop development with C++ workload and the v143 toolset. Windows builds compile the pinned Odocrypt runtime from source and fail closed when this toolchain is unavailable.
- Clone the repository and open Miningcore.sln, or run:
build-windows.batThe published files are written to build.
For managed-only development on a machine without the C++ workload, dotnet build and unrelated
tests may use -p:BuildOdoCryptWindows=false. That development-only opt-out omits Odocrypt from the
output: Odocrypt tests and runtime use will fail, and Windows publish always requires the verified
source build. For local toolchain-compatibility testing, an installed alternative can be selected
with MININGCORE_WINDOWS_PLATFORM_TOOLSET; setting it forces a native rebuild so the selected
toolset is actually exercised. Release CI remains pinned to v143.
Install Docker Engine for your Linux distribution and confirm it works:
sudo docker run --rm hello-world
MININGCORE_VERSION=v0.3.0 # Replace with the release you selected.
sudo docker pull ghcr.io/ninjak1dd/miningcore:${MININGCORE_VERSION}Pin a published version rather than copying the example version indefinitely. Copy and edit the configuration, then run the image. This example uses a fixed Docker bridge gateway, publishes the public API, binds the admin and metrics ports to host loopback, and publishes the merged-mining LTC Stratum port. Publish every additional port used by your configuration:
MININGCORE_VERSION=v0.3.0 # Replace with the release you selected.
sudo mkdir -p /etc/miningcore /var/lib/miningcore
sudo curl -fL \
https://raw.githubusercontent.com/NINJAK1DD/miningcore/${MININGCORE_VERSION}/config.example.json \
-o /etc/miningcore/config.json
sudo chown root:10001 /etc/miningcore/config.json
sudo chmod 0640 /etc/miningcore/config.json
sudo install -m 0600 -o root -g root /dev/null \
/etc/miningcore/miningcore.env
token="$(openssl rand -hex 32)"
printf 'MININGCORE_ADMIN_API_TOKEN=%s\n' "$token" |
sudo tee /etc/miningcore/miningcore.env >/dev/null
unset token
sudo chown 10001:10001 /var/lib/miningcore
sudo docker network create --driver bridge \
--subnet 172.30.56.0/24 --gateway 172.30.56.1 miningcore
sudoedit /etc/miningcore/config.jsonThe administrative token must remain a 64-character hexadecimal value; the openssl command above
generates the required format.
In the configuration, replace the container-local loopback whitelist entries for the two published protected ports with the fixed bridge gateway:
"adminIpWhitelist": [ "172.30.56.1" ],
"metricsIpWhitelist": [ "172.30.56.1" ]If that subnet overlaps the host network, choose another unused private subnet and use its selected gateway in both whitelist entries.
Then start Miningcore:
sudo docker run -d \
--name miningcore \
--restart unless-stopped \
--env-file /etc/miningcore/miningcore.env \
--network miningcore \
-p 4000:4000 \
-p 127.0.0.1:4001:4001 \
-p 127.0.0.1:4002:4002 \
-p 3032:3032 \
-v /etc/miningcore/config.json:/etc/miningcore/config.json:ro \
-v /var/lib/miningcore:/var/lib/miningcore \
ghcr.io/ninjak1dd/miningcore:${MININGCORE_VERSION}To build the same source locally instead:
git clone https://github.com/NINJAK1DD/miningcore.git
cd miningcore
git checkout dev
sudo docker build -t btcpool-miningcore:local .Run it with the same /etc/miningcore/config.json and /var/lib/miningcore mounts:
sudo docker run -d \
--name miningcore \
--restart unless-stopped \
--env-file /etc/miningcore/miningcore.env \
--network miningcore \
-p 4000:4000 \
-p 127.0.0.1:4001:4001 \
-p 127.0.0.1:4002:4002 \
-p 3032:3032 \
-v /etc/miningcore/config.json:/etc/miningcore/config.json:ro \
-v /var/lib/miningcore:/var/lib/miningcore \
btcpool-miningcore:localUseful management commands:
sudo docker logs -f miningcore
sudo sh -c '
. /etc/miningcore/miningcore.env
printf "Authorization: Bearer %s\n" "$MININGCORE_ADMIN_API_TOKEN" |
curl --fail --header @- \
http://127.0.0.1:4001/api/admin/stats/gc
'
curl --fail http://127.0.0.1:4002/metrics --output /dev/null
sudo docker stop miningcore
sudo docker rm miningcoredocker restart does not reload --env-file. After rotating the administrative token, changing a
version, or changing container creation options, remove and recreate the container with the full
version-pinned docker run command above. See the
administrative API security guide for safe token
rotation.
Remember these container boundaries:
127.0.0.1inside a container means the container itself, not the Docker host.- Miningcore must be able to reach PostgreSQL and every coin daemon through controlled network routes. Services on the Docker host normally use the selected bridge gateway rather than container-local loopback.
- Host traffic on a published port normally appears from the bridge gateway. If a protected request
returns
403, confirm the address in Miningcore's unauthorized-request log before changing a whitelist. - A containerised Prometheus service should use a dedicated network and a predictable whitelisted address.
- Native hashing libraries can depend on CPU architecture and features, so build locally only on hardware compatible with the production host.
The full release, checksum, provenance, container and update procedure is in the release guide.
The Quick start is the single copy-paste path for a new prebuilt installation. To avoid competing procedures, detailed database creation, backup, migration, partitioning and recovery commands live only in the task-specific runbooks:
| Task | Authoritative procedure |
|---|---|
| Create a new PostgreSQL database | Quick start: create PostgreSQL |
| Create a PostgreSQL database from a source checkout | Database guide: new installation using src/Miningcore/Persistence/Postgres/Scripts/createdb.sql |
| Upgrade an existing release and database | Release upgrade or rollback |
| Enable pooled accounting or PPS | PPS database prerequisites |
| Prepare a v0.2.1-or-earlier/pre-PR #135 database for default direct-coinbase SOLO | Direct-SOLO database migration |
| Back up, inspect or recover PostgreSQL | Database and recovery guide |
Partition the shares table |
Advanced partitioning |
Never run createdb.sql over an existing database, run release migrations through the old active
symlink, or edit balances, blocks or payments manually. Stop every writer named by the upgrade
runbook and prove the backup before a schema change.
For a fresh source-only installation, first follow the
source-checkout database path; do not use the prebuilt-only
/opt/miningcore/migrations/createdb.sql path unless that release layout has actually been
installed. Then copy the annotated configuration into the publish directory and open it for
editing:
cp config.example.json build/config.json
${EDITOR:-vi} build/config.jsonOn Windows PowerShell, use notepad build/config.json or another editor instead.
Replace every active placeholder marker (CHANGE_ME or REPLACE_WITH_) and remove pools or
services you do not intend to run. Save the file, then run this fail-closed placeholder check:
source_placeholder_status=0
if [ -f build/config.json ] && [ -r build/config.json ] && [ ! -L build/config.json ]; then
awk '
/^[[:space:]]*\/\// { next }
/CHANGE_ME|REPLACE_WITH_/ { print NR ":" $0; found = 1 }
END { exit found ? 0 : 3 }
' build/config.json || source_placeholder_status=$?
case "$source_placeholder_status" in
0) echo 'STOP: replace every active placeholder before starting Miningcore' >&2; false ;;
3) echo 'READY: no active placeholders remain' ;;
*) echo 'STOP: could not inspect build/config.json' >&2; false ;;
esac
else
echo 'STOP: could not inspect build/config.json' >&2
false
fiOnly after the check prints READY, start the published binary:
cd build
./Miningcore -c config.jsonMiningcore accepts comments in configuration files, while ordinary strict-JSON tools may not. The example index, configuration guide and coin-family extension guidance define the supported starting points. The machine-readable configuration schema covers the shared typed structure. Keep the first run interactive and, from another terminal, verify the local health endpoint:
curl --fail --max-time 5 http://127.0.0.1:4000/api/health-checkAfter verifying the pool APIs, install a production layout before unattended operation. The
supplied unit expects
/opt/miningcore/Miningcore.dll, /etc/miningcore/config.json and the dedicated miningcore
account; it does not run the development build/ layout unchanged. Follow
quick-start step 8 or the
release service procedure, or create an equivalent
service with paths and an account appropriate to your installation. Do not host a production pool
in screen or an interactive SSH session.
The API is enabled in the example on port 4000. Dedicated adminPort and metricsPort listeners
keep protected route families off the public listener. Administrative requests additionally require
a bearer token kept outside the JSON configuration and public WebUI. See the
administrative API security guide and
API listener configuration before publishing any HTTP port. Common
public endpoints include:
GET /api/health-check
GET /api/pools
GET /api/pools/{poolId}
GET /api/pools/{poolId}/blocks
GET /api/pools/{poolId}/miners/{address}
GET /api/blocks
The fork has its own API guide, derived from the current controllers rather than relying solely on an older upstream wiki. It includes v2 routes, WebSocket notifications, metrics, rate limiting, admin-port isolation and reverse-proxy guidance.
Miningcore supplies an API, not a bundled public website. A community project such as btclinux/Miningcore.WebUI can be used as a starting point, but it targets another Miningcore fork and is not maintained, audited or endorsed by this project. Review its current maintenance, licence and API assumptions, and deploy it behind your own HTTPS reverse proxy before exposing it publicly. BTCPool.co.uk uses its own operational choices; this reference is not a dependency.
Most beginners should use a direct node: Miningcore, PostgreSQL access and payout processing on one Linux host, with coin daemons on the same protected network. Distributed share relay deployments are an advanced option.
| Role | What it needs |
|---|---|
| Direct pool/recorder | PostgreSQL and one payout manager |
| Non-merged database-free relay sender | Remote receiver/recorder; no local database |
| Merged-mining relay sender | PostgreSQL for synchronous block persistence |
| Central relay receiver/recorder | PostgreSQL; usually the sole payout/reconciliation owner |
Only one payout manager may own a pool/database set. Merged-mining nodes also have synchronous block persistence and schema-preflight requirements. The full rules, crash recovery procedure and ZeroMQ limitations are in the merged-mining deployment guide.
- Linux is the production target. Windows builds are intended for development and testing.
- Keep the host and .NET 10 serviced. Apply supported security and runtime updates promptly.
- Check each coin before enabling it. Daemon, wallet, memory and native-file requirements vary by coin family; start with the bundled coin definitions and the daemon's own documentation.
- Keep private services private. Never expose wallet RPC, daemon RPC, PostgreSQL, the admin API or internal relay ports to the public internet.
- Prefer a direct deployment unless you need relays. Ordinary ZeroMQ relay traffic is not a durable queue and is not replayed after an outage. Read the share-relay guide before distributing roles.
- Plan for storage failure. Put
shareRecoveryFileon separately monitored or reserved storage where possible. If both PostgreSQL and the recovery journal fail, Miningcore deliberately stops accepting shares and requires the documented recovery procedure. - Allow clean shutdown to finish. Miningcore reserves up to 45 seconds for accounting and recovery work; configure the service manager above that limit. The supplied systemd unit uses 90 seconds.
The detailed queue, journal, fail-stop and platform guarantees are documented under Share recovery storage. They are kept out of this overview so operators can find the required actions without first reading implementation internals.
Before advertising a public pool:
- Run Miningcore on a maintained Linux release with a serviced .NET 10 runtime.
- Isolate daemon, wallet, PostgreSQL, admin API and relay ports with host/network firewalls.
- Put the public API and website behind an HTTPS reverse proxy; do not expose the admin API port.
- Enforce public-client request limits at that proxy. Miningcore does not recover the original client address from forwarded headers when the proxy connects over loopback.
- Keep hot-wallet balances limited. When the pool pays Bitcoin-family transaction fees, maintain a
confirmed fee reserve; account for
minersPayTxFeesand per-recipient fallback behavior. Test daemon-generated wallet backups, database backups and configuration recovery. - Use systemd or an equivalent supervisor with restart policy, resource limits and sufficient clean shutdown time. Keep its forced-stop timeout above Miningcore's 45-second internal budget.
- Monitor daemon sync, pool hashrate, rejected shares, uncertain blocks, reconciliation, disk space, PostgreSQL backups, wallet balances and payout ownership.
- Complete the real-daemon validation plan for merged mining. If the final relay hosts or route differ from the validated physical lab, repeat its firewall-interruption test on that exact production path.
Automated tests can be run with:
dotnet test src/Miningcore.Tests/Miningcore.Tests.csprojThey cover consensus serialization, attribution and persistence regressions, but do not replace real
litecoind, dogecoind, wallet and PostgreSQL testing.
The operator handbook collects routine health, monitoring, stop/start and backup checks. Start with the troubleshooting guide when a live service reports an error or unexpected state.
Submit changes as pull requests targeting the dev branch.
Use this repository's issue tracker for reproducible
fork-specific bugs. Operational information for the hosted pool belongs on
BTCPool.co.uk, not in GitHub issues.
The upstream repository, its discussions and any upstream commercial services are maintained separately and are not support offered by BTCPool.co.uk.
Donations to support development and maintenance of this NINJAK1DD Miningcore fork:
| Coin | Address |
|---|---|
| BTC | bc1q94x9ncw62g09c80yr38jkewyn6cre3h473g54j |
| ETH | 0x4DE55672F0bBB88882A5a589b320eE40FfbdebF9 |
| DOGE | DQKEyZ2sTzcCPeeqzP4xUiPHzwtCS9LUTt |
| ZEC | t1TbjCnoNdGWnwEt9QqCZvHuG3MsWf4Bj66 |
| XMR | 43iiCs5pjvqbzYDvGSPgwtTdR4E4s996cSBsCSTe5HHbSrzr4HBosKZch8t7Fpg34DL9dNcN22T7H6JWEC23B9iDLAZqQsp |
| BCH | bitcoincash:qzyvaurh8vlj22jvyhpdce6ld4lt3zfc3svyt665de |
| LTC | ltc1qgnt28drw663gldx76zp3s28xl58wsp0ccv4vxg |
| KAS | kaspa:qzdtdjatlzecrt9u4v22p5vgud6w6ylvemly9df6zpu0gp0yks9xxp24q79pu |
| ETC | 0x331e6c8d7Caae3Dd1136EefF6c828dBDe5ae64F0 |
| FIRO | aH1tURoFqY1quNraAtceE6YFPv3DLFo8zT |
| XEL | xel:gt8m2j4al22k8ecp99uducy84vnhn2nlx6ftxjgw2rfr0hg5n47sqkec7n4 |
| WART | 4701843e274a2a4dfbac59678cb693233274bf5fefcc4e46 |
Always verify the address and network before sending funds. Cryptocurrency transfers cannot be reversed.
Miningcore is distributed under the terms in LICENSE. This distribution derives from Miningcore and acknowledges its original maintainers and contributors; consult the upstream history for earlier work.
Third-party dependencies retain their own licence terms. AutoMapper's licence states that version 16
source and binaries are governed by the
Reciprocal Public License 1.5,
unless they are used under AutoMapper's commercial licence agreement. Miningcore's licence does not
replace those terms. Review them for your deployment and obtain independent legal advice if needed.
If you use a Lucky Penny licence, follow the
licence-key configuration guide for systemd and Docker setup,
verification, rotation and troubleshooting. Do not store a key in config.json or source control.
Without a key, AutoMapper logs a warning but does not disable runtime features; operators remain
responsible for complying with the applicable licence terms.
See Dependency security for NuGet audit policy, the AutoMapper dependency decision and the documented risk acceptance for the legacy Zcash cryptography dependency.
