Interactive Solo Ethereum staking guide for Ubuntu OS

Complete guide to stake one as well as thousands of validators on multiple chains through a single staking node. Simply made, interactive, well explained. The guide on thsi webpage is focused on staking Ethereum.

Disclaimer

This guide is for informational purposes only. The author nor website owner does not guarantee accuracy of the information in this guide and is not responsible for any damages or losses incurred by following the guide.

Prerequisites for this Ethereum staking

  1. Staking Node for Ethereum staking, see

    options and guides for Staking Node
  2. Access to Staking Node Operating System

  3. Interest in staking

Securying Ubuntu OS

In the matter of security, you must think about the way you are going to connect to / access your node - see the guide below.

Upgrade & update on the latest software and security updates.

$ sudo apt -y update && sudo apt -y upgrade
$ sudo apt dist-upgrade && sudo apt autoremove
$ sudo reboot

You can also create a shell script that will do this either on manual request or a schedule, see Update and Restart Ubuntu server Utility.

Configure the Firewall

  • Install UFW, configurate deny state for incoming and allow state for outgoing traffic
    $ sudo apt install ufw
    $ sudo ufw default deny incoming
    $ sudo ufw default allow outgoing
  • Temporary till next step - Enable SSH port for remote access (process only if you are connected through the SSH = you are not connected with a keyboard and monitor right to the node)
    sudo ufw allow 22/tcp
  • Enable Firewall
    $ sudo ufw enable
  • Check Firewall Ports
    sudo ufw numbered

Managing the SSH access

  • SSH allows to connect to the server either from the local or remote network.
  • If you are going to connect your node locally only (= with monitor and keyboard connected right in the node), you do not need to install SSH or you can simply disable it, if is already installed.

Check, whether SSH is installed on the server

which sshd

This command should print directory of the SSH service. If it prints an empty response, SSH is not installed on the server and thus connecting to server over SSH is not possible. If required, SSH can be installed with following command:

sudo apt install openssh-server

With allowed SSH access, you must protect SSH access to your server from attackers. Based on your network confifuration, access may be possible from:

  • From any network (Your server has public IP)
  • From a local network only (Your server is behind nat)
  • From a VPN network the node is assigned to

Even if you have enabled access from a local netowk only (your node is behind NAT), you should still protect your SSH access as a potential attacker may use a compromised device in your local network to access your node. The defense consists in increasing the number of obstacles that must be overcome to access your node.

Before configuring security matters and connecting to your node, take note the basic rule to maintain also the security of the computer(s) you are going to use for connecting to your node (stealing the SSH keys) as well as other devices required for connection (stealing 2FA codes) etc.

  • Modify default 22 SSH port

    As port 22 is default port for SSH connections, it's the first port that a potential attacker tests. Change it to a different free port.

    1. Choose any number between 21 and 49151

      Choose a port number for SSH:
    2. Check whether the selected port for SSH is not already in use
      sudo ss -tulpn | grep ':22'
      • blank response = port is not in used
      • red text response, the port is already in used. Check availability of a different port number in such case.
    3. Change SSH port from default 22 to 22 in the SSH config file
      1. Open sshd_config config file
        sudo nano /etc/ssh/sshd_config
      2. Find mark Port, usually Port 22. The mark specifies currently port used for SSH access.

        Rewrite the port value for Port

      3. Press CTRL + X then Y then ENTER to save and exit the config file.
    4. Enable the Port 1024 for SSH/TCP connection
      sudo ufw allow 1024/tcp
    5. Restart the SSH service to reflect the changes.
      sudo systemctl restart ssh

      After the restart, you will not able to connect through the SSH over port 22 anymore. Be sure you are connecting over the 1024 next time.

    6. Disable the default 22 port for SSH/TCP connection
      sudo ufw deny 22/tcp
    7. Check your port settings if needed
      sudo ufw status numbered
  • Configure SSH keys

    By default, SSH connections can be made using a combo of username and password. As password is usually somewhat "short" and thus susceptible to brute-force attacks, key loggers attacks and so on. This is why SSH keys significantly enhances the security of the login process.

    SSH keys step by step guide.
  • Configuring 2FA authentization

    2FA (2 Factor authentization) comes with additional code you must provide to access your node. You may know 2FA from crypto exchanges. In the same way you can protect loging to your node.

    2FA Google Authentication activation guide.
  • Configuring Brute-force & DDoS protection

    To defend against Brute Force and DDoS attacks, one can monitor incoming connections and block IP addresses that repeatedly attempt to log in with incorrect credentials. Installing the Fail2Ban package can assist with this.

    Guide to activate Fail2Ban.

