Self-host TwistCoin
Run your own copy of the node, block explorer, address indexer, and solo pool - bare metal or Docker, one piece at a time or everything in one command. (Looking to just point your ASIC at the existing pool? See Mine instead - this page is for standing up your own independent infrastructure.)
Docker Deploy everything at once
twistcoin-deploy is a Docker Compose project that builds and wires up all
five components together, each pulled straight from its own GitLab repository - nothing
else needs cloning.
git clone https://gitlab.com/TwistCoin/twistcoin-deploy.git
cd twistcoin-deploy
cp .env.example .env
cp twistcoin.conf.example twistcoin.conf
cp fulcrum.conf.example fulcrum.conf
Edit those three files: generate real RPC credentials (e.g. openssl rand -hex 16)
and use the same ones in all three, set PUBLIC_POOL_API_URL/
PUBLIC_POOL_STRATUM_URL in .env to wherever you'll expose the
pool publicly, and make sure twistcoin.conf has
addnode=node.twistcoin.org:8433 so your node can find the network, and
externalip= set to your machine's real public IP so your node can announce
itself back (see the note in the Node section below for why this matters).
docker compose --profile full up -d --build
Compose profiles let you run a subset instead of everything: no profile at all starts
just the node, --profile explorer adds the indexer and block explorer,
--profile pool adds the solo pool backend and frontend, and
--profile full is all of it. Each service also has its own standalone
Dockerfile and works fine outside Compose too - see below for each piece on its own,
bare metal or Docker.
docker run instead of Compose?
Put them on a shared network first (docker network create twistcoin, then
--network twistcoin on each docker run) so containers can reach
each other by name - the examples below assume that and use container names like
twistcoin-node as hostnames.
Node - twistcoin-core
A source fork of Bitcoin Core - same engine, same build system, different network. Everyone else in this list talks to it over RPC and/or ZMQ, so it comes first.
Bare metal
sudo apt install cmake ninja-build build-essential libboost-dev libevent-dev \
libsqlite3-dev pkg-config libzmq3-dev
git clone https://gitlab.com/TwistCoin/twistcoin-core.git
cd twistcoin-core
cmake -B build -DBUILD_GUI=OFF -DWITH_ZMQ=ON -DENABLE_WALLET=OFF -DBUILD_TESTS=OFF -DENABLE_IPC=OFF -G Ninja
cmake --build build -j$(nproc)
Write a config file (default location ~/.twistcoin/twistcoin.conf):
server=1
txindex=1
rpcuser=CHANGE_ME
rpcpassword=CHANGE_ME
zmqpubrawblock=tcp://127.0.0.1:29000
addnode=node.twistcoin.org:8433
externalip=YOUR_PUBLIC_IP
./build/bin/twistcoind -daemon
./build/bin/twistcoin-cli getblockchaininfo # check it's syncing
txindex=1 and the ZMQ line are only needed if you're also running the
explorer/indexer or the pool - skip them for a node on its own.
externalip= to your node's real public IP (add a second
externalip= line for IPv6 if you have one). Without it, your node has to
guess its own reachable address - via UPnP (unavailable on most cloud servers, and often
disabled even on home routers) or by getting enough consistent feedback from outbound
peers - and on a still-small network like this one, that guess often never confidently
resolves. The node works fine either way, but without externalip= it may
never announce itself to the rest of the network, making it invisible to new nodes even
though it's syncing and reachable.
Docker
git clone https://gitlab.com/TwistCoin/twistcoin-core.git
cd twistcoin-core
docker build -t twistcoin-core .
Same config file as above, then:
docker run -d --name twistcoin-node --network twistcoin \
-p 8433:8433 \
-v twistcoin-data:/data \
-v $(pwd)/twistcoin.conf:/data/twistcoin.conf:ro \
twistcoin-core
RPC (8432) isn't published to the host on purpose - only other containers on the same
Docker network need it, reachable as twistcoin-node:8432.
Block explorer - twistcoin-explorer
A fork of btc-rpc-explorer. Needs the node's RPC, and Fulcrum (below) for address balance/history lookups - it works without Fulcrum, just without that one feature.
Bare metal
git clone https://gitlab.com/TwistCoin/twistcoin-explorer.git
cd twistcoin-explorer
npm install
cp .env-sample .env
Edit .env:
BTCEXP_COIN=TWIST
BTCEXP_BITCOIND_HOST=127.0.0.1
BTCEXP_BITCOIND_PORT=8432
BTCEXP_BITCOIND_USER=CHANGE_ME
BTCEXP_BITCOIND_PASS=CHANGE_ME
BTCEXP_ADDRESS_API=electrum
BTCEXP_ELECTRUM_SERVERS=tcp://127.0.0.1:50001
npm start
BTCEXP_COIN=TWIST is the one setting that actually matters here - without
it, this runs as a plain Bitcoin explorer against the wrong network entirely.
Docker
git clone https://gitlab.com/TwistCoin/twistcoin-explorer.git
cd twistcoin-explorer
docker build -t twistcoin-explorer .
docker run -d --name twistcoin-explorer --network twistcoin \
-p 127.0.0.1:3002:3002 \
-e BTCEXP_COIN=TWIST \
-e BTCEXP_BITCOIND_HOST=twistcoin-node \
-e BTCEXP_BITCOIND_PORT=8432 \
-e BTCEXP_BITCOIND_USER=CHANGE_ME \
-e BTCEXP_BITCOIND_PASS=CHANGE_ME \
-e BTCEXP_ADDRESS_API=electrum \
-e BTCEXP_ELECTRUM_SERVERS=tcp://twistcoin-fulcrum:50001 \
twistcoin-explorer
Address indexer - twistcoin-fulcrum
Node RPC alone can't answer "what's the balance/history of this address" - that needs a separate index. This is a patched fork of Fulcrum (an Electrum-protocol server) - the single patch makes it recognize TwistCoin Core's P2P identity instead of assuming Bitcoin Cash for anything that isn't literally Bitcoin Core.
Bare metal
sudo apt install qt6-base-dev qmake6 libbz2-dev libzmq3-dev libminiupnpc-dev \
build-essential pkg-config
git clone https://gitlab.com/TwistCoin/twistcoin-fulcrum.git
cd twistcoin-fulcrum
qmake6
make -j$(nproc) # RocksDB ships statically in the repo, nothing extra to build
Config file (anywhere, referenced on the command line):
bitcoind = 127.0.0.1:8432
rpcuser = CHANGE_ME
rpcpassword = CHANGE_ME
datadir = /path/to/some/data/dir
tcp = 127.0.0.1:50001
peering = false
./Fulcrum fulcrum.conf
Docker
git clone https://gitlab.com/TwistCoin/twistcoin-fulcrum.git
cd twistcoin-fulcrum
docker build -f contrib/docker/Dockerfile -t twistcoin-fulcrum .
Same config file as above, with bitcoind = twistcoin-node:8432, then:
docker run -d --name twistcoin-fulcrum --network twistcoin \
-v fulcrum-data:/data \
-v $(pwd)/fulcrum.conf:/data/fulcrum.conf:ro \
twistcoin-fulcrum Fulcrum /data/fulcrum.conf
Pool backend - twistpool-backend
A fork of Public Pool - the stratum server and API. Solo mining only: whoever finds a block gets the whole reward.
Bare metal
git clone https://gitlab.com/TwistCoin/twistpool-backend.git
cd twistpool-backend
npm install
npm run build
cp full-setup/twistpool-mainnet.env .env
Edit .env - the RPC/ZMQ values must match your node:
NETWORK=mainnet
TWISTCOIN_RPC_URL=http://127.0.0.1
TWISTCOIN_RPC_PORT=8432
TWISTCOIN_RPC_USER=CHANGE_ME
TWISTCOIN_RPC_PASSWORD=CHANGE_ME
TWISTCOIN_ZMQ_HOST=tcp://127.0.0.1:29000
API_PORT=3334
STRATUM_PORT=3333
node dist/main
Docker
git clone https://gitlab.com/TwistCoin/twistpool-backend.git
cd twistpool-backend
docker build -t twistpool-backend .
docker run -d --name twistpool-backend --network twistcoin \
-p 3333:3333 \
-p 127.0.0.1:3334:3334 \
-e NETWORK=mainnet \
-e TWISTCOIN_RPC_URL=http://twistcoin-node \
-e TWISTCOIN_RPC_PORT=8432 \
-e TWISTCOIN_RPC_USER=CHANGE_ME \
-e TWISTCOIN_RPC_PASSWORD=CHANGE_ME \
-e TWISTCOIN_ZMQ_HOST=tcp://twistcoin-node:29000 \
-e API_PORT=3334 -e STRATUM_PORT=3333 -e API_SECURE=false \
-v twistpool-db:/twistpool/DB \
twistpool-backend
127.0.0.1.
Pool frontend - twistpool-frontend
A fork of Public Pool UI (Angular) - the web dashboard miners see. Talks to the pool backend's API, not the node directly.
Bare metal
Edit src/environments/environment.prod.ts first and set API_URL/
STRATUM_URL to your own pool's address - unlike the Docker image, there's no
runtime config step here, so these get baked in at build time.
git clone https://gitlab.com/TwistCoin/twistpool-frontend.git
cd twistpool-frontend
npm install
npm run build # -> dist/public-pool-ui/
Serve dist/public-pool-ui/ with any static file server (nginx, Caddy, etc.) -
remember to fall back unknown paths to index.html for Angular's client-side
routing, and to reverse-proxy /api/ through to the pool backend's API port.
Docker
git clone https://gitlab.com/TwistCoin/twistpool-frontend.git
cd twistpool-frontend
docker build -t twistpool-frontend .
docker run -d --name twistpool-frontend --network twistcoin \
-p 8080:80 \
-e PUBLIC_POOL_API_URL=https://yourpool.example \
-e PUBLIC_POOL_STRATUM_URL=stratum+tcp://yourpool.example:3333 \
twistpool-frontend
Served by Caddy inside the container, on port 80 -
PUBLIC_POOL_API_URL/PUBLIC_POOL_STRATUM_URL are read at
container startup, not baked into the image, so the same image works for any domain.