Installing and Running a Node as a Docker Instance

Introduction

A Full Node simply connects to the network, synchronizes ledger state, and observes the status of the network. It can be thought of as a kind of “wallet” that is connected directly to the network, with the Node’s own account available for programmatic control.

Reasons to run a full node include:

  • Prerequisite to running the node as a validator node

  • Observing the network state and operation directly and trustlessly

  • Operating a trustless account using programmatic controls. (The current Radix Desktop Wallet cannot be used as a GUI for a full node’s internal account)

This guide will run you through an example installation and deployment of a node using docker containers.

Installing a Full Node as a Docker Instance in the Cloud

We’ve split the installation into discrete stages:

  • Installing Docker and the secure key generation tools.

  • Using the keygen application to generate secure keys for your service.

  • Installing and running the node on a provisioned server instance.

  • (An optional step converts the node into a validator, which is covered here)

We’re using Amazon Web Services throughout our example, but you can install Radix nodes on any cloud service that supports Java, such as Google’s cloud platform or Microsoft Azure – or follow similar step to deploy on a private server.

Prerequisites

We’re assuming that you’re comfortable provisioning a cloud service instance and installing/running Docker on it. You’ll also need a working knowledge of Git, and the UNIX command line.

AWS provisioning is beyond the scope of this exercise, but there are plenty of resources dotted around the web which will help you to get started. You will also need a working knowledge of Docker.

The provisioned AWS service

We recommend the following hardware specification as a minimum starting point.

Model vCPU Memory (GB) Storage(GB) Network Bandwidth (Gbps) Operating System

c5.2xlarge

8

16

Provision a gp2 storage volume.

You should initially provision 250 GB of SSD space

Up to 10

Ubuntu 22.04.2.0 LTS (Jammy Jellyfish)

You should initially provision 250 GB of SSD space

If you’re using a service provider other than AWS, then aim for a similar spec.

1. Docker Installation

If you’re using the provision recommended in the The provisioned AWS service section then you can log into the instance and run the following commands to install docker and docker-compose.

  1. Create the directory for the compose scripts:

    sudo apt update
    mkdir radixdlt
    cd  radixdlt
    mkdir babylon-ledger
    All further instructions assume you are running commands from directory radixdlt and radixdlt/babylon-ledger. Make sure to update the docker-compose file if these should be changed.
  2. Install wget, Docker and the tools for key generating randomized keys:

    sudo apt install wget
    sudo apt install docker.io
    sudo apt install docker-compose
    sudo apt install rng-tools
    sudo rngd -r /dev/random
  3. Add user to Docker group:

    sudo groupadd docker
    sudo usermod -aG docker $USER
    newgrp docker

2. Get the Docker Compose Script

You will need a docker compose script to build the node, which you can download from the Radix repository on GitHub directly to your server. You’ll need a different script, depending on whether you’re setting up a full node or an archive node. Copy and paste the following code into a file and call it radix-fullnode-compose.yml.

  • Fullnode Mainnet (default)

  • Fullnode Mainnet (migration)

  • Fullnode Stokenet