Securying remote access tips

  • Staking node is accessible from public IP:
    • If you do not need o connect to your node from remote networks, move your node behind the router that prevents accessing the node.
    • If you want to keep this feature, you should still consider move the node behind the router, set VPN on the router, and when connecting to the node, firstly connect to the router VPN and then connect the node from "local" network through its local IP.
  • Staking node is not accessible from public IP:
    • If you need connecting your node from remote networks, you must either set a VPN, such as Tailscale (either on the server itself or any other device in your local network), or buy public IP from your ISP and follow the points for server accessible from the public IP.

If you have SSH installed and running on your server, you must either disable ports for SSH traffic, disable SSH or remove it. If SSH is not installed on your machine, you can skip this step - ssh access is not possible already.

  • Option 1: Stop and disable the ssh service

    sudo systemctl stop ssh
    sudo systemctl disable ssh

    If preferred, you can remove the SSH server client from the machine

    sudo apt remove openssh-server
  • Option 2: Disable traffic on SSH port

    Check 22/tcp port for enabled traffic with command

    sudo ufw status numbered

    Note: default 22 port could be changed, as well as could not be enabled. If there's any tcp traffic enabled, disable it. Code below is for default SSH port 22.

    sudo ufw deny 22/tcp

Consider installing and setting VPN to hide your public IP

VPN allows the server to access the internet through an intermediary in a form of a VPN server. In such case, your server's IP address (and location) is hidden behind the VPN server IP address. The disadvantage is the potential instability of the VPN server, in terms of connection speed and possible crashes into offline state.

Complete guide to install, configurate and activate Mullvad VPN on Ubuntu server.

Note: If you need to have active Mullvad and Tailscale simultaneously, follow a guide for setting rules for netfilter.

Check / set basic config for your node machine

  • Check, you are not logged in as root. If so, create a new user with sudo, see section Staking on rented hardware
  • Check a swap space
    free -h

    If there's no swap space created on your node, configurate a swap space.

  • Check timedatectl service for option to synchronize time

    Check current state:

    timedatectl status
  • Create downloads directory in your machine
    mkdir ~/downloads

    This folder will be used for downloading clients

Generate Client Authentication Secret for ethereum

  • Create a new directory for jwtsecret files
    sudo mkdir -p /var/lib/jwtsecret
  • Generate the JWT file using the openssl cryptography software library.
    openssl rand -hex 32 | sudo tee /var/lib/jwtsecret/ethereum.hex > /dev/null
  • Check the generated authentication secret
    $ nano /var/lib/jwtsecret/ethereum.hex
    Press CTRL + X to exit the config file.

Install and configurate preferred execution client

Installing Nethermind client

Nethermind documentation: https://docs.nethermind.io/

  1. Find the latest stable version of Nethermind on Github

  2. Download Nethermind version 1.29.1-dfea5240 to your node

    cd ~/downloads && curl -LO https://github.com/NethermindEth/nethermind/releases/download/1.29.1/nethermind-1.29.1-dfea5240-linux-x64.zip
  3. Install package for unzipping

    sudo apt-get install -y unzip
  4. Unzip the downloaded file

    unzip nethermind-1.29.1-dfea5240-linux-x64 -d nethermind
  5. Copy the client to /usr/local/bin/

    sudo cp -a nethermind /usr/local/bin/nethermind
  6. Remove downloaded files

    cd ~/downloads && rm nethermind-1.29.1-dfea5240-linux-x64.zip && rm -r nethermind

