Run a non-validator Ethereum node

Sharing my experience and what I have learned about running a non-staking Ethereum node.

Note:

  • You'll notice a couple of mentions of r/ethfinance, as my insights and motivation stem from the OGs in the crypto community who reflect there, sharing their knowledge, and wisdom, and inspiring others like myself.

  • The last client bug and much-needed discussion around client diversity sparked valuable discussions.

  • Hanniabu shared their thoughts on the financial loss of a bug in Geth, a majority client with 78% share of all running clients.

u/djlywtf hot takes on the consequences of running a majority client from the social side.

Motivation

The above discussion motivated me to run a node even though I can’t afford to run a full validator node. Running a non-validator node will also help in keeping the network secure and decentralised.

Now, if you want to run the node directly from the source code and want to stake as well, no need to read my mumble jumble any further. SomerEsat's guide has everything covered, and I was able to run the node without any trouble.

When I asked for feedback on choosing a node, Nimbus and Netheremind were suggested. After reading their docs for a couple of hours, I was lost and overwhelmed with different configuration parameters. Nonetheless, clients were running and syncing by the end of the day by using the source code and compiling it. But the goal was to run them on Docker.

Nimbus sadly lacks documentation for beginners like me, and I got no response to a couple of questions asked on Neterhmind Discord. So, I moved to the next one, Besu, and I loved their easy-to-follow documentation. The support I got on their Discord made me stick with them.

Besu:

Start here, and you can run the client by running the Docker command. Let's see the parameters one by one.

docker run -p 8545:8545 --mount type=bind,source=/<myvolume/besu/mainnet>,target=/var/lib/besu -p 30303:30303 hyperledger/besu:latest --rpc-http-enabled --data-path=/var/lib/besu
  1. docker run: Command to run Docker. If you haven't included your current logged user in the admin group, you might need to run the command with sudo.

  2. -p 8545:8545: Mapping the port of Docker to the port of your local system. The port (TCP) on which HTTP JSON-RPC listens. The default is 8545. Additional read Port Mapping

  3. --mount type=bind,source=/<myvolume/besu/mainnet>,target=/var/lib/besu: Docker runs on its environment, so if you don't mount the storage location to your local drive, your data will be lost each time you restart the Docker. This can be achieved by mounting a folder of your drive to the folder location of the client running inside the Docker. Additional read Mount bind

  4. -p 30303:30303: The P2P listening ports (UDP and TCP). Used to sync with other running clients. The default is 30303.

  5. hyperledger/besu:latest: Besu Docker image with the latest tag.

  6. --rpc-http-enabled: Enables or disables the HTTP JSON-RPC service. The default is false. Get yourself familiarised with different parameters supported by Besu

  7. --data-path=/var/lib/besu: Location where sync data will be stored.

The above code snippet is enough to get your node running, but you need to extend it further to make it somewhat production-ready, which includes monitoring and proper logging, will look like the below:

[
"--data-path=/var/lib/besu/data",
"--host-allowlist=*",
"--rpc-http-enabled",
"--rpc-http-cors-origins=*",
"--rpc-http-api=ETH,NET,CLIQUE,DEBUG,MINER,NET,PERM,ADMIN,EEA,TXPOOL,PRIV,WEB3",
"--engine-jwt-secret=/var/lib/besu/jwtsecret.hex",
"--engine-host-allowlist=*",
"--engine-rpc-enabled=true",
"--sync-mode=X_SNAP",
"--data-storage-format=BONSAI",
"--rpc-http-enabled=true",
"--graphql-http-enabled=true",
"--metrics-enabled",
"--max-peers=20",
"--Xp2p-peer-lower-bound=20",
]

Two important parameters:

  1. --sync-mode=X_SNAP: From the official doc - "We recommend using snap sync over fast sync because snap sync can be faster by several days. We recommend using snap sync with the Bonsai data storage format for the fastest sync and lowest storage requirements."

  2. --engine-jwt-secret=/var/lib/besu/jwtsecret.hex: A hex-encoded bytes secret shared between consensus and execution clients.

    Run this command to create a secret token, you can name the file whatever you want, just make sure that you are passing the same key to both clients. It’s a must.

    openssl rand -hex 32 | tr -d "\n" > jwtsecret.hex

Monitoring and Logging

Follow this guide to run Prometheus via service. You can run Prometheus without a service but doing so will help in starting the Prometheus automatically after a system reboot. Open the config file, remove any existing code, and paste the below. Use Vim or Nano to edit the text.

sudo nano /etc/prometheus/prometheus.yml

global:
  scrape_interval: 15s
scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: "teku-dev"
    scrape_timeout: 10s
    metrics_path: /metrics
    scheme: http
    static_configs:
      - targets: ["localhost:8008"]

Install Grafana with a volume mount, and access it on http://localhost:3000. The default username and password are admin and admin.

Go to HomeConnectionsAdd new connection Data Source → Choose Prometheus → Under connection type "http://localhost:9090" - Click Save & Test.

Now let’s import the Grafana dashboard. Go to Home Dashboard → On the top left, click New and choose import from the dropdown → Provide 13457 and click load. Grafana gives you a quick overview of nodes.

For the Teku client, below, you can directly see the log by reading the log files (logs.log). But remember not to attach the running container to the console to see the logs, doing so could lead to stopping the container once the log terminal is closed. Instead, access the logs via docker logs. Besu sends the logs directly to the console which can be accessed by running the below command.

sudo docker compose logs -f {service_name-if available} or containername

