Guide to Staking on Ethereum (Ubuntu/Lighthouse)

Warnings

Disclaimer

Acknowledgements

Support

Prerequisites

  • Ubuntu server v20.04 (LTS) amd64 installed and running on a local computer or in the cloud. A locally running computer is encouraged for greater decentralization.
  • MetaMask crypto wallet web browser extension installed and configured on a computer with a desktop (Mac, Windows, Linux, etc.) and a web browser (Brave, Safari, FireFox, etc.).

Testnet to Mainnet

Requirements

  • A relatively modern multi-core CPU.
  • 8GB RAM (16GB is better, and required in some cases).
  • An SSD (NVMe is better) of at least 1TB (2TB is strongly recommended).
  • A stable internet connection with sufficient download speed and monthly data allowance.

Activation Queue

Overview

  • Generate the staking Deposit Data and Validator Keystore(s)
  • Prepare the Ubuntu Server (updates, firewall, security, etc.)
  • Set up an Execution Client node and sync it with the Ethereum mainnet
  • Set up the Lighthouse Consensus Client and sync with other Beacon Nodes
  • Deposit 32 ETH to activate the staking Validator(s)

Step 1 — Generate Staking Data

Download the Deposit Tool (Staking Deposit CLI)

$ cd ~
$ curl -LO https://github.com/ethereum/staking-deposit-cli/releases/download/v2.3.0/staking_deposit-cli-76ed782-linux-amd64.tar.gz
$ tar xvf staking_deposit-cli-76ed782-linux-amd64.tar.gz
$ mv staking_deposit-cli-76ed782-linux-amd64 staking-deposit-cli
$ rm staking_deposit-cli-76ed782-linux-amd64.tar.gz # <-- Clean up
$ cd staking-deposit-cli

Prepare to Run the Deposit Tool (Staking Deposit CLI)

Run the Deposit Tool (Staking Deposit CLI)

$ sudo ./deposit new-mnemonic --num_validators 2 --chain mainnet
deposit.exe new-mnemonic --num_validators 2 --chain mainnet
  • The deposit_data-[timestamp].json file contains the public key(s) for the validator(s) and information about the staking deposit. This file will be used to complete the ETH staking deposit process later in this guide.
  • The keystore-[..].json files contain the encrypted validator signing key. There is one keystore file per validator that you are funding. These will be imported into the Consensus Client for use during validation operations.
  • You will copy the files over to your Ubuntu server (if not already there) later in this guide.
  • If you lose or accidentally delete the files it is possible to regenerate them using the Staking Deposit CLI tool and your mnemonic via the existing-mnemonic command. More information here.

Final Steps

Step 2 — Create the Server User

# adduser <yourusername>
# usermod -aG sudo <yourusername>
# rsync --archive --chown=<yourusername>:<yourusername> ~/.ssh /home/<yourusername>

Step 3 — Update the Server

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

Step 4 — Secure the Server

Modify the Default SSH Port

$ sudo ss -tulpn | grep ':YourSSHPortNumber'
$ sudo ss -tulpn | grep ':6673'
$ sudo nano /etc/ssh/sshd_config
Port <YourSSHPortNumber>
$ sudo systemctl restart ssh

Configure the Firewall

$ sudo apt install ufw
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
$ sudo ufw allow YourSSHPortNumber/tcp
$ sudo ufw allow 6673/tcp
$ sudo ufw deny 22/tcp
$ sudo ufw allow 30303
$ sudo ufw allow 9000

Enable the Firewall

$ sudo ufw enable
$ sudo ufw status numbered

Step 5 — Create a Swap Space

$ free -h
RAM     Swap Size
8GB 3GB
12GB 3GB
16GB 4GB
24GB 5GB
32GB 6GB
64GB 8GB
128GB 11GB
$ df -h
$ sudo fallocate -l 3G /swapfile
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ free -h
$ sudo cp /etc/fstab /etc/fstab.bak
$ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
$ sudo sysctl vm.swappiness=10
$ sudo sysctl vm.vfs_cache_pressure=50
$ sudo nano /etc/sysctl.conf
vm.swappiness=10
vm.vfs_cache_pressure=50

Step 6 — Configure Timekeeping

$ timedatectl
$ sudo timedatectl set-ntp on

Step 7 — Generate Client Authentication Secret

$ sudo mkdir -p /var/lib/jwtsecret
$ openssl rand -hex 32 | sudo tee /var/lib/jwtsecret/jwt.hex > /dev/null
$ sudo nano /var/lib/jwtsecret/jwt.hex