Create a system user and data directory for Nethermind service

  • Create a user

    :
    sudo useradd --system --no-create-home --shell /bin/false eth-nethermind
  • Create a folder for Nethermind data on Ethereum chain

    :
    sudo mkdir -p /var/lib/ethereum/nethermind
  • Set access permission and ownership for the Nethermind data folder

    sudo chown -R eth-nethermind:eth-nethermind /var/lib/ethereum/nethermind

Configurate & Run Nethermind service

  • Choose ports for communication

    Change the default ports below if you are going to stake on more chains simultaneously (e.g. Ethereum and Gnosis at once) on the same machine. If you are going to stake ethereum only, you can keep the default ports. If you are changing the default ports, be sure that the newly selected port is not already in used. A port in used may be checked with following code:

    ss -tuln | grep ':PORT'
    • If it returns empty response, the port is free and can be used.

    Ports selection

    • (Default port: 30303)
    • (Default port: 8545)
    • (Default port: 8551)

    If needed, check JSON RPC server and fundamentals in Nethermind documentation.

  • Enable port for P2P communication (execution client)

    To allow execution client synchronization, there's need to enable P2P traffic to TCP (allows the node to connect to peers) and UDP (allows node discovery) port 30303. It may be done with following UFW setup:

    $ sudo ufw allow 30303
  • Create configuration file for Nethermind service

    1. Open Nethermind configuration file

      sudo nano /etc/systemd/system/eth-nethermind.service
    2. Copy the configuration below into the file. If needed, check flags documentation.

      [Unit]
      Description=Nethermind Execution Client (Ethereum Mainnet)
      After=network.target
      Wants=network.target
      
      [Service]
      User=eth-nethermind
      Group=eth-nethermind
      Type=simple
      Restart=always
      RestartSec=5
      WorkingDirectory=/var/lib/ethereum/nethermind
      Environment="DOTNET_BUNDLE_EXTRACT_BASE_DIR=/var/lib/ethereum/nethermind"
      ExecStart=/usr/local/bin/nethermind/nethermind \
        --config mainnet \
        --datadir /var/lib/ethereum/nethermind \
        --Sync.SnapSync true \
        --Sync.AncientBodiesBarrier 11052984 \
        --Sync.AncientReceiptsBarrier 11052984 \
        --JsonRpc.JwtSecretFile /var/lib/jwtsecret/ethereum.hex \
        --Network.P2PPort 30303 \
        --Network.DiscoveryPort 30303 \
        --JsonRpc.EnginePort 8551 \
        --JsonRpc.Port 8545
      
      [Install]
      WantedBy=default.target
    3. Press CTRL + X then Y then ENTER to save and exit the config file.
  • Start the Nethermind service

    sudo systemctl daemon-reload
    sudo systemctl start eth-nethermind
  • Check the service

    systemctl status eth-nethermind
    journalctl -fu eth-nethermind

    If you see message "Waiting for Forkchoice message from Consensus Layer to set fresh pivot block", you can move on a Consensis Client setup.

  • Start the service automatically on system startup

    sudo systemctl enable eth-nethermind

Installing Erigon client

Erigon documentation: https://erigon.gitbook.io/erigon

  1. Find the latest stable version of Erigon on Github

  2. Download Erigon version 2.60.10

    cd ~/downloads && curl -LO https://github.com/erigontech/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_amd64v2.tar.gz
  3. Verify hash of donwnloaded file

    Get hash of downloaded file and compare it with official hashes
    sha256sum erigon_v2.60.10_linux_amd64v2.tar.gz
    And check it compare to the provided hash for the file from https://github.com/erigontech/erigon/releases/download/v2.60.10/erigon_v2.60.10_checksums.txt (Note: The link links at 2.60.10 version )
  4. Extract the downloaded package

    tar xvf erigon_v2.60.10_linux_amd64v2.tar.gz
  5. Copy extracted Erigon library

    sudo cp -a erigon_v2.60.10_linux_amd64v2 /usr/local/bin/erigonlib
  6. Remove downloaded files

    cd ~/downloads && rm -r erigon_v2.60.10_linux_amd64v2.tar.gz && rm -r erigon_v2.60.10_linux_amd64v2