We have client setup and monitoring, and now let's see the consensus client setting.

I went with Teku as their documentation is similar to Besu.

docker run -p 30303:30303/tcp -p 30303:30303/udp -p 5051:5051 --mount type=bind,source=/Users/user1/teku/,target=/var/lib/teku consensys/teku:latest --network=mainnet--data-base-path=/var/lib/teku --eth1-endpoint=http://102.10.10.1:8545 --rest-api-enabled=true

extended version of the command below.

[
  "--data-base-path=/var/lib/teku/data",
  "--ee-endpoint=http://besu_node:8551",
  "--ee-jwt-secret-file=/var/lib/teku/jwtsecret.hex",
  "--p2p-port=9000",
  "--rest-api-enabled=true",
  "--rest-api-docs-enabled=true",
  "--initial-state=https://sync-mainnet.beaconcha.in",
  "--metrics-enabled=true",
  "--log-destination=File",
  "--log-file=/var/lib/teku/logs",
]

Here we must use the same JWT secret being used in the execution client.

And use the --initial-state flag to sync your node from a recently finalized checkpoint state. A couple of community-managed endpoints are mentioned here.

The final touch was combining everything. Running and managing individual Docker images was a challenge, so decided to combine them with Docker Compose.

The final code looks something like this: You can copy and paste it into a Docker Compose file.


---
version: "3.4"
services:
  besu_node:
    environment:
      - "JAVA_OPTS=-Xmx8g" #5gb is also enough
    image: hyperledger/besu:24.1.1
    command:
      [
        "--data-path=/var/lib/besu/data",
        "--host-allowlist=*",
        "--rpc-http-enabled",
        "--rpc-http-cors-origins=*",
        "--rpc-http-api=ETH,NET,CLIQUE,DEBUG,MINER,NET,PERM,ADMIN,EEA,TXPOOL,PRIV,WEB3",
        "--engine-jwt-secret=/var/lib/besu/jwtsecret.hex",
        "--engine-host-allowlist=*",
        "--engine-rpc-enabled=true",
        "--sync-mode=X_SNAP",
        "--data-storage-format=BONSAI", #Bonsai is reccomended when using fast sync
        "--rpc-http-enabled=true",
        "--graphql-http-enabled=true",
        "--metrics-enabled",
        "--max-peers=20",
        "--Xp2p-peer-lower-bound=20",
      ]
    volumes:
      - type: bind
        source: /home/user/besu/  #this is a folder on your local system
        target: /var/lib/besu
    ports:
      # Map the p2p port(30303), RPC HTTP port(8545), and engine port (8551)
      - "8545:8545"
      - "8551:8551"
      - "30303:30303/tcp"
      - "30303:30303/udp"
      - "9545:9545"

  teku_node:
    environment:
      - "JAVA_OPTS=-Xmx8g"
    image: consensys/teku:latest
    command:
      [
        "--data-base-path=/var/lib/teku/data",
        "--ee-endpoint=http://besu_node:8551",
        "--ee-jwt-secret-file=/var/lib/teku/jwtsecret.hex",
        "--p2p-port=9000",
        "--rest-api-enabled=true",
        "--rest-api-docs-enabled=true",
        "--initial-state=https://sync-mainnet.beaconcha.in",
        "--metrics-enabled=true",
        "--log-destination=FILE",
        "--log-file=/var/lib/teku/data/logs/logs.log", # file to store the logs
      ]
    depends_on:
      - besu_node
    volumes:
      - type: bind # volume map type bind
        source: /home/user/teku/ #this is a folder on your local system
        target: /var/lib/teku
    ports:
      # Map the p2p port(9000) and REST API port(5051)
      - "9000:9000/tcp"
      - "9000:9000/udp"
      - "5051:5051"
      - "8008:8008"

Things to consider

  1. Important to complete port forwarding on your router so that nodes can communicate with each other and access Grafana and Prometheus. Port to open but not limited to: 5051, 9000, 9545, 30303, 8551, 8545

  2. If the firewall is enabled, make sure to allow the incoming traffic on those ports.

  3. Java installed

  4. Make sure to create the folder/directory being used in the code such as a logs file, or data storage file.

  5. JWT token must be the same between clients.

  6. If you want to run a node on ARM, follow this guide, suggested by u/minimalGravitas

  7. Read about client diversity, you can also find direct links to different clients on their website.

Help and support:

  1. Ethstaker Discord

  2. Ethstaker on Reddit

  3. A guide to choosing your clients and improving your setup as a solo staker by Haurog

  4. Check SSD recommendation here and here

  5. A must-read if you are interested in running a full node, additional doc on the same topic, ethstaker doc and Ethereum.org

Conclusion:

Excluding the majority of client, I chose the above because of their easy-to-follow documentation and Discord support, but it's still challenging to run and manage a node if one does not have in-depth knowledge of computer networking and is comfortable working with the console.

There is a learning curve, and I relatively feel more comfortable, but still, there is so much to learn and, I can only assume staking will add an extra layer of responsibility and concern from a security, troubleshooting and maintenance perspective. Before running a staking node, I would highly recommend running a test net node for a couple of months.

I am confident that running the docker-compose file will spin up both the execution and consensus client, given folders and files exist on the system.

As Nixo wrote, run your node on whatever hardware you have, apply for grants and share your learning. Their twitt was my motivation to write and share my learning.

As a side note, it’s also important to understand that running a non-staking node has no financial incentive.

Subscribe to weboftrust
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.