Step 8 — Configure the Execution Client

Install the Execution Client — Besu

$ cd ~
$ curl -LO https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.6/besu-22.7.6.tar.gz
$ tar xvf besu-22.7.6.tar.gz
$ sudo cp -a besu-22.7.6 /usr/local/bin/besu
$ rm besu-22.7.6.tar.gz
$ rm -r besu-22.7.6
$ sudo apt -y install default-jre
$ sudo apt install -y libjemalloc-dev
$ sudo useradd --no-create-home --shell /bin/false besu
$ sudo mkdir -p /var/lib/besu
$ sudo chown -R besu:besu /var/lib/besu
$ sudo nano /etc/systemd/system/besu.service
[Unit]
Description=Besu Execution Client (Mainnet)
Wants=network-online.target
After=network-online.target
[Service]
User=besu
Group=besu
Type=simple
Restart=always
RestartSec=5
Environment="JAVA_OPTS=-Xmx4g"
ExecStart=/usr/local/bin/besu/bin/besu \
--network=mainnet \
--sync-mode=X_SNAP \
--data-path=/var/lib/besu \
--data-storage-format=BONSAI \
--engine-jwt-secret=/var/lib/jwtsecret/jwt.hex
[Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl start besu
$ sudo systemctl status besu
$ sudo journalctl -fu besu
$ sudo systemctl enable besu

Install the Execution Client — Erigon

$ cd ~
$ curl -LO https://go.dev/dl/go1.19.linux-amd64.tar.gz
$ sudo rm -rf /usr/local/go
$ sudo tar -C /usr/local -xzf go1.19.linux-amd64.tar.gz
$ echo 'PATH="$PATH:/usr/local/go/bin"' >> $HOME/.profile
$ source $HOME/.profile
$ rm go1.19.linux-amd64.tar.gz
$ sudo apt-get install -y build-essential
$ cd ~
$ curl -LO https://github.com/ledgerwatch/erigon/archive/refs/tags/v2.27.0.tar.gz
$ tar xvf v2.27.0.tar.gz
$ cd erigon-2.27.0
$ make erigon
$ cd ~
$ sudo cp -a erigon-2.27.0 /usr/local/bin/erigon
$ rm v2.27.0.tar.gz
$ rm -r erigon-2.27.0
$ sudo useradd --no-create-home --shell /bin/false erigon
$ sudo mkdir -p /var/lib/erigon
$ sudo chown -R erigon:erigon /var/lib/erigon
$ sudo nano /etc/systemd/system/erigon.service
[Unit]
Description=Erigon Execution Client (Mainnet)
After=network.target
Wants=network.target
[Service]
User=erigon
Group=erigon
Type=simple
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/erigon/build/bin/erigon \
--chain=mainnet \
--datadir=/var/lib/erigon \
--authrpc.jwtsecret=/var/lib/jwtsecret/jwt.hex \
--externalcl \
--private.api.addr= \
--prune.r.before=11052984 \
--prune htc
[Install]
WantedBy=default.target
$ /usr/local/bin/erigon/build/bin/./erigon --help
$ sudo systemctl daemon-reload
$ sudo systemctl start erigon
$ sudo systemctl status erigon
$ sudo journalctl -fu erigon
$ sudo systemctl enable erigon
$ cd ~
$ curl -LO https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.10.25-69568c55.tar.gz
$ tar xvf geth-linux-amd64-1.10.25-69568c55.tar.gz
$ cd geth-linux-amd64-1.10.25-69568c55
$ sudo cp geth /usr/local/bin
$ cd ~
$ rm geth-linux-amd64-1.10.25-69568c55.tar.gz
$ rm -r geth-linux-amd64-1.10.25-69568c55
$ sudo useradd --no-create-home --shell /bin/false geth
$ sudo mkdir -p /var/lib/geth
$ sudo chown -R geth:geth /var/lib/geth
$ sudo nano /etc/systemd/system/geth.service
[Unit]
Description=Geth Execution Client (Mainnet)
After=network.target
Wants=network.target
[Service]
User=geth
Group=geth
Type=simple
Restart=always
RestartSec=5
TimeoutStopSec=600
ExecStart=/usr/local/bin/geth \
--mainnet \
--datadir /var/lib/geth \
--authrpc.jwtsecret /var/lib/jwtsecret/jwt.hex
[Install]
WantedBy=default.target
$ sudo systemctl daemon-reload
$ sudo systemctl start geth
$ sudo systemctl status geth
$ sudo journalctl -fu geth
$ sudo systemctl enable geth

Install the Execution Client — Nethermind

$ cd ~
$ curl -LO https://github.com/NethermindEth/nethermind/releases/download/1.14.3/nethermind-linux-amd64-1.14.3-7074612-20221003.zip
$ sudo apt-get install -y unzip
$ unzip nethermind-linux-amd64-1.14.3-7074612-20221003.zip -d nethermind
$ sudo cp -a nethermind /usr/local/bin/nethermind
$ rm nethermind-linux-amd64-1.14.3-7074612-20221003.zip
$ rm -r nethermind
$ sudo apt-get update
$ sudo apt-get install libsnappy-dev libc6-dev libc6 unzip -y
$ sudo useradd --no-create-home --shell /bin/false nethermind
$ sudo mkdir -p /var/lib/nethermind
$ sudo chown -R nethermind:nethermind /var/lib/nethermind
$ sudo nano /etc/systemd/system/nethermind.service
[Unit]
Description=Nethermind Execution Client (Mainnet)
After=network.target
Wants=network.target
[Service]
User=nethermind
Group=nethermind
Type=simple
Restart=always
RestartSec=5
WorkingDirectory=/var/lib/nethermind
Environment="DOTNET_BUNDLE_EXTRACT_BASE_DIR=/var/lib/nethermind"
ExecStart=/usr/local/bin/nethermind/Nethermind.Runner \
--config mainnet \
--datadir /var/lib/nethermind \
--Sync.SnapSync true \
--Sync.AncientBodiesBarrier 11052984 \
--Sync.AncientReceiptsBarrier 11052984 \
--JsonRpc.JwtSecretFile /var/lib/jwtsecret/jwt.hex
[Install]
WantedBy=default.target
$ sudo systemctl daemon-reload
$ sudo systemctl start nethermind
$ sudo systemctl status nethermind
$ sudo journalctl -fu nethermind
$ sudo systemctl enable nethermind

Step 9 — Install the Lighthouse Consensus Client

$ cd ~
$ curl -LO https://github.com/sigp/lighthouse/releases/download/v3.1.0/lighthouse-v3.1.0-x86_64-unknown-linux-gnu.tar.gz
$ tar xvf lighthouse-v3.1.0-x86_64-unknown-linux-gnu.tar.gz
$ sudo cp lighthouse /usr/local/bin
$ rm lighthouse-v3.1.0-x86_64-unknown-linux-gnu.tar.gz
$ rm lighthouse

Step 10 — Import the Validator Keys

Copy the Validator Keystore Files to the Server

$ sudo mkdir -p $HOME/staking-deposit-cli/validator_keys
$ sudo chown -R <yourusername>:<yourusername> $HOME/staking-deposit-cli/validator_keys

Import the Validator Keystore Files into Lighthouse

$ sudo mkdir -p /var/lib/lighthouse
$ sudo /usr/local/bin/lighthouse --network mainnet account validator import --directory $HOME/staking-deposit-cli/validator_keys --datadir /var/lib/lighthouse

Step 11 — Configure the Beacon Node Service

Set up the Account

$ sudo useradd --no-create-home --shell /bin/false lighthousebeacon

Set up the Directories and the Permissions

$ sudo mkdir -p /var/lib/lighthouse/beacon
$ sudo chown -R lighthousebeacon:lighthousebeacon /var/lib/lighthouse/beacon

Create and Configure the Service

$ sudo nano /etc/systemd/system/lighthousebeacon.service
[Unit]
Description=Lighthouse Consensus Client BN (Mainnet)
Wants=network-online.target
After=network-online.target
[Service]
User=lighthousebeacon
Group=lighthousebeacon
Type=simple
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/lighthouse bn \
--network mainnet \
--datadir /var/lib/lighthouse \
--http \
--execution-endpoint http://127.0.0.1:8551 \
--execution-jwt /var/lib/jwtsecret/jwt.hex \
--checkpoint-sync-url CheckpointSyncURL
[Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl start lighthousebeacon
$ sudo systemctl status lighthousebeacon
$ sudo journalctl -fu lighthousebeacon
$ sudo systemctl enable lighthousebeacon

Step 12 — Configure the Validator Service

Set up the Validator Node Account and Directory

$ sudo useradd --no-create-home --shell /bin/false lighthousevalidator
$ sudo chown -R lighthousevalidator:lighthousevalidator /var/lib/lighthouse/validators

Create and Configure the Service

$ sudo nano /etc/systemd/system/lighthousevalidator.service
[Unit]
Description=Lighthouse Consensus Client VC (Mainnet)
Wants=network-online.target
After=network-online.target
[Service]
User=lighthousevalidator
Group=lighthousevalidator
Type=simple
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/lighthouse vc \
--network mainnet \
--datadir /var/lib/lighthouse \
--suggested-fee-recipient FeeRecipientAddress \
--graffiti "<yourgraffiti>"
[Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl start lighthousevalidator
$ sudo systemctl status lighthousevalidator
$ sudo journalctl -fu lighthousevalidator
$ sudo systemctl enable lighthousevalidator

Step 13 — Fund the Validator Keys

Check the Status of Your Validator Deposits

  1. Copy your MetaMask (or other) wallet address used to make the deposit.
  2. Go here: https://beaconcha.in/
  3. Search for your key(s) using your wallet address.

Final Remarks and Recommended Next Steps

Next steps

  • Reboot your machine and make sure all services come back up
  • Understand how to update the client and server software
  • Use htop, df -h, or ncdu / to monitor resources on the local machine
  • Review Appendix H — Manage Systemd Journal Logs to manage log size
  • Get familiar with beaconcha.in so you can monitor your validators
  • Use the beaconcha.in mobile app to monitor your validators
  • Check my testnet guides for details on setting up Grafana monitoring
  • Join the Ethstaker and Lighthouse Discord for important notifications
  • Share feedback on Discord (Somer#0753), Twitter, or Reddit
  • Help others with their setup on the Ethstaker Discord
  • Share this guide with your friends!
  • Tips appreciated: somer.eth or Gitcoin Grants

Further Reading

Appendix A — Updating Besu

$ cd ~
$ curl -LO https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.6/besu-22.7.6.tar.gz
$ sudo systemctl stop besu
$ tar xvf besu-22.7.6.tar.gz
$ sudo rm -r /usr/local/bin/besu # <-- Remove the old files
$ sudo cp -a besu-22.7.6 /usr/local/bin/besu
$ sudo systemctl start besu
$ sudo systemctl status besu # <-- Check for errors
$ sudo journalctl -fu besu # <-- Monitor
$ sudo journalctl -fu lighthousebeacon # <-- Monitor
$ cd ~
$ rm besu-22.7.6.tar.gz
$ rm -r besu-22.7.6

Appendix B — Updating Erigon

$ cd ~
$ curl -LO https://github.com/ledgerwatch/erigon/archive/refs/tags/v2.27.0.tar.gz
$ tar xvf v2.27.0.tar.gz
$ cd erigon-2.27.0
$ make erigon
$ sudo systemctl stop erigon
$ cd ~
$ sudo rm -r /usr/local/bin/erigon # <-- Remove the old files
$ sudo cp -a erigon-2.27.0 /usr/local/bin/erigon
$ sudo systemctl start erigon
$ sudo systemctl status erigon # <-- Check for errors
$ sudo journalctl -fu erigon <-- Monitor
$ sudo journalctl -fu lighthousebeacon # <-- Monitor
$ rm v2.27.0.tar.gz
$ rm -r erigon-2.27.0

Appendix C — Updating Geth

$ cd ~
$ curl -LO https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.10.25-69568c55.tar.gz
$ sudo systemctl stop geth
$ tar xvf geth-linux-amd64-1.10.25-69568c55.tar.gz
$ cd geth-linux-amd64-1.10.25-69568c55
$ sudo cp geth /usr/local/bin
$ sudo systemctl start geth
$ sudo systemctl status geth # <-- Check for errors
$ sudo journalctl -fu geth # <-- Monitor
$ sudo journalctl -fu lighthousebeacon # <-- Monitor
$ cd ~
$ rm geth-linux-amd64-1.10.25-69568c55.tar.gz
$ rm -r geth-linux-amd64-1.10.25-69568c55
$ sudo systemctl stop geth
$ sudo apt update && sudo apt upgrade
$ sudo systemctl start geth
$ sudo systemctl status geth # <-- Check for errors
$ sudo journalctl -fu geth # <-- Monitor
$ sudo journalctl -fu lighthousebeacon # <-- Monitor

Appendix D — Updating Nethermind

$ cd ~
$ curl -LO https://github.com/NethermindEth/nethermind/releases/download/1.14.3/nethermind-linux-amd64-1.14.3-7074612-20221003.zip
$ sudo systemctl stop nethermind
$ unzip nethermind-linux-amd64-1.14.3-7074612-20221003.zip -d nethermind
$ sudo rm -r /usr/local/bin/nethermind # <-- Remove the old files
$ sudo cp -a nethermind /usr/local/bin/nethermind
$ sudo systemctl start nethermind
$ sudo systemctl status nethermind # <-- Check for errors
$ sudo journalctl -fu nethermind # <-- Monitor
$ sudo journalctl -fu lighthousebeacon # <-- Monitor
$ rm nethermind-linux-amd64-1.14.3-7074612-20221003.zip
$ rm -r nethermind

Appendix E — Updating Lighthouse

$ cd ~
$ curl -LO https://github.com/sigp/lighthouse/releases/download/v3.1.0/lighthouse-v3.1.0-x86_64-unknown-linux-gnu.tar.gz
$ sudo systemctl stop lighthousevalidator
$ sudo systemctl stop lighthousebeacon
$ tar xvf lighthouse-v3.1.0-x86_64-unknown-linux-gnu.tar.gz
$ sudo cp lighthouse /usr/local/bin
$ sudo systemctl start lighthousebeacon
$ sudo systemctl status lighthousebeacon # <-- Check for errors
$ sudo journalctl -fu lighthousebeacon # <-- Monitor
$ sudo systemctl start lighthousevalidator
$ sudo systemctl status lighthousevalidator # <-- Check for errors
$ sudo journalctl -fu lighthousevalidator # <-- Monitor
$ rm lighthouse-v3.1.0-x86_64-unknown-linux-gnu.tar.gz
$ rm lighthouse

Appendix F — Adding Validators

Generate Deposit Data

$ sudo ./deposit existing-mnemonic --validator_start_index <ValidatorStartIndex> --num_validators <NumberOfValidators> --chain mainnet
deposit.exe existing-mnemonic --validator_start_index <ValidatorStartIndex> --num_validators <NumberOfValidators> --chain mainnet
  • The newer deposit_data-[timestamp].json file contains the public key(s) for the newly added validator(s) and information about the staking deposit. This file will be used to complete the ETH staking deposit process later in this guide.
  • The newly created keystore-[..].json file(s) contain the encrypted validator signing key. There is one keystore file per additional validator that you are funding. These will be imported into the Consensus Client validator wallet for use during validation operations.
  • You will copy the files over to your Ubuntu server (if not already there) later in this step.
  • If you lose or accidentally delete the files it is possible to regenerate them using the Staking Deposit Tool and your mnemonic via the existing-mnemonic command. More information here.

Copy the Validator Keystore Files to the Server

$ sudo systemctl stop lighthousevalidator
$ sudo /usr/local/bin/lighthouse --network mainnet account validator import --directory $HOME/staking-deposit-cli/validator_keys --datadir /var/lib/lighthouse
$ sudo chown -R lighthousevalidator:lighthousevalidator /var/lib/lighthouse/validators
$ sudo systemctl start lighthousevalidator
$ sudo systemctl status lighthousevalidator # <-- Check for errors
$ sudo journalctl -fu lighthousevalidator # <-- Monitor
INFO Initialized validators enabled: 3, disabled: 0

Appendix G — Exiting Validators

$ cd ~
$ cd /usr/local/bin
$ lighthouse --network mainnet account validator exit --keystore /var/lib/lighthouse/validators/<ValidatorPublicKey>/voting-keystore.json --beacon-node http://localhost:5052

Appendix H — Manage Systemd Journal Logs

$ sudo journalctl --disk-usage
$ sudo journalctl --flush --rotate 
$ sudo journalctl --vacuum-time=3days
$ sudo journalctl --verify

Automatically Limit Log Size

$ sudo nano /etc/systemd/journald.conf
$ sudo systemctl restart systemd-journald

Appendix I — Expanding the Logical Volume

$ sudo lvdisplay # <-- Check your logical volume size
$ sudo lvm
> lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
> lvextend -l +100%FREE -r /dev/ubuntu-vg/ubuntu-lv
> exit
$ sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
$ df -h # <-- Check results

Full Disclaimer

--

--

Passionate about Ethereum and decentralized technology.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Somer Esat

Somer Esat

Passionate about Ethereum and decentralized technology.