Create a system user and data directory for Erigon service

  • Create a user

    :
    sudo useradd --system --no-create-home --shell /bin/false eth-erigon
  • Create a folder for Erigon data on ethereum network

    :
    sudo mkdir -p /var/lib/ethereum/erigon
  • Set access permission and ownership for the Erigon data folder

    sudo chown -R eth-erigon:eth-erigon /var/lib/ethereum/erigon

Configurate & Run Erigon Service

  • Choose ports for communication

    Change the default ports below if you are going to stake on more chains simultaneously (e.g. Ethereum and Gnosis at once) on the same machine. If you are going to stake ethereum only, you can keep the default ports. If you are changing the default ports, be sure that the newly selected port is not already in used. A port in used may be checked with following code:

    ss -tuln | grep ':PORT'
    • If it returns empty response, the port is free and can be used.

    Ports selection

    • (Default port: 30303)
    • (Default port: 8545)
    • (Default port: 8551)
  • Enable port for P2P communication (execution client)

    To allow execution client synchronization, there's need to enable P2P traffic to TCP (allows the node to connect to peers) and UDP (allows node discovery) port 30303. It may be done with following UFW setup:

    $ sudo ufw allow 30303
  • Create configuration file for Erigon service

    1. Open configuration file
      sudo nano /etc/systemd/system/eth-erigon.service
    2. Copy the configuration below into the file
      [Unit]
      Description=Erigon Execution Client (Ethereum Mainnet)
      After=network.target
      Wants=network.target
      [Service]
      User=eth-erigon
      Group=eth-erigon
      Type=simple
      Restart=always
      RestartSec=5
      ExecStart=/usr/local/bin/erigonlib/erigon \
        --chain=mainnet \
        --datadir=/var/lib/ethereum/erigon \
        --authrpc.jwtsecret=/var/lib/jwtsecret/ethereum.hex \
      #  --externalcl \
        --prune=htcr
      #  --private.api.addr= \
      #  --prune.r.before=11052984 
      [Install]
      WantedBy=default.target
    3. Press CTRL + X then Y then ENTER to save and exit the config file.
  • Start the service

    sudo systemctl daemon-reload
    sudo systemctl start eth-erigon
  • Check the service

    systemctl status eth-erigon
    journalctl -fu eth-erigon
  • Start the service on system startup

    sudo systemctl enable eth-erigon

Soon

Soon

Consensus client

Install Consensus client

  1. Find the latest stable version of Lighthouse on Github

  2. Download Lighthouse version 5.3.0 to your node

    cd ~/downloads && curl -LO https://github.com/sigp/lighthouse/releases/download/v5.3.0/lighthouse-v5.3.0-x86_64-unknown-linux-gnu.tar.gz

    Extract downloaded file

    $ tar xvf lighthouse-v5.3.0-x86_64-unknown-linux-gnu.tar.gz
  3. Replace old Lighthouse client for new
    $ sudo cp ~/downloads/lighthouse /usr/local/bin
  4. Remove downloaded files
    $ cd ~/downloads && rm lighthouse-v5.3.0-x86_64-unknown-linux-gnu.tar.gz && rm -r lighthouse