version: '3.8'
services:
  core:
    cap_add:
    - NET_ADMIN
    environment:
      RADIXDLT_NETWORK_ID: 1
      RADIXDLT_NETWORK_SEEDS_REMOTE: "radix://node_rdx1qf2x63qx4jdaxj83kkw2yytehvvmu6r2xll5gcp6c9rancmrfsgfw0vnc65@52.212.35.209,radix://node_rdx1qgxn3eeldj33kd98ha6wkjgk4k77z6xm0dv7mwnrkefknjcqsvhuu4gc609@54.79.136.139,radix://node_rdx1qwrrnhzfu99fg3yqgk3ut9vev2pdssv7hxhff80msjmmcj968487uugc0t2@43.204.226.50,radix://node_rdx1q0gnmwv0fmcp7ecq0znff7yzrt7ggwrp47sa9pssgyvrnl75tvxmvj78u7t@52.21.106.232"
      JAVA_OPTS: --enable-preview -server -Xms12g -Xmx12g -XX:MaxDirectMemorySize=2048m
        -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCompressedOops -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts
        -Djavax.net.ssl.trustStoreType=jks -Djava.security.egd=file:/dev/urandom -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
      RADIXDLT_LOG_LEVEL: info
      RADIXDLT_NETWORK_USE_PROXY_PROTOCOL: 'false'
      RADIXDLT_VALIDATOR_KEY_LOCATION: /home/radixdlt/node-keystore.ks
      RADIX_NODE_KEYSTORE_PASSWORD: "${RADIXDLT_NODE_KEY_PASSWORD}"
    image: radixdlt/babylon-node:v1.0.4
    init: true
    mem_limit: 14000m
    restart: unless-stopped
    ulimits:
      memlock: -1
      nofile:
        hard: 65536
        soft: 65536
    volumes:
    - babylon_ledger:/home/radixdlt/RADIXDB
    - ./radixdlt/node-keystore.ks:/home/radixdlt/node-keystore.ks
  nginx:
    environment:
      RADIXDLT_GATEWAY_API_ENABLE: 'true'
      RADIXDLT_GATEWAY_BEHIND_AUTH: 'true'
      RADIXDLT_NETWORK_USE_PROXY_PROTOCOL: 'false'
      RADIXDLT_TRANSACTIONS_API_ENABLE: 'false'
    image: radixdlt/babylon-nginx:1.0.1
    ports:
    - 443:443
    - 30000:30000
    restart: unless-stopped
    ulimits:
      nofile:
        hard: 65536
        soft: 65536
    volumes:
    - nginx_secrets:/etc/nginx/secrets
volumes:
  babylon_ledger:
    driver: local
    driver_opts:
      device: ./babylon-ledger
      o: bind
      type: none
  nginx_secrets:
version: '3.8'
services:
  core:
    cap_add:
    - NET_ADMIN
    environment:
      RADIXDLT_NETWORK_ID: 1
      RADIXDLT_NETWORK_SEEDS_REMOTE: "radix://node_rdx1qf2x63qx4jdaxj83kkw2yytehvvmu6r2xll5gcp6c9rancmrfsgfw0vnc65@52.212.35.209,radix://node_rdx1qgxn3eeldj33kd98ha6wkjgk4k77z6xm0dv7mwnrkefknjcqsvhuu4gc609@54.79.136.139,radix://node_rdx1qwrrnhzfu99fg3yqgk3ut9vev2pdssv7hxhff80msjmmcj968487uugc0t2@43.204.226.50,radix://node_rdx1q0gnmwv0fmcp7ecq0znff7yzrt7ggwrp47sa9pssgyvrnl75tvxmvj78u7t@52.21.106.232"
      JAVA_OPTS: --enable-preview -server -Xms12g -Xmx12g -XX:MaxDirectMemorySize=2048m
        -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCompressedOops -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts
        -Djavax.net.ssl.trustStoreType=jks -Djava.security.egd=file:/dev/urandom -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
      RADIXDLT_GENESIS_OLYMPIA_NODE_BECH32_ADDRESS: ${RADIXDLT_GENESIS_OLYMPIA_NODE_BECH32_ADDRESS}
      RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_AUTH_PASSWORD: ${RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_AUTH_PASSWORD}.
      RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_AUTH_USER: ${RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_AUTH_USER}
      RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_URL: ${RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_URL}
      RADIXDLT_GENESIS_USE_OLYMPIA: 'true'
      RADIXDLT_LOG_LEVEL: info
      RADIXDLT_NETWORK_USE_PROXY_PROTOCOL: 'false'
      RADIXDLT_VALIDATOR_KEY_LOCATION: /home/radixdlt/node-keystore.ks
      RADIX_NODE_KEYSTORE_PASSWORD: "${RADIXDLT_NODE_KEY_PASSWORD}"
    image: radixdlt/babylon-node:v1.0.4
    init: true
    mem_limit: 14000m
    restart: unless-stopped
    ulimits:
      memlock: -1
      nofile:
        hard: 65536
        soft: 65536
    volumes:
    - babylon_ledger:/home/radixdlt/RADIXDB
    - ./radixdlt/node-keystore.ks:/home/radixdlt/node-keystore.ks
  nginx:
    environment:
      RADIXDLT_GATEWAY_API_ENABLE: 'true'
      RADIXDLT_GATEWAY_BEHIND_AUTH: 'true'
      RADIXDLT_NETWORK_USE_PROXY_PROTOCOL: 'false'
      RADIXDLT_TRANSACTIONS_API_ENABLE: 'false'
    image: radixdlt/babylon-nginx:1.0.1
    ports:
    - 443:443
    - 30000:30000
    restart: unless-stopped
    ulimits:
      nofile:
        hard: 65536
        soft: 65536
    volumes:
    - nginx_secrets:/etc/nginx/secrets
