Tutorial · Running a node

Run a node in Docker

Build a small Docker image for IronDivi or the original Divi node from the official release file, check the file's fingerprint while you build, and run the node in a container that keeps its data, restarts after a crash and keeps its command port private.

About 7 minutes · Checked 2026-10-22

1Before you start

You need Docker on a 64-bit Intel or AMD Linux machine. We used Docker 29.9.0 on Ubuntu 22.04. Both Divi nodes publish a Linux build for that kind of machine, and that is what the images below are made from.

This page builds its own image instead of pulling someone else's. You see every line that goes into it, and the build stops if the downloaded file is not the one the release published.

Everything here runs on testnet first. When the container behaves the way you expect, step 8 moves it to the real network.

New to the two nodes?

IronDivi or the original Divi node explains the difference. The short version: IronDivi gives the smaller image and stops in a few seconds.

2Write the Dockerfile

Make an empty folder and save this as Dockerfile inside it.

# syntax=docker/dockerfile:1
FROM alpine:3.20
ADD --checksum=sha256:cda18c3c6d9716aba3634edb8caef44a2bb6a26fe72ccad7186cdf3e33530445 \
    https://github.com/DiviDomains/IronDivi/releases/download/v0.2.5/irondivi-x86_64-linux-musl.tar.gz /tmp/irondivi.tar.gz
RUN tar -xzf /tmp/irondivi.tar.gz -C /tmp \
 && install -m 755 /tmp/irondivi-x86_64-linux-musl/irondivid /tmp/irondivi-x86_64-linux-musl/irondivi-cli /usr/local/bin/ \
 && rm -rf /tmp/irondivi* \
 && adduser -D -h /data divi
USER divi
VOLUME /data
EXPOSE 51474
ENTRYPOINT ["irondivid", "--datadir", "/data", "--printtoconsole"]
CMD ["--testnet"]

What each part does:

3Build the image

From inside the folder:

docker build -t irondivi:0.2.5 .
docker image ls irondivi

Our build took 17 seconds and the image is about 42 MB.

To see the fingerprint check work, change one character of the checksum and build again. The build stops with an error that contains digest mismatch. Put the right value back before you go on.

4Start the node

docker run -d --name irondivi \
  --restart unless-stopped \
  -p 51474:51474 \
  -v irondivi-data:/data \
  irondivi:0.2.5

Ask the node questions with docker exec, which runs irondivi-cli inside the container:

docker exec irondivi irondivi-cli --testnet --datadir /data getblockcount
docker exec irondivi irondivi-cli --testnet --datadir /data getconnectioncount

The count climbs as the node downloads the chain. A full testnet download took our IronDivi node about an hour.

The command port stays inside

We did not publish the command port with -p, and you should not either. IronDivi listens for commands on 127.0.0.1 inside the container, so only docker exec can reach it.

With --datadir /data, IronDivi puts its files straight into /data. It does not make a testnet folder inside it.

5Give the command port a password

Without a name and password in its settings file, IronDivi accepts commands from anyone who reaches the port. Its log says:

RPC authentication disabled: rpcuser/rpcpassword not set

The port is only reachable from inside the container, but a password costs nothing. This command makes a random one and writes it straight into the container, so it never shows on your screen or lands in your shell history:

openssl rand -hex 24 | docker exec -i irondivi sh -c \
  'read p; printf "rpcuser = \"divi\"\nrpcpassword = \"%s\"\n" "$p" > /data/irondivi.conf; chmod 600 /data/irondivi.conf'
docker restart irondivi
docker logs irondivi 2>&1 | grep "RPC authentication"

The last line should now say RPC authentication enabled. irondivi-cli reads the same file, so the docker exec commands above keep working without any change. A request with the wrong password gets HTTP 401 Unauthorized.

The settings file is TOML, so text goes in double quotes. Config files explained lists every setting you can add.

6Logs, stopping and starting

docker logs -f irondivi     # follow the log; Ctrl+C stops following, not the node
docker stop irondivi        # stop the node
docker start irondivi       # start it again

docker stop sends the node the same polite signal as kill. Ours stopped in 3.1 seconds with exit code 0.

To replace the container, for example with a newer image, remove it and run it again with the same volume. The chain and wallet stay where they were:

docker rm -f irondivi
docker run -d --name irondivi --restart unless-stopped -p 51474:51474 -v irondivi-data:/data irondivi:0.2.5

Our node came back at the same height. docker rm never removes a named volume. Only docker volume rm irondivi-data does that, and it deletes the wallet with it.

We also killed the node process hard with kill -9 from outside the container. Docker started it again by itself and the restart count went to 1:

docker inspect -f '{{.RestartCount}}' irondivi
Back up the wallet first

