feat: docker image for ElectrumX, configured by environment
Replaces lukechilds/electrumx, unmaintained for years. ElectrumX 2.0.0 from the
upstream tag, rocksdb, built in a venv so only the runtime library follows into
the final image.
Every variable is ElectrumX's own — the entrypoint only fills defaults and
rejects the one mistake that is expensive to diagnose: NET spelled the way
bitcoind spells it ("test" for "testnet"), which otherwise fails deep inside a
coin-class lookup. DB_ENGINE defaults to rocksdb because 2.0 made the variable
required, and peer discovery is off because this image is for private indexers.
Verified on testnet2 against the sibling bitcoind image: coin BitcoinRegtest,
db height matching daemon height at 101, Electrum protocol answering on 50001.
That run also found what the README now states — 2.x refuses to serve unless
the daemon runs with both txindex=1 and txospenderindex=1.
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
# Intro
|
||||
|
||||
> Русская версия: [README.ru-RU.md](README.ru-RU.md)
|
||||
|
||||
[ElectrumX](https://github.com/spesmilo/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
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```sh
|
||||
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
|
||||
|
||||
```sh
|
||||
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](https://github.com/spesmilo/electrumx/tags):
|
||||
|
||||
```sh
|
||||
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](https://electrumx-spesmilo.readthedocs.io/en/latest/environment.html)
|
||||
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=1` and `txospenderindex=1`.** ElectrumX 2.x checks
|
||||
`getindexinfo` before it serves anything and exits with a `RuntimeError`
|
||||
naming the missing index — one at a time, so fixing `txindex` earns you the
|
||||
same message about `txospenderindex`. With the sibling
|
||||
[bitcoind image](https://git.bitdeals.org/private/bitcoind) that is
|
||||
`BITCOIND_TXINDEX=1` and `BITCOIND_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.
|
||||
- **`NET` is ElectrumX's spelling, not bitcoind's.** The daemon calls the
|
||||
networks `main`, `test` and `regtest`; ElectrumX calls them `mainnet`,
|
||||
`testnet` and `regtest`. The entrypoint rejects an unknown value, because the
|
||||
pair is usually configured from one `.env` and `NET=test` would 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 `SERVICES` asks for TLS and
|
||||
no files are supplied.** Clients then have to trust it explicitly. That is the
|
||||
price of ElectrumX refusing to start when `ssl://` is requested without a
|
||||
certificate, which is a surprising way to learn you added a port.
|
||||
Reference in New Issue
Block a user