volumes:
  babylon_ledger:
    driver: local
    driver_opts:
      device: ./babylon-ledger
      o: bind
      type: none
  nginx_secrets:
version: '3.8'
services:
  core:
    cap_add:
    - NET_ADMIN
    environment:
      RADIXDLT_NETWORK_ID: 2
      RADIXDLT_NETWORK_SEEDS_REMOTE: "radix://node_tdx_2_1qv89yg0la2jt429vqp8sxtpg95hj637gards67gpgqy2vuvwe4s5ss0va2y@13.126.248.88,radix://node_tdx_2_1qvtd9ffdhxyg7meqggr2ezsdfgjre5aqs6jwk5amdhjg86xhurgn5c79t9t@13.210.209.103,radix://node_tdx_2_1qwfh2nn0zx8cut5fqfz6n7pau2f7vdyl89mypldnn4fwlhaeg2tvunp8s8h@54.229.126.97,radix://node_tdx_2_1qwz237kqdpct5l3yjhmna66uxja2ymrf3x6hh528ng3gtvnwndtn5rsrad4@3.210.187.161"
      JAVA_OPTS: --enable-preview -server -Xms12g -Xmx12g -XX:MaxDirectMemorySize=2048m
        -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCompressedOops -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts
        -Djavax.net.ssl.trustStoreType=jks -Djava.security.egd=file:/dev/urandom -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
      RADIXDLT_LOG_LEVEL: info
      RADIXDLT_NETWORK_USE_PROXY_PROTOCOL: 'false'
      RADIXDLT_VALIDATOR_KEY_LOCATION: /home/radixdlt/node-keystore.ks
      RADIX_NODE_KEYSTORE_PASSWORD: "${RADIXDLT_NODE_KEY_PASSWORD}"
    image: radixdlt/babylon-node:v1.0.4
    init: true
    mem_limit: 14000m
    restart: unless-stopped
    ulimits:
      memlock: -1
      nofile:
        hard: 65536
        soft: 65536
    volumes:
    - babylon_ledger:/home/radixdlt/RADIXDB
    - ./radixdlt/node-keystore.ks:/home/radixdlt/node-keystore.ks
  nginx:
    environment:
      RADIXDLT_GATEWAY_API_ENABLE: 'true'
      RADIXDLT_GATEWAY_BEHIND_AUTH: 'true'
      RADIXDLT_NETWORK_USE_PROXY_PROTOCOL: 'false'
      RADIXDLT_TRANSACTIONS_API_ENABLE: 'false'
    image: radixdlt/babylon-nginx:1.0.1
    ports:
    - 443:443
    - 30000:30000
    restart: unless-stopped
    ulimits:
      nofile:
        hard: 65536
        soft: 65536
    volumes:
    - nginx_secrets:/etc/nginx/secrets
volumes:
  babylon_ledger:
    driver: local
    driver_opts:
      device: ./babylon-ledger
      o: bind
      type: none
  nginx_secrets:

3. Generate the keys

You’ll need the Radix Key Generator application to create secure keys for the node once it’s installed. (It’s a good idea to generate the keys first, just to get them out of the way).

The key file contains a randomly-generated private key that determines your node’s unique address and (if choosing to register as a validator node) validator ID.

