bitdeals 3a52b5128b
Build docker image and push to registry.bitdeals.org / build (push) Failing after 3m16s
ci: build and publish the image on every push to main
The registry account available on the testnet hosts is pull-only (403 on a
blob upload even for an existing repository), so publishing goes the same way
every other BitDeals image does: the Gitea runner builds and pushes with the
CI credentials. Tags mirror the family — an immutable <version>.<sha7>, a
moving <version>, and :latest for compose and Watchtower.

The version is read out of the Dockerfile ARG rather than repeated here: a tag
that can disagree with the binary inside is worse than no tag.
2026-08-06 12:01:10 +00:00

Intro

Русская версия: README.ru-RU.md

Bitcoin Core is the reference Bitcoin implementation. bitcoind is its daemon: it keeps a full copy of the chain, relays transactions and serves a JSON-RPC interface.

Bitcoin Core running as a daemon in a docker container, configured by environment variables.

This repository covers the docker deployment only. The binaries are the official release build, checked against a SHA-256 pinned in the Dockerfile.

Usage

The container has two ports and they are not interchangeable. The RPC port (8332 main, 18332 test, 18443 regtest) controls the wallet and has no TLS: keep it on loopback, or on an internal docker network. The P2P port (8333 / 18333 / 18444) is the chain protocol: publish it to accept inbound peers, leave it unpublished to stay outbound-only.

The chain is selected by BITCOIND_CHAIN, and it also sets the default RPC port. An unknown value stops the container instead of falling back to mainnet.

docker-compose

services:
  bitcoind:
    build:
      context: https://git.bitdeals.org/private/bitcoind.git
      dockerfile: ./docker/Dockerfile
    image: registry.bitdeals.org/bitcoind
    environment:
      - BITCOIND_CHAIN=regtest
      - BITCOIND_USER=CHANGE_ME
      - BITCOIND_PASSWORD=CHANGE_ME
      - BITCOIND_FALLBACKFEE=0.00001
      - BITCOIND_TXINDEX=1            # both required by ElectrumX,
      - BITCOIND_TXOSPENDERINDEX=1    # drop them if nothing indexes this node
    ports:
      - 127.0.0.1:18443:18443   # RPC — loopback only
    volumes:
      - btcdata:/data/.bitcoin

volumes:
  btcdata:

docker cli

docker run -d \
  -e BITCOIND_CHAIN=regtest \
  -e BITCOIND_USER=CHANGE_ME \
  -e BITCOIND_PASSWORD=CHANGE_ME \
  -e BITCOIND_FALLBACKFEE=0.00001 \
  -p 127.0.0.1:18443:18443 \
  -v btcdata:/data/.bitcoin \
  registry.bitdeals.org/bitcoind

Anything after the image name is appended to the daemon's own arguments, so a one-off maintenance run needs no new image:

docker run --rm -v btcdata:/data/.bitcoin registry.bitdeals.org/bitcoind -reindex

build and publish

A push to main builds and publishes the image (.gitea/workflows/build.yaml), tagging it three ways: <version>.<sha7> to deploy by, <version> to read, and latest for compose and Watchtower. By hand, when the registry credentials are at hand:

docker build . --file docker/Dockerfile --tag registry.bitdeals.org/bitcoind
docker push registry.bitdeals.org/bitcoind

A different Core version is a build argument, and the checksum must move with it — take both from https://bitcoincore.org/bin/bitcoin-core-<version>/SHA256SUMS:

docker build . --file docker/Dockerfile \
  --build-arg BITCOIN_VERSION=31.1 \
  --build-arg BITCOIN_SHA256_X86_64=b80d9c3e04da78fb6f0569685673418cf686fadba9042d926d13fb87ff503f9e \
  --tag registry.bitdeals.org/bitcoind:31.1

Parameters

Container images are configured using parameters passed at runtime.

Parameter Function
-p 127.0.0.1:8332 RPC port. The daemon binds what BITCOIND_RPCBIND says, so what you publish decides who reaches it. It has full control of the wallet — see "Notes"
-p 8333 P2P port. Optional: without it the node still connects out to peers, it just cannot be connected to. Follows the chain: 8333 main, 18333 test, 18444 regtest
-v /data/.bitcoin Data directory: the chain, the block index and the wallets. Without it a container update means downloading the chain again
-e BITCOIND_CHAIN Network: main, test, signet or regtest. Anything else stops the container. Default: main
-e BITCOIND_USER RPC user. Default: user — change it
-e BITCOIND_PASSWORD RPC password. Default: pass — change it
-e BITCOIND_PORT RPC port. Default: the standard port of the selected chain (8332/18332/38332/18443). Pin it to keep one RPC URL across networks
-e BITCOIND_RPCBIND Interface the RPC listens on inside the container. Default: 0.0.0.0, so other containers reach it by service name
-e BITCOIND_RPCALLOWIP Who may call the RPC. Default: 0.0.0.0/0 — the container is expected to be closed off by what you publish, not by this
-e BITCOIND_FALLBACKFEE Fee rate (BTC/kvB) used when the chain has no fee history to estimate from. Default: 0 (disabled). A fresh regtest chain needs it, e.g. 0.00001
-e BITCOIND_TXINDEX Build the full transaction index. Default: 0. Required by ElectrumX. Changing it on an existing datadir forces a reindex
-e BITCOIND_TXOSPENDERINDEX Build the index of which transaction spent each output. Default: 0. Required by ElectrumX 2.x. Changing it on an existing datadir forces a reindex
-e BITCOIND_EXTRA_ARGS Extra bitcoind arguments, split on whitespace and appended last — so they override everything above

Notes

  • The RPC has full control of the wallet and no TLS. Publish it to 127.0.0.1 only, or not at all — inside a compose project other services reach it over the internal network by service name. BITCOIND_RPCALLOWIP defaults to 0.0.0.0/0 because that is the only value that works for container-to-container calls; the port mapping is what keeps it private.
  • The RPC credentials are visible in the container's process list. They are daemon arguments, which is how Core takes network-specific options that a config file would apply only inside a [chain] section. bitcoin-cli inside the container reads them from cli.conf instead, so the health check does not add a second copy.
  • A datadir from another image needs one manual chown. The daemon runs as uid 1000 and the entrypoint fixes ownership of the data directory itself, but it deliberately does not walk it: a synced mainnet datadir is hundreds of gigabytes and a recursive chown would be added to every restart.
  • An ElectrumX in front of this node needs two indexes. Set both BITCOIND_TXINDEX=1 and BITCOIND_TXOSPENDERINDEX=1: ElectrumX 2.x asks getindexinfo at startup and exits naming the one that is missing — first txindex, then, once that is fixed, txospenderindex. Both default to 0 here because they cost disk and most other users do not need them.
  • Pruning is incompatible with ElectrumX. An indexer needs the whole chain; -prune through BITCOIND_EXTRA_ARGS will make it fail at some later, much less obvious point.
  • Core 29 and later have no legacy wallets. createwallet produces a descriptor wallet, and a private key is imported with importdescriptors, not importprivkey. Code that pins descriptors=false fails at wallet creation.
  • Bumping the version means bumping the checksum. The build downloads the release tarball and verifies it in the same layer; a version bump on its own fails at sha256sum -c rather than shipping something unverified.
  • The container turns healthy as soon as the RPC answers, which is long before the chain is synced. That is on purpose: "unhealthy for three days of initial block download" would get the node restarted by anything watching health.
S
Description
No description provided
Readme
49 KiB
Languages
Dockerfile 50.7%
Shell 49.3%