Spin up a private Bitcoin regtest network with two nodes (Docker), auto-mine spendable coins and repeatedly send transactions between nodes using a tiny bash helper.
Includes CI (ShellCheck + Hadolint + smoke test with live logs & timings) and an on-demand demo workflow.
Stack: Docker, docker compose v2, Bash, Bitcoin Core (regtest)
git clone https://github.com/SubhanshuMG/bitcoin-regtest-devops.git
cd bitcoin-regtest-devopsStart both nodes (node1 mines 101 blocks on first run):
docker compose up -dWatch logs live while services get healthy:
docker compose logs -f --tail=100Create & confirm a tx from node1 ➜ node2:
bash ./scripts/create-tx.sh 0.10Expected output:
🏦 Creating + broadcasting 0.10 BTC from node1 ➜ node2
🪙 TX broadcast – <txid>
✅ Confirmed in block (confirmations: 1)
Cleanup:
docker compose down -v.
├─ docker-compose.yml # 2 Bitcoin Core nodes, healthchecks with start_period
├─ Dockerfile # image based on bitcoin/bitcoin:25 (+ jq)
├─ scripts/
│ ├─ entrypoint.sh # builds bitcoind args from env; idempotent mining on node1
│ ├─ create-tx.sh # re-runnable: fresh address + confirm block each run
│ └─ wait-for-bitcoind.sh # RPC readiness probe (used by healthchecks)
└─ .github/workflows/
├─ ci.yml # lint + build + up + live logs + tx (timed)
└─ demo.yml # on-demand demo run; logs uploaded as artifact
└─ LICENSE # MIT
-
Two nodes with separate P2P/RPC ports:
node1mines 101 blocks on first run so coinbase UTXOs are spendable.node2peers tonode1via-addnode=node1:18444.
-
Entrypoint (
scripts/entrypoint.sh) assemblesbitcoindflags from env vars (no fragile env expansion in composecommand:), waits for RPC, creates a default wallet, and handles first-run mining onnode1. -
Healthchecks poll
getblockchaininfountil RPC is ready; CI waits on health and streams container logs live. -
Transactions (
scripts/create-tx.sh) do the following:- Request a fresh address on
node2 - Send funds from
node1 - Mine 1 block on
node1to confirm - Verify confirmations on
node2
- Request a fresh address on
Check chain state:
docker exec btc-node1 bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass -rpcport=18443 getblockchaininfo
docker exec btc-node2 bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass -rpcport=18445 getpeerinfoMine extra blocks:
docker exec btc-node1 bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass -rpcport=18443 \
generatetoaddress 3 "$(docker exec btc-node1 bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass -rpcport=18443 getnewaddress)"Check balances:
docker exec btc-node1 bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass -rpcport=18443 getbalance
docker exec btc-node2 bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass -rpcport=18445 getbalanceWorkflow: ci.yml — runs on every push/PR
- Lint: ShellCheck (
bewuethr/shellcheck-action@v2) + Hadolint (warnings don’t fail build) - Build: compose build; warms
bitcoin/bitcoin:25 - Up & Logs:
docker compose up -dthen streams logs live until both nodes are healthy (with timeout) - Tx: runs
bash ./scripts/create-tx.sh 0.01 - Timings: prints elapsed times for build / up+healthy / tx so reviewers see performance
Demo workflow: demo.yml lets reviewers click Run workflow, optionally choose an amount, and get logs + a fresh tx artifact in the run outputs.
- Compose over Kubernetes: ideal for local review; production would ship via Helm on k8s
- Single image for both nodes: identical binaries → fewer surprises & faster CI cache reuse
- Credentials: demo-only RPC creds via env; production would use
rpcauthor a secrets manager - Idempotency:
node1mines 101 blocks once per data volume (.bootstrappedflag) - Repeatable tx: every
create-tx.shcall generates a fresh address & confirms the tx
✅ Two-node regtest with peering and mined spendable funds
✅ At least one transaction from one node to the other
✅ Script re-usable: new tx on each run
✅ README with documented examples (mining, tx)
✅ CI pipeline (lint + smoke test w/ live logs & timings)
➕ Good git hygiene: small, descriptive commits
➕ Notes on trade-offs
➕ CD-style demo workflow (demo.yml) with logs artifact
- Docker Engine with docker compose v2
- Internet access for first image pull
This project is licensed under the MIT License (see LICENSE).