This means if you lose your key file, you will forever lose your node address and validator ID - forcing you to generate a new key file from scratch.

Any tokens held by the node address will be lost.

As a validator, your delegators will have to unstake from your validator ID and restake to your new ID.

Always make sure that you securely back up your key file as soon as you’ve generated it, and carefully protect it.

You can check for the latest version of the keygen program here:

which should be used in the command given below to generate the secure keys.

docker run --rm -v ${PWD}:/keygen/key radixdlt/keygen:v1.4.1 --keystore=/keygen/key/node-keystore.ks --password=node-password

If you check the directory, you should now have a key file called node-keystore.ks.

The key generation process may take a long time if your server hasn’t generated a sufficiently large pool of random values to build fresh keys. Be prepared to wait up to twenty minutes for the key generation to complete.

You must change the key file’s permissions so that container can use it.

sudo chmod 644 node-keystore.ks

4. Setting up your Environment

The installation uses a Docker compose script to build the instance.

4.1. Create the environment variables

The compose script needs two pieces of information from you before it can run:

RADIXDLT_NODE_KEY_PASSWORD

The password you used in Section 3, “Generate the keys”.

For migration these additional variables must be set:

RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_URL

The root url to your olympia node without the '/olympia-end-state'. If you are not using nginx in front of your node, this defaults to the port 3400 and not the port for the core-api.

RADIXDLT_GENESIS_OLYMPIA_NODE_BECH32_ADDRESS

The bech32 node address of the olympia node to connect to. This is not the validator address.

RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_AUTH_PASSWORD

The administrative user to your olympia node. Can be left blank if not using nginx to protect the node.

RADIXDLT_GENESIS_OLYMPIA_NODE_END_STATE_API_AUTH_PASSWORD

The administrative password to your olympia node. Can be left blank if not using nginx to protect the node.

Set up the address and the password by creating environment variables on the instance:

export RADIXDLT_NODE_KEY_PASSWORD=node-password

5. Configure the Ports

The node requires that a number of ports are accessible on your server instance. Ensure that ports 443 and 30000 are available and can be seen externally.

HTTPS port for all API end points
 sudo ufw allow 443/tcp
GOSSIP port for node to node communication
 sudo ufw allow 30000/tcp

Bear in mind that you must arrange for port access outside your cloud server instance: this is usually done through the management console provided by your cloud service.

For more information on the ports used by the Radix service, please consult the Ports used by the Radix Node documentation.

At this point in directory radixdlt, you should have two files:

  • radix-fullnode-compose.yml or radix-archivenode-compose.yml

  • node-keystore.ks

6. Configure Nginx Admin password

The node uses Nginx as its front end server. During startup, it creates an HTTP basic auth user named admin. The password is generated automatically and printed to the logs. If you want to use your own password, you will need to use the Docker instruction below to set the password before running the node installation.

docker run --rm -v radixdlt_nginx_secrets:/secrets radixdlt/htpasswd:v1.1.0 htpasswd -bc /secrets/htpasswd.admin admin {nginx-admin-password}

If you omit the command, then nginx will create a password and print it out in the log. It will not appear in the logs if the nginx container restarts for any other reason.

To setup the superadmin and metrics users for your use, run these commands:

docker run --rm -v radixdlt_nginx_secrets:/secrets radixdlt/htpasswd:v1.1.0 htpasswd -bc /secrets/htpasswd.superadmin superadmin {nginx-superadmin-password}

docker run --rm -v radixdlt_nginx_secrets:/secrets radixdlt/htpasswd:v1.1.0 htpasswd -bc /secrets/htpasswd.metrics metrics {nginx-metrics-password}

7. Running the node

Run the compose script to install and run the node.

  • full node

docker-compose -f radix-fullnode-compose.yml up -d
The docker-compose file uses relative paths and expects this command to be run from the radixdlt folder created in the first step.

Troubleshooting

If your node isn’t running at this point, then consult the Troubleshooting Guide, or drop a message on Discord where Radix staff and community will be happy to help out.

Where to next …?

Once your node is up and running you can configure it to run as a validator by following the steps in Registering a Validator Node