Replaces lncm/bitcoind, which pins Core 26 — a version that still has legacy wallets, while the code that talks to it (bt's BitcoindClient) is written for the descriptor-only behaviour of 29 and later. The binaries are the official release build, verified by SHA-256 in the same layer that downloads them; a version bump that forgets the checksum fails the build instead of shipping something unverified. uid 1000 and /data/.bitcoin are kept from the image this replaces, so an existing named volume survives the switch without a recursive chown of a synced chain. Verified on testnet2: regtest node healthy in ~12 s, descriptor wallet, 101 blocks mined, sendtoaddress accepted — the last one being the check for BITCOIND_FALLBACKFEE, without which a fresh chain refuses to send.
91 lines
3.9 KiB
Docker
91 lines
3.9 KiB
Docker
# A container for the Bitcoin Core daemon
|
|
#
|
|
# The binaries are the official release build, taken from bitcoincore.org and
|
|
# checked against a SHA-256 pinned in this file. Building Core from source in
|
|
# CI would cost twenty minutes per image for a binary that upstream already
|
|
# publishes reproducibly; verifying the checksum is what makes taking it safe.
|
|
#
|
|
# Bumping BITCOIN_VERSION means bumping both checksums below. Get them from
|
|
# https://bitcoincore.org/bin/bitcoin-core-<version>/SHA256SUMS -- if you bump
|
|
# the version alone the build fails at `sha256sum -c`, which is the intent.
|
|
|
|
FROM debian:trixie-slim AS fetch
|
|
|
|
ARG BITCOIN_VERSION=31.1
|
|
ARG BITCOIN_SHA256_X86_64=b80d9c3e04da78fb6f0569685673418cf686fadba9042d926d13fb87ff503f9e
|
|
ARG BITCOIN_SHA256_AARCH64=dcf1873f2208ba4f962f3398d47e154c39c0084be8f4553e05c940d0ace3d004
|
|
|
|
RUN apt-get update \
|
|
&& apt-get install -yq --no-install-suggests --no-install-recommends \
|
|
ca-certificates wget \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# One RUN, because the checksum must be verified in the same layer that
|
|
# downloads: a cached "download" layer paired with a later check would verify
|
|
# an artefact nobody fetched in this build.
|
|
RUN set -eu; \
|
|
arch="$(uname -m)"; \
|
|
case "$arch" in \
|
|
x86_64) sha="$BITCOIN_SHA256_X86_64" ;; \
|
|
aarch64) sha="$BITCOIN_SHA256_AARCH64" ;; \
|
|
*) echo "unsupported architecture: $arch" >&2; exit 1 ;; \
|
|
esac; \
|
|
tarball="bitcoin-${BITCOIN_VERSION}-${arch}-linux-gnu.tar.gz"; \
|
|
wget -q "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/${tarball}"; \
|
|
echo "${sha} ${tarball}" | sha256sum -c -; \
|
|
tar -xzf "$tarball" -C /tmp; \
|
|
mkdir -p /opt/bitcoin/bin; \
|
|
cp "/tmp/bitcoin-${BITCOIN_VERSION}/bin/bitcoind" \
|
|
"/tmp/bitcoin-${BITCOIN_VERSION}/bin/bitcoin-cli" /opt/bitcoin/bin/; \
|
|
/opt/bitcoin/bin/bitcoind -version | head -n 1
|
|
|
|
|
|
FROM debian:trixie-slim
|
|
|
|
# RPC. The daemon binds what BITCOIND_RPCBIND says (0.0.0.0 by default, because
|
|
# a container's peers reach it by service name); what you publish decides who
|
|
# outside can reach it, and the answer should stay "loopback only" -- the RPC
|
|
# controls the wallet and has no TLS.
|
|
EXPOSE 8332/tcp
|
|
# P2P. Publish it to accept inbound peers; without it the node still connects
|
|
# out. The port follows the chain: 8333 main, 18333 test, 18444 regtest.
|
|
EXPOSE 8333/tcp
|
|
|
|
# uid/gid 1000 and /data/.bitcoin are not arbitrary: they are what the image
|
|
# this one replaces (lncm/bitcoind) used, so an existing named volume keeps
|
|
# working across the switch without a recursive chown of a synced chain.
|
|
ENV USER_UID=1000
|
|
ENV USER_GID=1000
|
|
ENV HOME=/data
|
|
ENV BITCOIN_DATA=/data/.bitcoin
|
|
|
|
COPY --from=fetch /opt/bitcoin/bin/ /usr/local/bin/
|
|
COPY ./docker/run.sh /usr/local/bin/
|
|
COPY ./docker/healthy_check.sh /usr/local/bin/
|
|
|
|
RUN apt-get update \
|
|
&& apt-get install -yq --no-install-suggests --no-install-recommends gosu \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Both are ENTRYPOINT/HEALTHCHECK targets in exec form, so the bit has to be
|
|
# set here: a clone on a filesystem that does not carry it would otherwise
|
|
# build an image that cannot start.
|
|
RUN chmod +x /usr/local/bin/run.sh /usr/local/bin/healthy_check.sh
|
|
|
|
# groupadd, not addgroup: the slim images dropped the adduser package.
|
|
RUN groupadd --gid $USER_GID bitcoin \
|
|
&& useradd --uid $USER_UID --gid $USER_GID --skel /dev/null --create-home --home-dir $HOME bitcoin
|
|
|
|
VOLUME ${BITCOIN_DATA}
|
|
WORKDIR ${HOME}
|
|
|
|
# ENTRYPOINT, not CMD: everything after the image name is appended to bitcoind's
|
|
# own arguments, so `docker run … -reindex` does what it looks like.
|
|
ENTRYPOINT ["/usr/local/bin/run.sh"]
|
|
|
|
# The daemon answers RPC long before the chain is synced, so this reports "can I
|
|
# be talked to", not "am I caught up". On a fresh mainnet datadir the first
|
|
# answer still waits for the block index to load, hence the start period.
|
|
HEALTHCHECK --interval=15s --timeout=10s --start-period=120s --retries=3 \
|
|
CMD ["/usr/local/bin/healthy_check.sh"]
|