Configurate Lighthouse Beacon service

  1. Create a user for lighthouse beacon :
    $ sudo useradd --system --no-create-home --shell /bin/false eth-lighthousebeacon
  2. Create a directory for data :
    $ sudo mkdir -p /var/lib/ethereum/lighthouse/beacon
  3. Set permission for accessing the directory
    $ sudo chown -R eth-lighthousebeacon:eth-lighthousebeacon /var/lib/ethereum/lighthouse/beacon
  • Create configuration file for Lighthouse Beacon service

    Open Lighthouse Beacon configuration file

    $ sudo nano /etc/systemd/system/eth-lighthousebeacon.service

    Copy the configuration below into the file. If needed, check flags documentation.

    [Unit]
    Description=Lighthouse Consensus Client BN (Ethereum Mainnet)
    Wants=network-online.target
    After=network-online.target
    
    [Service]
    User=eth-lighthousebeacon
    Group=eth-lighthousebeacon
    Type=simple
    Restart=always
    RestartSec=5
    ExecStart=/usr/local/bin/lighthouse bn \
      --network mainnet \
      --datadir /var/lib/ethereum/lighthouse \
      --http \
      --execution-endpoint http://127.0.0.1:8551 \
      --execution-jwt /var/lib/jwtsecret/ethereum.hex \
    #  --checkpoint-sync-url https://mainnet.checkpoint.sigp.io \
      --checkpoint-sync-url=https://beaconstate.info \
      --port 9000 \
      --port6 9090 \
    #  --discovery-port 9000 \
      --quic-port 9001 \
      --quic-port6 9091 \
      --http-port 5052
    
    [Install]
    WantedBy=multi-user.target

    Press CTRL + X then Y then ENTER to save and exit the config file.

  • Load changes made in config files to the system

    $ sudo systemctl daemon-reload
  • Start the service
    $ sudo systemctl start eth-lighthousebeacon
  • Check the state
    $ systemctl status eth-lighthousebeacon
    $ journalctl -fu eth-lighthousebeacon
  • Activate service to start automatically
    $ sudo systemctl enable eth-lighthousebeacon
  1. Installing NodeJS through the Node Version Manager

    Node Version Manager (NVM) is a piece of shell code that allows you to easily install and maintain different versions of Node.js and its associated packages.

    1. Check latest verision of NVM on GitHub.
    2. View code of NVM ver 0.39.4

      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh
    3. Install NVM

      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh | bash

      NVM will be installed with permissions of a user that processing that request (you). NVM is installed to user account, specifically to "~/.bashrc" directory.

    4. source/reload nvm for an option to use it

      source ~/.bashrc
    5. Check available Node.js versions

      nvm list-remote
      Selected version: v
    6. Install requested Node.js version

      nvm install v20.11.0

      Node.js is installed with permissions of a user that processing that request (you)

    7. Show active Node.js version in use

      node -v

      If o version is selected, use nvm use 20.11.0

  2. Install build-essential tools

    sudo apt-get install build-essential -y
  3. Install Yarn

    corepack enable
    corepack prepare yarn@stable --activate
    yarn help
  4. Build Lodestar

    • Download latest Lodestar client from GitHub

      cd ~/downloads && git clone -b stable https://github.com/chainsafe/lodestar.git
    • Install yarn

      cd lodestar && yarn install
    • Build Lodestart client

      yarn run build
    • Check builded Lodestar version

      ./lodestar -v
  5. Copy new production client to /usr/local/bin directory

    sudo cp -a ~/downloads/lodestar /usr/local/bin

