<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Salifu Yakubu</title>
    <description>The latest articles on DEV Community by Salifu Yakubu (@salifu_yakubu_746531f3b9b).</description>
    <link>https://dev.to/salifu_yakubu_746531f3b9b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4004067%2Fc7918305-a4f4-4b70-83aa-e44ff360280c.jpg</url>
      <title>DEV Community: Salifu Yakubu</title>
      <link>https://dev.to/salifu_yakubu_746531f3b9b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salifu_yakubu_746531f3b9b"/>
    <language>en</language>
    <item>
      <title>Running a Bitcoin Core Node with Docker — Compile from Source vs Pre-built Binaries</title>
      <dc:creator>Salifu Yakubu</dc:creator>
      <pubDate>Tue, 30 Jun 2026 13:12:55 +0000</pubDate>
      <link>https://dev.to/salifu_yakubu_746531f3b9b/running-a-bitcoin-core-node-with-docker-compile-from-source-vs-pre-built-binaries-1e4p</link>
      <guid>https://dev.to/salifu_yakubu_746531f3b9b/running-a-bitcoin-core-node-with-docker-compile-from-source-vs-pre-built-binaries-1e4p</guid>
      <description>&lt;p&gt;This guide walks you through two approaches to setting up a local Bitcoin Core v28.0 node using Docker, targeting both &lt;strong&gt;regtest&lt;/strong&gt; (a fully local, isolated chain you control) and &lt;strong&gt;testnet&lt;/strong&gt; (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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Docker Desktop (or Docker Engine + Compose plugin) installed and running&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git&lt;/code&gt; installed&lt;/li&gt;
&lt;li&gt;Basic comfort with the terminal&lt;/li&gt;
&lt;li&gt;~4 GB free disk space (more for testnet sync)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Understanding the Two Approaches
&lt;/h2&gt;

&lt;p&gt;Before 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?&lt;/p&gt;

&lt;h3&gt;
  
  
  Compile from Source
&lt;/h3&gt;

&lt;p&gt;You download the raw C++ source code from the Bitcoin Core repository, tell the compiler exactly what features to include, and produce binaries yourself. The &lt;code&gt;./configure&lt;/code&gt; step is where you make decisions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./configure &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--with-sqlite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;  &lt;span class="c"&gt;# Use SQLite for wallet storage (the v28 default)&lt;/span&gt;
    &lt;span class="nt"&gt;--without-bdb&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;      &lt;span class="c"&gt;# Drop BerkeleyDB — the old wallet backend, now legacy&lt;/span&gt;
    &lt;span class="nt"&gt;--disable-tests&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;    &lt;span class="c"&gt;# Skip test suite binaries — not needed at runtime&lt;/span&gt;
    &lt;span class="nt"&gt;--disable-bench&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;    &lt;span class="c"&gt;# Skip benchmarking binaries&lt;/span&gt;
    &lt;span class="nt"&gt;--without-gui&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;      &lt;span class="c"&gt;# No Qt desktop GUI — this is a headless server node&lt;/span&gt;
    &lt;span class="nt"&gt;--disable-man&lt;/span&gt;         &lt;span class="c"&gt;# Skip generating man pages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each flag is a question: &lt;em&gt;what is this node for, and what should it include?&lt;/em&gt; That process of asking and answering is most of the educational value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Compile from Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Build time&lt;/td&gt;
&lt;td&gt;20–40 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final image size&lt;/td&gt;
&lt;td&gt;~250 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reproducibility&lt;/td&gt;
&lt;td&gt;Sensitive to compiler and library versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Educational value&lt;/td&gt;
&lt;td&gt;High — exposes dependencies, wallet architecture, build flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Understanding how Bitcoin Core is structured&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Pre-built Binaries
&lt;/h3&gt;

&lt;p&gt;The 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Pre-built Binaries&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Build time&lt;/td&gt;
&lt;td&gt;~1 minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final image size&lt;/td&gt;
&lt;td&gt;~80–100 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reproducibility&lt;/td&gt;
&lt;td&gt;Identical binary every time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Educational value&lt;/td&gt;
&lt;td&gt;Lower — the build process is hidden&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Fast iteration when the focus is RPC and wallet exercises&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which should you choose?&lt;/strong&gt;&lt;br&gt;
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 node &lt;em&gt;does&lt;/em&gt; (mining blocks in regtest, reading the mempool, broadcasting transactions), pre-built is less friction. This guide covers both in full.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;Create a working directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;bitcoin-node &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;bitcoin-node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bitcoin-node/
├── Dockerfile              # Choose one of the two versions below
├── docker-compose.yml
└── entrypoint.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Option A: Compile from Source
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Dockerfile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="c"&gt;# Stage 1 — builder&lt;/span&gt;
&lt;span class="c"&gt;# Compiles Bitcoin Core v28.0 from source on Debian Bookworm.&lt;/span&gt;
&lt;span class="c"&gt;# BerkeleyDB is dropped — Bitcoin Core v28 uses SQLite by default.&lt;/span&gt;
&lt;span class="c"&gt;# Nothing from this stage leaks into the final image.&lt;/span&gt;
&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;debian:bookworm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;        git &lt;span class="se"&gt;\
&lt;/span&gt;        build-essential &lt;span class="se"&gt;\
&lt;/span&gt;        libtool &lt;span class="se"&gt;\
&lt;/span&gt;        autotools-dev &lt;span class="se"&gt;\
&lt;/span&gt;        automake &lt;span class="se"&gt;\
&lt;/span&gt;        pkg-config &lt;span class="se"&gt;\
&lt;/span&gt;        python3 &lt;span class="se"&gt;\
&lt;/span&gt;        libssl-dev &lt;span class="se"&gt;\
&lt;/span&gt;        libevent-dev &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-system-dev &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-filesystem-dev &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-thread-dev &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-chrono-dev &lt;span class="se"&gt;\
&lt;/span&gt;        libsqlite3-dev &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# Clone Bitcoin Core v28.0 at the exact tagged commit&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &lt;span class="nt"&gt;--branch&lt;/span&gt; v28.0 &lt;span class="se"&gt;\
&lt;/span&gt;        https://github.com/bitcoin/bitcoin.git /bitcoin

&lt;span class="c"&gt;# Compile Bitcoin Core with SQLite wallet, no GUI, no tests, no bench&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /bitcoin &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    ./autogen.sh &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    ./configure &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--with-sqlite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--without-bdb&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--disable-tests&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--disable-bench&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--without-gui&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--disable-man&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    make &lt;span class="nt"&gt;-j&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    make &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="c"&gt;# Stage 2 — runtime&lt;/span&gt;
&lt;span class="c"&gt;# Copies only the compiled binaries. No build tools, no source.&lt;/span&gt;
&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; debian:bookworm&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;        libssl3 &lt;span class="se"&gt;\
&lt;/span&gt;        libevent-2.1-7 &lt;span class="se"&gt;\
&lt;/span&gt;        libevent-pthreads-2.1-7 &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-system1.74.0 &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-filesystem1.74.0 &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-thread1.74.0 &lt;span class="se"&gt;\
&lt;/span&gt;        libboost-chrono1.74.0 &lt;span class="se"&gt;\
&lt;/span&gt;        libsqlite3-0 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /usr/local/bin/bitcoind    /usr/local/bin/bitcoind&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /usr/local/bin/bitcoin-cli /usr/local/bin/bitcoin-cli&lt;/span&gt;

&lt;span class="k"&gt;VOLUME&lt;/span&gt;&lt;span class="s"&gt; ["/root/.bitcoin"]&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8333&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; entrypoint.sh /entrypoint.sh&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /entrypoint.sh
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/entrypoint.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;debian:bookworm&lt;/code&gt; instead of &lt;code&gt;debian:13&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
Debian 13 ("trixie") is still in testing. Library package names and versions shift without notice, which makes the runtime layer fragile. &lt;code&gt;bookworm&lt;/code&gt; (Debian 12) is the current stable release — the library names above are reliable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What to pay attention to
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;./autogen.sh&lt;/code&gt;&lt;/strong&gt; generates the &lt;code&gt;configure&lt;/code&gt; script from &lt;code&gt;configure.ac&lt;/code&gt;. Bitcoin Core does not ship a pre-generated &lt;code&gt;configure&lt;/code&gt; script in its repository, so this step is always required when building from source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;make -j$(nproc)&lt;/code&gt;&lt;/strong&gt; parallelises the build across all available CPU cores. On a 4-core machine this is &lt;code&gt;make -j4&lt;/code&gt;. Removing &lt;code&gt;-j$(nproc)&lt;/code&gt; makes the build sequential — useful for debugging build failures but much slower.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The two-stage build&lt;/strong&gt; is 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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option B: Pre-built Binaries
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Dockerfile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="c"&gt;# Stage 1 — verifier&lt;/span&gt;
&lt;span class="c"&gt;# Downloads Bitcoin Core v28.0 official binaries and verifies them.&lt;/span&gt;
&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;debian:bookworm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;        wget &lt;span class="se"&gt;\
&lt;/span&gt;        gpg &lt;span class="se"&gt;\
&lt;/span&gt;        gpg-agent &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;

&lt;span class="c"&gt;# Download binaries, checksums, and the detached signature&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;wget &lt;span class="nt"&gt;-q&lt;/span&gt; https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    wget &lt;span class="nt"&gt;-q&lt;/span&gt; https://bitcoincore.org/bin/bitcoin-core-28.0/SHA256SUMS &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    wget &lt;span class="nt"&gt;-q&lt;/span&gt; https://bitcoincore.org/bin/bitcoin-core-28.0/SHA256SUMS.asc

&lt;span class="c"&gt;# Import release signing keys from the Bitcoin Core guix.sigs repository&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;gpg &lt;span class="nt"&gt;--keyserver&lt;/span&gt; hkps://keys.openpgp.org &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--recv-keys&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;          152812300785C96444D3334D17565732E08E5E41 &lt;span class="se"&gt;\
&lt;/span&gt;          0CCBAAFD76A2ECE2CCD3141DE2FFD5B1D88CA97D

&lt;span class="c"&gt;# Verify the GPG signature on the checksums file&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;gpg &lt;span class="nt"&gt;--verify&lt;/span&gt; SHA256SUMS.asc SHA256SUMS

&lt;span class="c"&gt;# Verify the tarball matches the signed checksum&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"bitcoin-28.0-x86_64-linux-gnu.tar.gz"&lt;/span&gt; SHA256SUMS | &lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; -

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; bitcoin-28.0-x86_64-linux-gnu.tar.gz

&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="c"&gt;# Stage 2 — runtime&lt;/span&gt;
&lt;span class="c"&gt;# ============================================================&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; debian:bookworm&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        ca-certificates &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /build/bitcoin-28.0/bin/bitcoind    /usr/local/bin/bitcoind&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /build/bitcoin-28.0/bin/bitcoin-cli /usr/local/bin/bitcoin-cli&lt;/span&gt;

&lt;span class="k"&gt;VOLUME&lt;/span&gt;&lt;span class="s"&gt; ["/root/.bitcoin"]&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8333&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; entrypoint.sh /entrypoint.sh&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /entrypoint.sh
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/entrypoint.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why the GPG step matters
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;SHA256SUMS&lt;/code&gt; file contains a hash of the tarball. A checksum alone tells you the download arrived intact — it does not tell you whether &lt;code&gt;bitcoincore.org&lt;/code&gt; itself was compromised, or whether the file was replaced in transit.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SHA256SUMS.asc&lt;/code&gt; is a GPG detached signature over &lt;code&gt;SHA256SUMS&lt;/code&gt;, produced by a Bitcoin Core maintainer using their private key. When you run &lt;code&gt;gpg --verify SHA256SUMS.asc SHA256SUMS&lt;/code&gt;, 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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exercise:&lt;/strong&gt; Run &lt;code&gt;gpg --verify SHA256SUMS.asc SHA256SUMS&lt;/code&gt; and note the output. Then intentionally corrupt one byte in &lt;code&gt;SHA256SUMS&lt;/code&gt; and run it again. What does GPG report?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Entrypoint Script
&lt;/h2&gt;

&lt;p&gt;This file is identical for both approaches. Save it as &lt;code&gt;entrypoint.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nv"&gt;MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;regtest&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MODE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in
  &lt;/span&gt;regtest&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Starting Bitcoin Core v28.0 (regtest) ==="&lt;/span&gt;
    bitcoind &lt;span class="nt"&gt;-regtest&lt;/span&gt; &lt;span class="nt"&gt;-daemon&lt;/span&gt;
    &lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/.bitcoin/regtest/debug.log
    &lt;span class="p"&gt;;;&lt;/span&gt;
  testnet&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Starting Bitcoin Core v28.0 (testnet) ==="&lt;/span&gt;
    bitcoind &lt;span class="nt"&gt;-testnet&lt;/span&gt; &lt;span class="nt"&gt;-daemon&lt;/span&gt;
    &lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/.bitcoin/testnet3/debug.log
    &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: Unknown mode '&lt;/span&gt;&lt;span class="nv"&gt;$MODE&lt;/span&gt;&lt;span class="s2"&gt;'. Use 'regtest' or 'testnet'."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;esac&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Waiting for debug.log ==="&lt;/span&gt;
&lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Node running in &lt;/span&gt;&lt;span class="nv"&gt;$MODE&lt;/span&gt;&lt;span class="s2"&gt; mode. Tailing debug log (Ctrl+C to detach) ==="&lt;/span&gt;
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make it executable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x entrypoint.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this script does
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;set -e&lt;/code&gt; causes the script to exit immediately if any command fails. Without this, a failed &lt;code&gt;bitcoind&lt;/code&gt; launch would silently fall through to &lt;code&gt;tail -f&lt;/code&gt; on a log file that does not exist yet.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-daemon&lt;/code&gt; starts &lt;code&gt;bitcoind&lt;/code&gt; as a background process. The script then polls for the debug log file — this is how it knows &lt;code&gt;bitcoind&lt;/code&gt; has actually initialised rather than just been spawned.&lt;/p&gt;

&lt;p&gt;The two log paths reflect Bitcoin Core's directory layout:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Data directory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;regtest&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/root/.bitcoin/regtest/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;testnet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/root/.bitcoin/testnet3/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mainnet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/root/.bitcoin/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;

&lt;p&gt;Save as &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;bitcoin-node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitcoin-core:v28.0&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitcoin-regtest&lt;/span&gt;

    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18444:18444"&lt;/span&gt;   &lt;span class="c1"&gt;# P2P  (regtest)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18443:18443"&lt;/span&gt;   &lt;span class="c1"&gt;# RPC  (regtest)&lt;/span&gt;

    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./bitcoin-data:/root/.bitcoin&lt;/span&gt;

    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/entrypoint.sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;regtest"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Port reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8333&lt;/td&gt;
&lt;td&gt;P2P&lt;/td&gt;
&lt;td&gt;Mainnet peer connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18333&lt;/td&gt;
&lt;td&gt;P2P&lt;/td&gt;
&lt;td&gt;Testnet peer connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18444&lt;/td&gt;
&lt;td&gt;P2P&lt;/td&gt;
&lt;td&gt;Regtest peer connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8332&lt;/td&gt;
&lt;td&gt;RPC&lt;/td&gt;
&lt;td&gt;Mainnet RPC server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18332&lt;/td&gt;
&lt;td&gt;RPC&lt;/td&gt;
&lt;td&gt;Testnet RPC server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18443&lt;/td&gt;
&lt;td&gt;RPC&lt;/td&gt;
&lt;td&gt;Regtest RPC server&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Switching to testnet
&lt;/h3&gt;

&lt;p&gt;Change the &lt;code&gt;entrypoint&lt;/code&gt; line and update the port mappings in &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18333:18333"&lt;/span&gt;   &lt;span class="c1"&gt;# P2P  (testnet)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18332:18332"&lt;/span&gt;   &lt;span class="c1"&gt;# RPC  (testnet)&lt;/span&gt;

    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/entrypoint.sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;testnet"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note on testnet:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Building and Running
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Build the image
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the source build this will take 20–40 minutes the first time. Docker caches layers, so subsequent builds are fast unless you change the &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start the node
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A healthy regtest start looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;=== 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
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;2024-01-15T10:23:02Z init message: Done loading
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run in detached mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Interacting with the Node via RPC
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Inside the container
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; getblockchaininfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  From the host (requires RPC auth)
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;bitcoin-data/bitcoin.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;rpcuser&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;devuser&lt;/span&gt;
&lt;span class="py"&gt;rpcpassword&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;devpass123&lt;/span&gt;
&lt;span class="py"&gt;rpcallowip&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
&lt;span class="py"&gt;rpcbind&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then from the host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-rpcconnect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;127.0.0.1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-rpcport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;18443 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-rpcuser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;devuser &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-rpcpassword&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;devpass123 &lt;span class="se"&gt;\&lt;/span&gt;
    getblockchaininfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Essential CLI Exercises (Regtest)
&lt;/h2&gt;

&lt;p&gt;Regtest gives you a blank chain — nothing exists until you create it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check the chain state
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; getblockchaininfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a wallet
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; createwallet &lt;span class="s2"&gt;"my-wallet"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mine blocks
&lt;/h3&gt;

&lt;p&gt;Mining in regtest is instant. Generate 101 blocks to make the coinbase of the first block spendable (coinbase outputs require 100 confirmations):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    generatetoaddress 101 &lt;span class="si"&gt;$(&lt;/span&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; getnewaddress&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check your balance
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; getbalance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;50.00000000&lt;/code&gt; BTC.&lt;/p&gt;

&lt;h3&gt;
  
  
  Send a transaction
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; getnewaddress&lt;span class="si"&gt;)&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; sendtoaddress &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ADDR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 1.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inspect the mempool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; getrawmempool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mine one block to confirm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    generatetoaddress 1 &lt;span class="si"&gt;$(&lt;/span&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; getnewaddress&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Decode a raw transaction
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    getrawtransaction &amp;lt;txid&amp;gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Container exits immediately&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose logs bitcoin-node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most common cause is a malformed &lt;code&gt;bitcoin.conf&lt;/code&gt; or a port already in use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;bitcoin-cli&lt;/code&gt; returns "Connection refused"&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;bitcoind&lt;/code&gt; may still be initialising. Follow the logs and wait for "Done loading".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testnet sync is very slow&lt;/strong&gt;&lt;br&gt;
Add &lt;code&gt;prune=550&lt;/code&gt; to &lt;code&gt;bitcoin.conf&lt;/code&gt; to limit disk usage to ~550 MB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Wallet file not found" on RPC calls&lt;/strong&gt;&lt;br&gt;
Create a wallet explicitly — v28 no longer creates a default wallet on startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; bitcoin-regtest bitcoin-cli &lt;span class="nt"&gt;-regtest&lt;/span&gt; createwallet &lt;span class="s2"&gt;"default"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Rebuilding after changing the Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose build &lt;span class="nt"&gt;--no-cache&lt;/span&gt;
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Source Build&lt;/th&gt;
&lt;th&gt;Pre-built&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dockerfile complexity&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build time&lt;/td&gt;
&lt;td&gt;20–40 min&lt;/td&gt;
&lt;td&gt;~1 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPG verification&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git verify-tag v28.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg --verify SHA256SUMS.asc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Understanding Bitcoin Core internals&lt;/td&gt;
&lt;td&gt;RPC / wallet exercises&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regtest ready&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testnet ready&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both setups use the same &lt;code&gt;entrypoint.sh&lt;/code&gt; and &lt;code&gt;docker-compose.yml&lt;/code&gt;. The only difference is what arrives at &lt;code&gt;/usr/local/bin/bitcoind&lt;/code&gt;, whether you compiled it or downloaded it, it is the same software.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;p&gt;Written by &lt;strong&gt;Samuel Kodie&lt;/strong&gt; (Discord: skodie0) and &lt;strong&gt;Salifu Yakubu&lt;/strong&gt; (Discord: salifu_88984)&lt;/p&gt;

</description>
      <category>bitcoin</category>
      <category>docker</category>
      <category>blockchain</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
