WealthMedia

Running a Bitcoin Core Node with Docker — Compile from Source vs Pre-built Binaries

This guide walks you through two approaches to setting up a local Bitcoin Core v28. 0 node using Docker, targeting bothregtest(a fully local, isolated chain you control) andtestnet(a public test network with. . .

· 8 min read

Running a Bitcoin Core Node with Docker — Compile from Source vs Pre-built Binaries

This guide walks you through two approaches to setting up a local Bitcoin Core v28. 0 node using Docker, targeting bothregtest(a fully local, isolated chain you control) andtestnet(a public test network with real peer connections). By the end you will have a running node, understand what every line of configuration does, and be ready to interact with it over RPC. PrerequisitesDocker Desktop (or Docker Engine + Compose plugin) installed and runninggitinstalledBasic comfort with the terminal~4 GB free disk space (more for testnet sync)Understanding the Two ApproachesBefore writing a single line of code, you need to make a decision that shapes everything else: do you compile Bitcoin Core from source, or do you download official pre-built binaries?Compile from SourceYou download the raw C++ source code from the Bitcoin Core repository, tell the compiler exactly what features to include, and produce binaries yourself. The. /configurestep is where you make decisions:. /configure\--with-sqlite=yes\# Use SQLite for wallet storage (the v28 default)--without-bdb\# Drop BerkeleyDB — the old wallet backend, now legacy--disable-tests\# Skip test suite binaries — not needed at runtime--disable-bench\# Skip benchmarking binaries--without-gui\# No Qt desktop GUI — this is a headless server node--disable-man# Skip generating man pagesEnter fullscreen modeExit fullscreen modeEach flag is a question:what is this node for, and what should it include?That process of asking and answering is most of the educational value. Trade-offs:Compile from SourceBuild time20–40 minutesFinal image size~250 MBReproducibilitySensitive to compiler and library versionsEducational valueHigh — exposes dependencies, wallet architecture, build flagsBest forUnderstanding how Bitcoin Core is structuredPre-built BinariesThe Bitcoin Core project publishes official binaries for every release. You download the tarball, verify its checksum, and copy the binaries into your image. No compiler required. Trade-offs:Pre-built BinariesBuild time~1 minuteFinal image size~80–100 MBReproducibilityIdentical binary every timeEducational valueLower — the build process is hiddenBest forFast iteration when the focus is RPC and wallet exercisesWhich should you choose?If the exercise is about how Bitcoin Core is built — its dependencies, wallet backends, compile-time options — use source. If the exercise is about what the nodedoes(mining blocks in regtest, reading the mempool, broadcasting transactions), pre-built is less friction. This guide covers both in full. Project StructureCreate a working directory:mkdirbitcoin-node&&cdbitcoin-nodeEnter fullscreen modeExit fullscreen modebitcoin-node/ ├── Dockerfile # Choose one of the two versions below ├── docker-compose. yml └── entrypoint. shEnter fullscreen modeExit fullscreen modeOption A: Compile from SourceThe Dockerfile# ============================================================# Stage 1 — builder# Compiles Bitcoin Core v28. 0 from source on Debian Bookworm. # BerkeleyDB is dropped — Bitcoin Core v28 uses SQLite by default. # Nothing from this stage leaks into the final image. # ============================================================FROMdebian:bookwormASbuilderRUNapt-get update&&\apt-getinstall-y--no-install-recommends\ca-certificates\git\build-essential\libtool\autotools-dev\automake\pkg-config\python3\libssl-dev\libevent-dev\libboost-system-dev\libboost-filesystem-dev\libboost-thread-dev\libboost-chrono-dev\libsqlite3-dev&&\rm-rf/var/lib/apt/lists/*# Clone Bitcoin Core v28. 0 at the exact tagged commitRUNgit clone--depth1--branchv28. 0\https://github. com/bitcoin/bitcoin. git /bitcoin# Compile Bitcoin Core with SQLite wallet, no GUI, no tests, no benchRUNcd/bitcoin&&\. /autogen. sh&&\. /configure\--with-sqlite=yes\--without-bdb\--disable-tests\--disable-bench\--without-gui\--disable-man&&\make-j$(nproc)&&\makeinstall# ============================================================# Stage 2 — runtime# Copies only the compiled binaries. No build tools, no source. # ============================================================FROMdebian:bookwormRUNapt-get update&&\apt-getinstall-y--no-install-recommends\ca-certificates\libssl3\libevent-2. 1-7\libevent-pthreads-2. 1-7\libboost-system1. 74. 0\libboost-filesystem1. 74. 0\libboost-thread1. 74. 0\libboost-chrono1. 74. 0\libsqlite3-0&&\rm-rf/var/lib/apt/lists/*COPY--from=builder /usr/local/bin/bitcoind /usr/local/bin/bitcoindCOPY--from=builder /usr/local/bin/bitcoin-cli /usr/local/bin/bitcoin-cliVOLUME["/root/. bitcoin"]EXPOSE8333COPYentrypoint. sh /entrypoint. shRUNchmod+x /entrypoint. shENTRYPOINT["/entrypoint. sh"]Enter fullscreen modeExit fullscreen modeWhydebian:bookworminstead ofdebian:13?Debian 13 ("trixie") is still in testing. Library package names and versions shift without notice, which makes the runtime layer fragile. bookworm(Debian 12) is the current stable release — the library names above are reliable. What to pay attention to. /autogen. shgenerates theconfigurescript fromconfigure. ac. Bitcoin Core does not ship a pre-generatedconfigurescript in its repository, so this step is always required when building from source. make -j$(nproc)parallelises the build across all available CPU cores. On a 4-core machine this ismake -j4. Removing-j$(nproc)makes the build sequential — useful for debugging build failures but much slower. The two-stage buildis deliberate. The builder stage installs compilers, headers, and source — easily 600 MB of tooling. The runtime stage copies only the two binaries and their shared library dependencies. This is why the final image is ~250 MB rather than ~800 MB. Option B: Pre-built BinariesThe Dockerfile# ============================================================# Stage 1 — verifier# Downloads Bitcoin Core v28. 0 official binaries and verifies them. # ============================================================FROMdebian:bookwormASbuilderRUNapt-get update&&\apt-getinstall-y--no-install-recommends\ca-certificates\wget\gpg\gpg-agent&&\rm-rf/var/lib/apt/lists/*WORKDIR/build# Download binaries, checksums, and the detached signatureRUNwget-qhttps://bitcoincore. org/bin/bitcoin-core-28. 0/bitcoin-28. 0-x86_64-linux-gnu. tar. gz&&\wget-qhttps://bitcoincore. org/bin/bitcoin-core-28. 0/SHA256SUMS&&\wget-qhttps://bitcoincore. org/bin/bitcoin-core-28. 0/SHA256SUMS. asc# Import release signing keys from the Bitcoin Core guix. sigs repositoryRUNgpg--keyserverhkps://keys. openpgp. org\--recv-keys\152812300785C96444D3334D17565732E08E5E41\0CCBAAFD76A2ECE2CCD3141DE2FFD5B1D88CA97D# Verify the GPG signature on the checksums fileRUNgpg--verifySHA256SUMS. asc SHA256SUMS# Verify the tarball matches the signed checksumRUNgrep"bitcoin-28. 0-x86_64-linux-gnu. tar. gz"SHA256SUMS |sha256sum-c-RUNtar-xzfbitcoin-28. 0-x86_64-linux-gnu. tar. gz# ============================================================# Stage 2 — runtime# ============================================================FROMdebian:bookwormRUNapt-get update&&\apt-getinstall-y--no-install-recommends\ca-certificates&&\rm-rf/var/lib/apt/lists/*COPY--from=builder /build/bitcoin-28. 0/bin/bitcoind /usr/local/bin/bitcoindCOPY--from=builder /build/bitcoin-28. 0/bin/bitcoin-cli /usr/local/bin/bitcoin-cliVOLUME["/root/. bitcoin"]EXPOSE8333COPYentrypoint. sh /entrypoint. shRUNchmod+x /entrypoint. shENTRYPOINT["/entrypoint. sh"]Enter fullscreen modeExit fullscreen modeWhy the GPG step mattersTheSHA256SUMSfile contains a hash of the tarball. A checksum alone tells you the download arrived intact — it does not tell you whetherbitcoincore. orgitself was compromised, or whether the file was replaced in transit. SHA256SUMS. ascis a GPG detached signature overSHA256SUMS, produced by a Bitcoin Core maintainer using their private key. When you rungpg --verify SHA256SUMS. asc SHA256SUMS, you are confirming that a known, trusted key holder signed off on those checksums. This is the same trust model that Bitcoin Core users are expected to follow when installing on any machine — skipping it in a learning environment teaches a bad habit. Exercise:Rungpg --verify SHA256SUMS. asc SHA256SUMSand note the output. Then intentionally corrupt one byte inSHA256SUMSand run it again. What does GPG report?The Entrypoint ScriptThis file is identical for both approaches. Save it asentrypoint. sh:#!/usr/bin/env bashset-eMODE="${1:-regtest}"case"$MODE"inregtest)echo"=== Starting Bitcoin Core v28. 0 (regtest) ==="bitcoind-regtest-daemonLOG=/root/. bitcoin/regtest/debug. log;;testnet)echo"=== Starting Bitcoin Core v28. 0 (testnet) ==="bitcoind-testnet-daemonLOG=/root/. bitcoin/testnet3/debug. log;;*)echo"ERROR: Unknown mode '$MODE'. Use 'regtest' or 'testnet'. "exit1;;esacecho"=== Waiting for debug. log ==="until[-f"$LOG"];dosleep1doneecho"=== Node running in$MODEmode. Tailing debug log (Ctrl+C to detach) ==="tail-f"$LOG"Enter fullscreen modeExit fullscreen modeMake it executable:chmod+x entrypoint. shEnter fullscreen modeExit fullscreen modeWhat this script doesset -ecauses the script to exit immediately if any command fails. Without this, a failedbitcoindlaunch would silently fall through totail -fon a log file that does not exist yet. -daemonstartsbitcoindas a background process. The script then polls for the debug log file — this is how it knowsbitcoindhas actually initialised rather than just been spawned. The two log paths reflect Bitcoin Core's directory layout:ModeData directoryregtest/root/. bitcoin/regtest/testnet/root/. bitcoin/testnet3/mainnet/root/. bitcoin/Docker ComposeSave asdocker-compose. yml:services:bitcoin-node:build:context:. dockerfile:Dockerfileimage:bitcoin-core:v28. 0container_name:bitcoin-regtestports:-"18444:18444"# P2P (regtest)-"18443:18443"# RPC (regtest)volumes:-. /bitcoin-data:/root/. bitcoinentrypoint:["/entrypoint. sh","regtest"]restart:unless-stoppedEnter fullscreen modeExit fullscreen modePort referencePortProtocolPurpose8333P2PMainnet peer connections18333P2PTestnet peer connections18444P2PRegtest peer connections8332RPCMainnet RPC server18332RPCTestnet RPC server18443RPCRegtest RPC serverSwitching to testnetChange theentrypointline and update the port mappings indocker-compose. yml:ports:-"18333:18333"# P2P (testnet)-"18332:18332"# RPC (testnet)entrypoint:["/entrypoint. sh","testnet"]Enter fullscreen modeExit fullscreen modeNote on testnet:A testnet node needs to sync with the public testnet chain. For most CLI exercises in a development environment, regtest is preferred — you control the chain entirely, block generation is instant, and there is no sync wait. Building and RunningBuild the imagedocker compose buildEnter fullscreen modeExit fullscreen modeFor the source build this will take 20–40 minutes the first time. Docker caches layers, so subsequent builds are fast unless you change theDockerfile. Start the nodedocker compose upEnter fullscreen modeExit fullscreen modeA healthy regtest start looks like:=== Starting Bitcoin Core v28. 0 (regtest) === === Waiting for debug. log === === Node running in regtest mode. Tailing debug log (Ctrl+C to detach) === 2024-01-15T10:23:01Z Bitcoin Core version v28. 0. 0. . . 2024-01-15T10:23:02Z init message: Done loadingEnter fullscreen modeExit fullscreen modeRun in detached modedocker compose up-ddocker compose logs-fEnter fullscreen modeExit fullscreen modeInteracting with the Node via RPCInside the containerdockerexec-itbitcoin-regtest bitcoin-cli-regtestgetblockchaininfoEnter fullscreen modeExit fullscreen modeFrom the host (requires RPC auth)Createbitcoin-data/bitcoin. conf:rpcuser=devuserrpcpassword=devpass123rpcallowip=0. 0. 0. 0/0rpcbind=0. 0. 0. 0Enter fullscreen modeExit fullscreen modeThen from the host:bitcoin-cli-regtest\-rpcconnect=127. 0. 0. 1\-rpcport=18443\-rpcuser=devuser\-rpcpassword=devpass123\getblockchaininfoEnter fullscreen modeExit fullscreen modeEssential CLI Exercises (Regtest)Regtest gives you a blank chain — nothing exists until you create it. Check the chain statedockerexec-itbitcoin-regtest bitcoin-cli-regtestgetblockchaininfoEnter fullscreen modeExit fullscreen modeCreate a walletdockerexec-itbitcoin-regtest bitcoin-cli-regtestcreatewallet"my-wallet"Enter fullscreen modeExit fullscreen modeMine blocksMining in regtest is instant. Generate 101 blocks to make the coinbase of the first block spendable (coinbase outputs require 100 confirmations):dockerexec-itbitcoin-regtest bitcoin-cli-regtest\generatetoaddress 101$(dockerexecbitcoin-regtest bitcoin-cli-regtestgetnewaddress)Enter fullscreen modeExit fullscreen modeCheck your balancedockerexec-itbitcoin-regtest bitcoin-cli-regtestgetbalanceEnter fullscreen modeExit fullscreen modeYou should see50. 00000000BTC. Send a transactionADDR=$(dockerexecbitcoin-regtest bitcoin-cli-regtestgetnewaddress)dockerexec-itbitcoin-regtest bitcoin-cli-regtestsendtoaddress"$ADDR"1. 5Enter fullscreen modeExit fullscreen modeInspect the mempooldockerexec-itbitcoin-regtest bitcoin-cli-regtestgetrawmempoolEnter fullscreen modeExit fullscreen modeMine one block to confirm:dockerexec-itbitcoin-regtest bitcoin-cli-regtest\generatetoaddress 1$(dockerexecbitcoin-regtest bitcoin-cli-regtestgetnewaddress)Enter fullscreen modeExit fullscreen modeDecode a raw transactiondockerexec-itbitcoin-regtest bitcoin-cli-regtest\getrawtransaction trueEnter fullscreen modeExit fullscreen modeTroubleshootingContainer exits immediatelydocker compose logs bitcoin-nodeEnter fullscreen modeExit fullscreen modeThe most common cause is a malformedbitcoin. confor a port already in use. bitcoin-clireturns "Connection refused"bitcoindmay still be initialising. Follow the logs and wait for "Done loading". Testnet sync is very slowAddprune=550tobitcoin. confto limit disk usage to ~550 MB. "Wallet file not found" on RPC callsCreate a wallet explicitly — v28 no longer creates a default wallet on startup:dockerexec-itbitcoin-regtest bitcoin-cli-regtestcreatewallet"default"Enter fullscreen modeExit fullscreen modeRebuilding after changing the Dockerfiledocker compose build--no-cachedocker compose upEnter fullscreen modeExit fullscreen modeSummarySource BuildPre-builtDockerfile complexityHighLowBuild time20–40 min~1 minGPG verificationgit verify-tag v28. 0gpg --verify SHA256SUMS. ascBest forUnderstanding Bitcoin Core internalsRPC / wallet exercisesRegtest ready✅✅Testnet ready✅✅Both setups use the sameentrypoint. shanddocker-compose. yml. The only difference is what arrives at/usr/local/bin/bitcoind, whether you compiled it or downloaded it, it is the same software. The next step is working with wallets, descriptor addresses, and raw transactions. All of those exercises work against either setup with no changes to the Compose file. Written bySamuel Kodie(Discord: skodie0) andSalifu Yakubu(Discord: salifu_88984)

Source: dev.to

More Crypto news