Configurate Lodestar Beacon service

  1. Configuring lodestarbeacon service user and data directory

    • Create a service user

      :
      $ sudo useradd --system --no-create-home --shell /bin/false eth-lodestarbeacon
    • Enable eth-lodestarbeacon user access NodeJs

      :
      sudo usermod -aG myserveruser eth-lodestarbeacon
    • Create a directory for Lodestar Beacon data

      :
      sudo mkdir -p /var/lib/ethereum/lodestar/beacon
    • Set directory ownership

      sudo chown -R eth-lodestarbeacon:eth-lodestarbeacon /var/lib/ethereum/lodestar/beacon
  2. Create configuration file for the Lodestar beacon service

    • Open the configuration file

      sudo nano /etc/systemd/system/eth-lodestarbeacon.service
    • Copy following configuration to the file

      :
      This can be get with command $ node version

      [Unit]
      Description=Lodestar Consensus Beacon Client (Ethereum mainnet)
      Wants=network-online.target
      After=network-online.target
      [Service]
      User=eth-lodestarbeacon
      Type=simple
      Restart=always
      RestartSec=5
      WorkingDirectory=/usr/local/bin/lodestar
      Environment="PATH=/home/myserveruser/.nvm/versions/node/v20.11.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
      ExecStart=/usr/local/bin/lodestar/lodestar beacon \
        --network mainnet \
        --dataDir /var/lib/ethereum/lodestar/beacon \
        --execution.urls http://127.0.0.1:8551 \
        --jwt-secret /var/lib/jwtsecret/ethereum.hex \
        --port 9000 \
        --port6 9090
        #--suggestedFeeRecipient 0x.........................
      [Install]
      WantedBy=multi-user.target

      Check all available flags.

    • Press CTRL + X then Y then ENTER to save and exit the config file.
  3. Reload daemon

    sudo systemctl daemon-reload
  4. Run the service

    sudo systemctl start eth-lodestarbeacon
  5. Monitor the running lodestar Beacon service

    systemctl status eth-lodestarbeacon
    journalctl -fu eth-lodestarbeacon
  6. Enable auto start on server statup

    sudo systemctl enable eth-lodestarbeacon
  1. Install Java

    cd ~/downloads && wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.deb
    sudo apt install ./jdk-21_linux-x64_bin.deb
    java --version
  2. Find the latest stable version of Teku on Github

    Find latest Teku version at Github: https://github.com/Consensys/teku/releases
    Write latest stable Teku version:

    This will update the url links in the guide below.

  3. Download the latest Teku version

    cd ~/downloads && curl -LO https://artifacts.consensys.net/public/teku/raw/names/teku.tar.gz/versions/24.10.3/teku-24.10.3.tar.gz
  4. Unpack the downloaded Teku version

    $ tar xvf teku-24.10.3.tar.gz
  5. Copy the Teku Library

    sudo cp -a ~/downloads/teku-24.10.3 /usr/local/bin/teku
  6. Remove downloaded files

    cd ~/downloads && rm teku-24.10.3.tar.gz && rm -r teku-24.10.3

Configurate Teku Beacon service

  • Create a user

    :
    sudo useradd --system --no-create-home --shell /bin/false eth-tekubeacon
  • Create a folder for Tekubeacon data on Ethereum chain

    :
    sudo mkdir -p /var/lib/ethereum/tekubeacon
  • Set access permission and ownership for the Nethermind data folder

    sudo chown -R eth-tekubeacon:eth-tekubeacon /var/lib/ethereum/tekubeacon

Configurate & Run Tekubeacon service

  • Create configuration file for Tekubeacon service

    1. Open Tekubeacon configuration file

      sudo nano /etc/systemd/system/eth-tekubeacon.service
    2. Copy configuration

      [Unit]
      Description=Teku Consensus Client (Ethereum Mainnet)
      Wants=network-online.target
      After=network-online.target
      [Service]
      User=eth-tekubeacon
      Group=eth-tekubeacon
      Type=simple
      Restart=always
      RestartSec=5
      Environment="JAVA_OPTS=-Xmx5g"
      Environment="TEKU_OPTS=-XX:-HeapDumpOnOutOfMemoryError"
      ExecStart=/usr/local/bin/teku/bin/teku \
        --network=mainnet \
        --data-path=/var/lib/ethereum/tekubeacon \
        --ee-endpoint=http://127.0.0.1:8551 \
        --ee-jwt-secret-file=/var/lib/jwtsecret/ethereum.hex \
        --metrics-enabled=true \
        --rest-api-enabled=true \
        --validators-proposer-default-fee-recipient= 0x... \
        #--checkpoint-sync-url= \
        --initial-state=https://checkpoint.gnosischain.com/eth/v2/debug/beacon/states/finalized
      [Install]
      WantedBy=multi-user.target
    3. Press CTRL + X then Y then ENTER to save and exit the config file.
  • Load changes

    sudo systemctl daemon-reload
  • Start the Beacon chain service

    sudo systemctl start eth-tekubeacon
  • Check the service

    systemctl status eth-tekubeacon
    journalctl -fu eth-tekubeacon
  • Start the service automatically on system startup

    sudo systemctl enable eth-tekubeacon

Continue with your Staking option preference