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 code inside is worse than no tag.
Intro
Русская версия: README.ru-RU.md
ElectrumX is a server for the Electrum protocol. It indexes the chain from a full node and answers the queries a light client cannot answer for itself: the history and the UTXOs of an arbitrary address, and transaction broadcast.
ElectrumX running in a docker container, configured by environment variables.
This repository covers the docker deployment only. ElectrumX itself is installed from a pinned upstream git tag.
Usage
ElectrumX needs a bitcoind it can reach over RPC, on the same network, not
pruned. DAEMON_URL is the only required variable; NET must name the same
chain the daemon runs.
The container serves the Electrum protocol on 50001 (plaintext TCP) and, if
SERVICES asks for it, on 50002 (TLS). There is no authentication of any
kind, so keep both inside the docker network or on loopback. The RPC service
on localhost:8000 is administrative and never leaves the container — the
health check is what uses it.
docker-compose
services:
electrumx:
build:
context: https://git.bitdeals.org/private/electrumx.git
dockerfile: ./docker/Dockerfile
image: registry.bitdeals.org/electrumx
environment:
- COIN=Bitcoin
- NET=regtest
- DAEMON_URL=http://CHANGE_ME:CHANGE_ME@bitcoind:18443
- CACHE_MB=400
ports:
- 127.0.0.1:50001:50001 # no auth — loopback only
volumes:
- electrumxdata:/data
volumes:
electrumxdata:
docker cli
docker run -d \
-e COIN=Bitcoin \
-e NET=regtest \
-e DAEMON_URL=http://CHANGE_ME:CHANGE_ME@bitcoind:18443 \
-e CACHE_MB=400 \
-p 127.0.0.1:50001:50001 \
-v electrumxdata:/data \
registry.bitdeals.org/electrumx
Anything after the image name is passed on to electrumx_server.
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/electrumx
docker push registry.bitdeals.org/electrumx
A different ElectrumX release is a build argument — use a tag from the upstream repository:
docker build . --file docker/Dockerfile \
--build-arg ELECTRUMX_VERSION=2.0.0 \
--tag registry.bitdeals.org/electrumx:2.0.0
Parameters
Container images are configured using parameters passed at runtime. Every variable is ElectrumX's own, so the upstream environment reference applies unchanged; the table lists the ones this image gives a default to.
| Parameter | Function |
|---|---|
| -p 127.0.0.1:50001 | Electrum protocol over plaintext TCP. No authentication — see "Notes" |
| -p 127.0.0.1:50002 | Electrum protocol over TLS. Served only when SERVICES includes ssl:// |
| -v /data | Data directory: the index, and the self-signed certificate if one was generated. Losing it means indexing the chain again |
| -e DAEMON_URL | Required. The daemon's RPC, e.g. http://user:password@bitcoind:8332. Several may be given, comma-separated |
| -e COIN | Coin class. Default: Bitcoin |
| -e NET | Network: mainnet, testnet, testnet4, signet, regtest or mutinynet. Must match the daemon's chain. Default: mainnet |
| -e DB_ENGINE | Index storage. Default: rocksdb, the only engine whose libraries this image carries |
| -e DB_DIRECTORY | Where the index lives. Default: /data |
| -e SERVICES | What to serve, comma-separated. Default: tcp://:50001,rpc://localhost:8000. Keep an rpc:// entry — the health check needs it |
| -e SSL_CERTFILE, -e SSL_KEYFILE | TLS certificate and key. Default: generated as a self-signed pair in the data directory when SERVICES includes ssl:// |
| -e PEER_DISCOVERY | Whether to learn other public servers. Default: off — this image is meant for a private indexer |
| -e PEER_ANNOUNCE | Whether to announce this server to the peer network. Default: false |
| -e CACHE_MB | Indexing cache. Default: 1200 (ElectrumX's own). Lower it for a small chain, raise it to speed up an initial mainnet index |
Notes
- There is no authentication. Anyone who reaches 50001 or 50002 can query any address and broadcast transactions. Publish to loopback, or not at all when the clients are containers on the same network.
- An index from another image is not readable. This one runs rocksdb;
lukechilds/electrumx, which it replaces in BitDeals, wrote leveldb. Point the container at an empty volume and let it index — for regtest and testnet this is quick, for mainnet it is a matter of days. - The daemon needs
txindex=1andtxospenderindex=1. ElectrumX 2.x checksgetindexinfobefore it serves anything and exits with aRuntimeErrornaming the missing index — one at a time, so fixingtxindexearns you the same message abouttxospenderindex. With the sibling bitcoind image that isBITCOIND_TXINDEX=1andBITCOIND_TXOSPENDERINDEX=1; on an existing datadir turning them on means a reindex of the daemon. - The daemon must not be pruned. Indexing reads every block; a pruned node fails partway through with an error about a missing block rather than about the configuration.
NETis ElectrumX's spelling, not bitcoind's. The daemon calls the networksmain,testandregtest; ElectrumX calls themmainnet,testnetandregtest. The entrypoint rejects an unknown value, because the pair is usually configured from one.envandNET=testwould otherwise fail deep inside a coin lookup.- The container turns healthy only once it is serving, which is after it has caught up with the daemon. An initial mainnet index takes days and the container will be unhealthy for all of it — watch the logs instead; on regtest it is a matter of seconds.
- A self-signed certificate is generated only if
SERVICESasks for TLS and no files are supplied. Clients then have to trust it explicitly. That is the price of ElectrumX refusing to start whenssl://is requested without a certificate, which is a surprising way to learn you added a port.