The wallet is the wallet folder inside the volume. Before you experiment with volumes, stop the node and copy it out: docker stop irondivi && docker cp irondivi:/data/wallet ./irondivi-wallet-backup && docker start irondivi. Better still, write down the recovery words as Back up your wallet explains.

7The original Divi node in Docker

The original node (version 3.0.0) needs a slightly different image. Its Linux build expects the standard C library, so the image uses a small Debian base instead of Alpine. Save this in a second folder:

# syntax=docker/dockerfile:1
FROM debian:bookworm-slim
ADD --checksum=sha256:d09933ab413335b7472b29c4c255d7affea73630b73a0d5c52aec40a63fbd276 \
    https://github.com/DiviProject/Divi/releases/download/v3.0.0/divi-3.0.0-x86_64-linux-gnu-9e2f76c.tar.gz /tmp/divi.tar.gz
RUN tar -xzf /tmp/divi.tar.gz -C /tmp \
 && install -m 755 /tmp/divi-3.0.0/bin/divid /tmp/divi-3.0.0/bin/divi-cli /usr/local/bin/ \
 && rm -rf /tmp/divi* \
 && useradd -M -d /data -u 1000 divi \
 && install -d -o divi -g divi /data
USER divi
VOLUME /data
EXPOSE 51474
ENTRYPOINT ["divid", "-datadir=/data", "-printtoconsole"]
CMD ["-testnet"]

The Divi release page publishes no fingerprints. The value above is the SHA-256 of the file we downloaded and checked in Install the Divi node. Our image is about 94 MB.

This node refuses to open its command port until its settings file has a password. Write the file into the volume before the first start:

docker build -t divid:3.0.0 .
docker run --rm -v divid-data:/data --entrypoint sh divid:3.0.0 -c \
  'umask 077; p=$(head -c 24 /dev/urandom | od -An -tx1 | tr -d " \n"); printf "rpcuser=divi\nrpcpassword=%s\n" "$p" > /data/divi.conf'
docker run -d --name divid --restart unless-stopped --stop-timeout 120 \
  -p 51474:51474 -v divid-data:/data divid:3.0.0
docker exec divid divi-cli -datadir=/data -testnet getblockcount

The C++ settings file has no quotes. Write rpcpassword=value, never rpcpassword="value".

The first start is slow. The node creates a new wallet and fills it with spare keys, and for about two and a half minutes it answers every command with Loading wallet... (N %). Leave it alone until the count appears.

Give it time to stop

Docker waits 10 seconds after asking a container to stop, then kills it. Ours took 19 seconds to stop after a few minutes of running, so the default would have killed it. If the original node is killed, its next start can fail with Block database corruption detected. --stop-timeout 120 gives it two minutes. Recover a chain explains what to do if it happens anyway.

This node puts its testnet files in /data/testnet3, next to divi.conf.

Our C++ container started, answered commands and stopped cleanly, but it found no peers in the first 15 minutes we watched it. Its log showed socket recv error Connection reset by peer (104), the same refusal described in Install the Divi node for nodes started from a connection that already had many nodes on it. Adding three addnode= lines and restarting had not helped a few minutes later. If yours stays at 0 connections, read the advice on that page before you suspect Docker.

8Move to the real network

Use a new volume, so the testnet chain and wallet stay apart from the real ones, and publish the real network port, 51472, instead of 51474.

For IronDivi, delete the CMD ["--testnet"] line, build the image again, then:

docker run -d --name irondivi-main --restart unless-stopped \
  -p 51472:51472 -v irondivi-main:/data irondivi:0.2.5

For the original node, delete its CMD ["-testnet"] line, write a password into the new volume as in step 7, then run the image with -p 51472:51472 and a new volume. In the docker exec commands, leave out --testnet and -testnet.

The real chain is much bigger: our original node took about 3 hours 40 minutes and 6.5 GB of disk to download it.

If something goes wrong

What you seeWhat to do
digest mismatch during the buildThe downloaded file is not the one the checksum describes. Check that the version in the URL and the checksum belong to the same file on the release page.
You must set rpcpassword=<password> in the configuration fileThe original node found no password and exited with code 1. With --restart unless-stopped Docker starts it again and again. Write divi.conf into the volume as in step 7, then docker restart divid. Ignore the password the message suggests: it is now in your log.
Loading wallet... (21 %)The original node is still creating its first wallet. Wait.
getconnectioncount stays at 0See the advice on peers in Install the Divi node. It is not a Docker problem.
HTTP 401 Unauthorized from irondivi-cliThe tool read a different settings file from the node. Keep --datadir /data and --testnet on every docker exec command.
Block database corruption detected in docker logs dividThe original node was killed instead of stopped. See Recover a chain.
port is already allocatedAnother node or container already uses that port on the computer. Stop it, or publish a different outside port such as -p 51574:51474.

Next: run a node without Docker as a system service, or learn to upgrade a node safely.