Guide to Staking on Ethereum 2.0 (Ubuntu/Pyrmont/Lighthouse)

WARNING — do not use this guide for connecting to the Eth2 Mainnet. Mainnet guides are here.
This is a step-by-step guide to staking on the Ethereum 2.0 Pyrmont multi-client testnet via the Sigma Prime Lighthouse client. It is based on the following technologies:
- Ubuntu v20.04 (LTS) x64 server
- Go Ethereum Node (code branch)
- Sigma Prime’s Ethereum 2.0 client, Lighthouse (code branch)
- Official multi-client testnet public network, Pyrmont
- MetaMask crypto wallet browser extension
- Prometheus metrics
- Grafana dashboard
This guide includes instructions on how to:
- Configure a newly running Ubuntu server instance
- Configure and run an Ethereum 1.0 node as a service
- Generate a Lighthouse wallet and import Pyrmont validator account keys
- Compile and configure the Lighthouse client software for Ethereum 2.0, Phase 0 (Pyrmont testnet) and run as a service
- Install and configure Prometheus metrics and set up a Grafana dashboard
Warnings
This guide is for the Pyrmont testnet. DO NOT, under any circumstances, send mainnet ETH to this testnet. You will lose it.
This guide SHOULD NOT be used for connecting to the Eth2 mainnet. An Eth2 mainnet specific guide can be found here.
Acknowledgements and Disclaimer
This guide is based on information I pulled together from various on-line resources and this guide wouldn’t exist without them. Thank you, all!
Thanks to the folks on the Lighthouse and EthStaker discords for their help and review.
Special thanks to the client team and the EF researchers. Your tireless efforts over the past few years have brought us to the cusp of an incredible moment in history — the launch of Ethereum 2.0.
This is for educational purposes only. I’m not an expert in any of the technologies listed in this guide. The accuracy of this guide is not guaranteed and I am not responsible for any damages or losses incurred by following this guide.
Feedback is always welcome!
Support
This stuff can be tricky. If you need help there are two great resources you can reach out to (besides me):
- EthStaker community on Reddit or Discord. Knowledgeable and friendly community passionate about staking on Ethereum 2.0.
- Lighthouse client team Discord. The client software engineering team. Experts on Lighthouse and its usage.
Prerequisites
This guide assumes some knowledge of Ethereum, ETH, staking, Linux, and MetaMask.
This guide also requires the following are installed and running before getting started:
- Ubuntu server v20.04 (LTS) amd64 or newer, installed and running on a local computer on your network or in the cloud (AWS, Digital Ocean, Microsoft Azure, etc.). A local computer is recommended for greater decentralization — if the cloud provider goes down then all nodes hosted with that provider go down.
- MetaMask crypto wallet browser extension, installed and configured. A computer with a desktop (Mac, Windows, Linux) and a browser (Safari, Brave, FireFox, etc.) is required.
Note for Raspberry Pi Users
I haven’t tested this guide on a Rpi. If you want to try, just swap out the software listed below for the ARM version, where available. No guarantee it will work!
Requirements
- Ubuntu server instance. I used v20.04 (LTS) amd64 server VM.
- MetaMask crypto wallet browser extension, installed and configured.
- Hardware recommended hardware requirements:
- Processor: Intel Core i7–4770 or AMD FX-8310 or better
- Memory: 16GB RAM
- Storage: 100GB available space SSD
Overview
This is a long and detailed guide. Here’s a super simplified diagram to help you conceptualize what we are going to do. The yellow boxes are the parts this guide mostly covers.

The conceptual flow is:
- Set up a Eth1 node and sync it with the Eth1 Göerli testnet
- Configure Beacon Node and sync it with the Eth1 Node
- Generate and activate validator keys
- Configure the Validator Client
- The Beacon Node makes the magic happen (blocks, attestations, slashings) with the help of the validator (signing)
Step 0 — Connect to the Server
Using a SSH client, connect to your Ubuntu server. The root
user account on Ubuntu server is normally disabled by default, however some cloud providers enable it. If you are logged in as root
then let’s create a user-level account with admin privileges instead, because using the root user to log in is risky.
NOTE: If you are not logged in as root then skip this and go to Step 1.
# adduser <yourusername>
You will asked to create a password and some other information.
Grant admin rights to the new user by adding it to the sudo group.
# usermod -aG sudo <yourusername>
When you log in as <yourusername>
you can type sudo before commands to perform actions with superuser privileges.
Optional: If you used SSH keys to connect to your Ubuntu instance via the root
user you will need to associate the new user with the root user’s SSH key data.
# rsync --archive --chown=<yourusername>:<yourusername> ~/.ssh /home/<yourusername>
Finally, log out of root
and log in as <yourusername>
.
Step 1 — Update Your System
Make sure your system is up to date with the latest software and security updates.
$ sudo apt update && sudo apt upgrade
$ sudo apt dist-upgrade && sudo apt autoremove
Step 2 — Secure Your System
Security is important. This is not a comprehensive security guide, rather just some basic settings.
Configure the firewall
Ubuntu 20.04 servers can use the default UFW firewall to restrict traffic to the server. We need to allow inbound traffic for SSH, Go Ethereum, Grafana, and Lighthouse.
Allow SSH
Allows connection to the server over SSH. For security reasons we are going to modify the default port of 22 because it is a common attack vector.
Note: If you would rather not change the default SSH port (not recommended), then include a rule allowing the default SSH port
$ sudo ufw allow 22/tcp
and move onto the “Allow Go Ethereum” section.
Choose a port number between 1024–49151 and run the following command to make sure your selection is not already in use on the server. If it is (red text), choose a different port.
$ sudo ss -tulpn | grep ':<yourSSHportnumber>'
Update the firewall to allow inbound traffic on <yourSSHportnumber>
. SSH requires TCP.
$ sudo ufw allow <yourSSHportnumber>/tcp
Next change the default SSH port.
$ sudo nano /etc/ssh/sshd_config
Find the line with # Port 22
or Port 22
and change it to Port <yourSSHportnumber>
. Remove the #
if it was present.
Check the screen shot below for reference. Your file should look similar to that (but with the port number you chose). Exit and save.

Restart the SSH service.
$ sudo systemctl restart ssh
Next time you log in via SSH use <yourSSHportnumber>
for the port.
Optional: If you were already using UFW with port 22/TCP allowed then update the firewall to deny inbound traffic on that port.
$ sudo ufw deny 22/tcp
Allow Go Ethereum
Allows incoming requests from Go Ethereum peers (port 30303/TPC and 30303/UDP). If you’d rather use a node hosted by a 3rd party (Infura, etc.) then skip this step.
Note: If you are hosting your Ubuntu instance locally your internet router and/or firewall will need to be configured to allow incoming traffic on these ports as well.
$ sudo ufw allow 30303
Allow Lighthouse
Allows P2P connections with peers for actions on the beacon node (ports 9000/TCP and 9000/UDP).
Note: If you are hosting your Ubuntu instance locally your internet router and/or firewall will need to be configured to allow incoming traffic on these ports as well.
$ sudo ufw allow 9000
Allow Grafana
Allows incoming requests to the Grafana web server (port 3000/TCP).
$ sudo ufw allow 3000/tcp
Allow Prometheus (Optional)
If you want direct access to the Prometheus data service you can open up port 9090/TCP as well. This is not necessary if you are solely using Grafana to view the data. I did not open this port.
$ sudo ufw allow 9090/tcp
Now enable the firewall and check to verify the rules have been correctly configured.
$ sudo ufw enable
$ sudo ufw status numbered
Output should look something like this.

Step 3— Install and Run Go Ethereum Node
Install and configure an Ethereum 1.0 node that the beacon-chain will connect to. If you’d rather use a node hosted by a 3rd party (Infura, etc.) then skip this step.
Install Go Ethereum
Go Ethereum recommends using PPA’s (Personal Package Archives).
$ sudo add-apt-repository -y ppa:ethereum/ethereum
Update the packages and install the latest stable version.
$ sudo apt update
$ sudo apt install geth
Run Go Ethereum as a Background Service
Create an account for the service to run under. This type of account can’t log into the server.
$ sudo useradd --no-create-home --shell /bin/false goeth
Create the data directory for the Eth1 chain. This is required for storing the Eth1 node data. Use the -p
option to create the full path.
$ sudo mkdir -p /var/lib/goethereum
Set directory permissions. The goeth
account needs permission to modify the data directory.
$ sudo chown -R goeth:goeth /var/lib/goethereum
Create a systemd service file to store the service config. We will use the config file to tell systemd to run the geth
process.
$ sudo nano /etc/systemd/system/geth.service
Paste the following service configuration into the file.
[Unit]
Description=Ethereum go client
After=network.target
Wants=network.target[Service]
User=goeth
Group=goeth
Type=simple
Restart=always
RestartSec=5
ExecStart=geth --goerli --http --datadir /var/lib/goethereum[Install]
WantedBy=default.target
The --goerli
flag is used to target the Göerli test network and the --http
flag is to expose an endpoint (http://localhost:8545) that the beacon chain will connect to.
Check the screen shot below for reference. Your file should look like that. Exit and save.

Reload systemd to reflect the changes.
$ sudo systemctl daemon-reload
Start the service and check to make sure it’s running correctly.
$ sudo systemctl start geth
$ sudo systemctl status geth
Output should look like this.

If you did everything right, it should say active (running) in green text. If not then go back and repeat the steps to fix the problem. Press Q to quit.
Enable the geth service to automatically start on reboot.
$ sudo systemctl enable geth
The Go Ethereum node will begin to sync. You can follow the progress by running the journal command. Press Ctrl+C to quit.
$ sudo journalctl -fu geth.service
Sometimes it can take a while to find peers to sync. If so, you can add some peers to help things along. Go here for the latest list and modify the geth service as follows:
$ sudo systemctl stop geth
$ sudo nano /etc/systemd/system/geth.service
Modify the ExecStart line and add the --bootnodes
flag with a few of the latest peers (comma separated).
ExecStart=geth --goerli --http --datadir /var/lib/goethereum --bootnodes "enode://46add44b9f13965f7b9875ac6b85f016f341012d84f975377573800a863526f4da19ae2c620ec73d11591fa9510e992ecc03ad0751f53cc02f7c7ed6d55c7291@94.237.54.114:30313,enode://119f66b04772e8d2e9d352b81a15aa49d565590bfc9a80fe732706919f8ccd00a471cf8433e398c55c4862aadb4aadf3a010201483b87e8358951698aa0b6f07@13.250.50.139:30303"
Save the file and exit. Restart the service and observe.
$ sudo systemctl daemon-reload
$ sudo systemctl start geth
$ sudo journalctl -f -u geth.service
Once it gets started the output should look like this.

You should wait for the node sync to complete before you run the beacon chain. You can see the latest block here.
For example, the screen shot above shows the node is processing block number=498880
and looking at the screen shot below, we can see the latest block number is 3270051
. So based on that we still have a while to go before completing the sync.

Next we will clone and build the Lighthouse software. Consider opening a new terminal window here so you can continue to observe the Eth1 node sync.
Step 4— Install Dependencies
Rust is required to build Lighthouse. Follow the prompts to install.
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env
Since Rust modifies the PATH variable we run source $HOME/.cargo/env
. Doing so prevents a command not found
error like the one below when trying to compile.
cargo install --path lighthouse --force --locked
make: cargo: Command not found
make: *** [Makefile:20: install] Error 127
A number of packages (git, gcc, g++, make, cmake, etc) are also required.
$ sudo apt install -y git gcc g++ make cmake pkg-config libssl-dev
Step 5— Install and Build Lighthouse
Now we’re ready to build Lighthouse. The Lighthouse build produces a lighthouse
binary. We execute the same binary with different subcommands to get the functionality we need. E.g.:
lighthouse beacon_node
will run a beacon node instance.
lighthouse validator_client
will run a validator client instance.
Go here to get the latest release information. It is important to avoid cloning the master branch as it may be unstable.
Use the label (in this case v1.0.0
).

$ cd ~
$ git clone -b v1.0.0 https://github.com/sigp/lighthouse.git
$ cd lighthouse
Use Make to compile the Lighthouse binary.
$ make
Output looks like this.

Depending on your hardware it can take a while to build. Good time to get a fresh beverage and re-hydrate. Maybe check out a few of my other articles.
If the build succeeds then continue. If not get help on the Lighthouse Discord.
Step 6— Complete the Pyrmont On-boarding Process
In order to run a validator on the Eth2.0 Pyrmont testnet we will need to sign up for one or more validator accounts.
NOTE: If you have already generated your deposit data and submitted your staking deposits you can skip this step. If you generated them elsewhere you will need to copy your validator keys onto the server.
The steps to sign-up are:
- Get Göerli ETH
- Generate the validator keys. Each key is a validator account
- Fund the validator account(s) with 32 Göerli ETH per account
- Wait for your validator account(s) to become active
Let’s get started.
Get Goerli ETH
- Go to a computer with the MetaMask browser extension installed.
- Click on MetaMask and log in.
- Using the drop-down at the top, select the Göerli Test Network.
- Click on the account name to copy your Göerli Test Network wallet address.
- Using your address, get Göerli ETH from the authenticated faucet or via the
#request-goerli-eth
channel on the ethstaker Discord using the bot command:!goerliEth <yourwalletaddress>
.
NOTE: Each validator requires a 32 ETH deposit. You should have sufficient Göerli ETH in your MetaMask wallet to fund each validator. For example, if you want 10 validators you need to have 320 Göerli ETH plus some extra (e.g. 1 Göerli ETH) to pay for the gas fees.
Generate Validator Keys
Next we will generate the validator keys. The validator client supports multiple validator keys. Each validator key is basically a “validator account” on the Pyrmont testnet.
Go here to get the “Latest release” of the deposit command line interface app.

In the assets section copy the link to the Linux version. We will use that link to download it as shown below. Modify the the URL in the instructions below to match the latest version download link.
$ cd ~
$ curl -LO https://github.com/ethereum/eth2.0-deposit-cli/releases/download/v1.1.0/eth2deposit-cli-ed5a6d3-linux-amd64.tar.gz
Unpack the tar archive.
$ tar xvf eth2deposit-cli-ed5a6d3-linux-amd64.tar.gz
$ cd eth2deposit-cli-ed5a6d3-linux-amd64
Clean up by removing the downloaded tar archive file.
$ rm -rf eth2deposit-cli-ed5a6d3-linux-amd64.tar.gz
Run the application to generate the validator keys.
NOTE: For mainnet this should ideally be done on a fresh machine not connected to the internet to avoid leaking your mnemonic.
Change <numberofvalidators>
to the number of validator keys you want to create. E.g. --num_validators 5
.
$ ./deposit new-mnemonic --num_validators <numberofvalidators> --mnemonic_language=english --chain pyrmont
It will ask you to create a wallet password. We will use this to load the validator keys into your client’s validator wallet. Back it up somewhere safe.

A seed phrase (mnemonic) will be generated. Back it up somewhere safe.

Once you have confirmed your mnemonic your validator keys will be created.

The newly created validator keys and deposit data file are created at the specified location.

The deposit_data-[timestamp].json
file contains the public keys for the validators and information about the deposit. This file will be used to complete the deposit process in the next step. Since we are on a server we don’t have a web browser so secure FTP (SFTP) the file over to a computer running MetaMask.
The keystore-m...json
files contain the encrypted signing key. There is one keystore-m per validator. These will be used to create the client validator wallet.
Fund the Validator Keys
This step involves depositing the required amount of Göerli ETH to the Pyrmont testnet staking contract. This is done on the Eth2.0 Lauchpad website.
WARNING: DO NOT send real ETH to the Pyrmont testnet. You will lose your ETH.
Go here: https://pyrmont.launchpad.ethereum.org/
Click through the warning steps then select the number of validators you are going to run. Scroll down and click continue.

You will be asked to upload the deposit_data-[timestamp].json
file. This should have been copied over in the previous step. Browse or drag the file and click continue.

Connect your wallet. Choose MetaMask, log in, select the Göerli Test Network and click Continue.
WARNING: The launchpad should prevent you from using anything other than the Göerli Test Network, but be absolutely 100% sure you have selected the Göerli Test Network in MetaMask. DO NOT sent real ETH to the Pyrmont testnet.

Your MetaMask balance will be displayed. The site will allow you to continue if you have sufficient Göerli ETH balance.

A summary shows the number of validators and total amount of Göerli ETH required. Tick the boxes if you agree and click continue.

Click on initiate all transactions. This will pop open multiple instances of MetaMask, each with a 32 Göerli ETH transaction request to the Pyrmont testnet deposit contract. Confirm each transaction.

Once all the transactions have successfully completed you are done!

Check the Status of Your Validators
Newly added validators can take a while (hours/days/weeks) to activate. You can check the status of your keys with these steps:
- Copy your Göerli Test Network wallet address
- Go here: https://pyrmont.beaconcha.in/
- Search your wallet address. Your keys will be shown.
Click on a key to see the Estimated Activation information.

That’s it! Now let’s create the validator wallet.
Step 7— Create the Validator Wallet
The validator wallet is created by importing the keystore-m JSON files from the previous step.
First create a directory to store the validator wallet and give the current user permissions to access it. Change <yourusername>
to your logged in username.
$ sudo mkdir -p /var/lib/lighthouse
$ sudo chown -R <yourusername>:<yourusername> /var/lib/lighthouse
Next we will use the Lighthouse binary we complied earlier to create a wallet using the keys we generated in the previous step. Replace <PathToValidatorKeys>
with the path to your generated validator keys. E.g. -- keys-dir=$HOME/eth2.0-deposit-cli/validator_keys
$ cd lighthouse
$ lighthouse --network pyrmont account validator import --directory $HOME/<PathToValidatorKeys> --datadir /var/lib/lighthouse
The --datadir
flag specifies the location to output the wallet data. The process will create a validators
directory under the --datadir
path.
Next you will need to enter the password you used to create the validator keys on the Eth2 Launch Pad site. You will be asked to provide the password for each key, one-by-one. Be sure to provide the password each time because the validator will be running as a service, and it needs to persist the password in a file to access the key.
Output should look like:
Running account manager for pyrmont testnet
validator-dir path: "/var/lib/lighthouse/validators"
validator-dir path: "/var/lib/lighthouse/validators"
WARNING: DO NOT USE THE ORIGINAL KEYSTORES TO VALIDATE WITH ANOTHER CLIENT, OR YOU WILL GET SLASHED.Keystore found at "/home/ethstaker/eth2deposit-cli-ed5a6d3-linux-amd64/validator_keys/keystore-m_12381_3600_1_0_0-1605678395.json":- Public key: 0xa79583298ecbd5564fce6ccefe2e69969705aff950235dc59ae303fa210b029b565c08303eb18cf02ecc26c429059d7f
- UUID: 94079858-57db-4fb2-8272-5dbdfb31e65eIf you enter the password it will be stored as plain-text in validator_definitions.yml so that it is not required each time the validator client starts.Enter the keystore password, or press enter to omit it:Password is correct.Successfully imported keystore.
Successfully updated validator_definitions.yml.
Once you do this for each keystore-m JSON file you should get a successful message.
Successfully imported 2 validators (0 skipped).WARNING: DO NOT USE THE ORIGINAL KEYSTORES TO VALIDATE WITH ANOTHER CLIENT, OR YOU WILL GET SLASHED.
For security reasons, update permissions to remove access to var/lib/lighthouse
for <youruseraccount>
. This is intentionally not using -R as we will reassign permissions to the sub-directories later.
sudo chown root:root /var/lib/lighthouse
That’s it! Now that the validator wallet is configured we will set up the beacon node and validator.
Step 8— Configure the Beacon Node
We will run the beacon node as a service so if the system restarts the process will automatically start back up again.
Setup Accounts and Directories
Create an account for the beacon node to run under. This type of account can’t log into the server.
$ sudo useradd --no-create-home --shell /bin/false lighthousebeacon
Create the data directory for the Lighthouse beacon node database.
$ sudo mkdir -p /var/lib/lighthouse/beacon
Set directory permissions. The lighthousebeacon
account needs permission to modify the database directory.
$ sudo chown -R lighthousebeacon:lighthousebeacon /var/lib/lighthouse/beacon
Next, copy the compiled lighthouse
binary (from Step 5) to the /usr/local/bin
directory. We will run it from there.
Note: You will need to do this step each time you pull/build a new version of the
lighthouse
binary. See Appendix — Updating Lighthouse at the end of this guide
$ sudo cp /$HOME/.cargo/bin/lighthouse /usr/local/bin
Create and Configure the Service
Create a systemd service file to store the service config.
$ sudo nano /etc/systemd/system/lighthousebeacon.service
Paste the following into the file.
[Unit]
Description=Lighthouse Beacon Node
Wants=network-online.target
After=network-online.target[Service]
Type=simple
User=lighthousebeacon
Group=lighthousebeacon
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/lighthouse beacon_node --datadir /var/lib/lighthouse --network pyrmont --staking --eth1-endpoint http://127.0.0.1:8545 --metrics[Install]
WantedBy=multi-user.target
The beacon_node
subcommand tells the lighthouse
binary that we want to run the beacon node.
The --datadir
flag is the path to store the beacon node database.
The --staking
flag indicates that we are also going to be running a validator, therefore enabling the HTTP server. The validator and beacon node use that to communicate with each other.
The --eth1-endpoint
flag defines the endpoint of the Eth1 node. If you installed one locally the value is http://127.0.0.1:8545
. If you’re using a third party use the external endpoint address (e.g. Infura or Prysmatic’s Eth1 node: https://goerli.prylabs.net
).
The --metrics
flag enables a metrics server on the default port 5054. The output will be captured by Prometheus for graphing via Grafana.
Check the screen shot below for reference. Your file should look like that. Exit and save.

Reload systemd to reflect the changes.
$ sudo systemctl daemon-reload
Note: If you are running a local Eth1 node (see Step 3) you should wait until it fully syncs before starting the beacon chain service. Check progress here:
sudo journalctl -fu geth.service
Start the service and check to make sure it’s running correctly.
$ sudo systemctl start lighthousebeacon
$ sudo systemctl status lighthousebeacon
Output should look like this.

If you did everything right, it should say active (running) in green text. If not then go back and repeat the steps to fix the problem. Press Q to quit.
Enable the beacon-chain service to automatically start on reboot.
$ sudo systemctl enable lighthousebeacon
The beacon-chain will begin to sync. It may take several hours for the node to fully sync. You can check the progress by running the journal command. Press Ctrl+C to quit.
$ sudo journalctl -fu lighthousebeacon.service
It should look something like this.
Nov 19 09:57:15 ETH-STAKER-001 systemd[1]: Started Lighthouse Beacon Node.
Nov 19 09:57:15 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:57:15.398 WARN Ethereum 2.0 is pre-release. This software is experimental
Nov 19 09:57:15 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:57:15.398 INFO Lighthouse started version: Lighthouse/v0.3.5-1a530e5a
Nov 19 09:57:15 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:57:15.398 INFO Configured for testnet name: pyrmont
Nov 19 09:57:15 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:57:15.398 INFO Data directory initialised datadir: /var/lib/lighthouse
Nov 19 09:57:15 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:57:15.398 WARN Running HTTP server on port 5052
Nov 19 09:57:15 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:57:15.456 INFO Starting from known genesis state service: beacon
Nov 19 09:57:16 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:57:16.564 INFO Block production enabled method: json rpc via http, endpoint: https://goerli.prylabs.net
The output will give an indication of time to fully sync.
Nov 19 09:59:37 ETH-STAKER-001 lighthouse[158842]: Nov 19 09:59:37.001 INFO Syncing est_time: 18 mins, speed: 5.31 slots/sec, distance: 5830 slots (19 hrs 26 mins), peers: 29, service: slot_notifier
Now your beacon chain is running as a service. Congratulations! While the beacon node is syncing, let’s move onto the next step.
Step 9 — Configure the Validator
Setup Accounts and Directories
We will run the validator as a service so if the system restarts the process will automatically start back up again.
Create an account for the validator service to run under. This type of account can’t log into the server.
$ sudo useradd --no-create-home --shell /bin/false lighthousevalidator
We created the data directory for the validator in the wallet creation step: /var/lib/lighthouse/validators
. Now set directory permissions so the lighthousevalidator
account can modify the validator account data directory.
$ sudo chown -R lighthousevalidator:lighthousevalidator /var/lib/lighthouse/validators
Create and Configure the Service
Create a systemd service file to store the service config.
$ sudo nano /etc/systemd/system/lighthousevalidator.service
Paste the following into the file with the following exceptions:
Replace <POAPstring>
with your preferred text. E.g. --graffiti "abcdefg12345"
[Unit]
Description=Lighthouse Validator
Wants=network-online.target
After=network-online.target[Service]
Type=simple
User=lighthousevalidator
Group=lighthousevalidator
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/lighthouse validator_client --network pyrmont --datadir /var/lib/lighthouse --graffiti "<yourPOAPstring>"[Install]
WantedBy=multi-user.target
We use the same lighthouse
binary located in /usr/local/bin
but this time we apply the validator_client
subcommand, instructing it to run the validator.
The --network pyrmont
flag is required to indicate we are running against the Pyrmont testnet.
The --datadir
flag is where we are going to save our validator database.
Check the screen shot below for reference. Exit and save.

Reload systemd to reflect the changes.
$ sudo systemctl daemon-reload
Start the service and check to make sure it’s running correctly.
$ sudo systemctl start lighthousevalidator
$ sudo systemctl status lighthousevalidator
You should see output that looks something like this.

If you did everything right, it should say active (running) in green text. If not then go back and repeat the steps to fix the problem. Press Q to quit.
Enable the validator service to automatically start on reboot.
$ sudo systemctl enable lighthousevalidator
You can check the progress by running the journal command. Press Ctrl+C to quit.
$ sudo journalctl -fu lighthousevalidator.service
The validator will enable the validator keys in the validator wallet and confirm the connection to the beacon node.
Nov 19 10:13:54 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:54.772 INFO Completed validator discovery new_validators: 0
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.904 INFO Enabled validator voting_pubkey: 0xa79583298ecbd5564fce6ccefe2e69969705aff950235dc59ae303fa210b029b565c08303eb18cf02ecc26c429059d>
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.904 INFO Enabled validator voting_pubkey: 0x8c8b19c544d79bdaf60d7dcc86ebaeeed4d804d2ecb4c66e5b27e19a664a81457a1c02a873a110e1d332abce5800cf>
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.904 INFO Initialized validators enabled: 2, disabled: 0
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.931 INFO Connected to beacon node version: Lighthouse/v0.3.5-1a530e5a/x86_64-linux
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.934 INFO Genesis has already occurred seconds_ago: 80028
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.934 INFO Loaded validator keypair store voting_validators: 2
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.934 INFO Block production service started service: block
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.934 INFO Attestation production service started next_update_millis: 11065, service: attestation
Nov 19 10:13:55 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:13:55.935 INFO HTTP API server is disabled
It may take hours or even days to activate the validator account(s) on the testnet once the beacon chain has actually started processing.
Nov 19 10:25:49 ETH-STAKER-001 lighthouse[159892]: Nov 19 10:25:49.004 INFO Awaiting activation slot: 6728, epoch: 210, validators: 2, service: notifier
You can check the status of your validator(s) via beaconcha.in. Simply do a search for your validator public key(s) or search using your MetaMask wallet address. It may be a while before they appear on the site.
That’s it. We have a functioning beacon chain and validator. Congratulations: you are awesome!
Step 10 — Install Prometheus
Prometheus is an open-source systems monitoring and alerting toolkit. It runs as a service on your Ubuntu server and its job is to capture metrics. More information here.
We are going to use Prometheus to expose runtime data from the beacon-chain and validator as well as instance specific metrics.
Create User Accounts
Accounts for the services to run under. These accounts can’t log into the server.
$ sudo useradd --no-create-home --shell /bin/false prometheus
$ sudo useradd --no-create-home --shell /bin/false node_exporter
Create Directories
Program and data directories.
$ sudo mkdir /etc/prometheus
$ sudo mkdir /var/lib/prometheus
Set directory ownership. The prometheus
account will manage these.
$ sudo chown -R prometheus:prometheus /etc/prometheus
$ sudo chown -R prometheus:prometheus /var/lib/prometheus
Download Prometheus software
Adjust the version number to the latest version from the Prometheus download page. Rpi users be sure to get the ARM binary.
$ cd ~
$ curl -LO https://github.com/prometheus/prometheus/releases/download/v2.20.0/prometheus-2.20.0.linux-amd64.tar.gz
Unpack the archive. It contains two binaries and some content files.
$ tar xvf prometheus-2.20.0.linux-amd64.tar.gz
Copy the binaries to the following locations.
$ sudo cp prometheus-2.20.0.linux-amd64/prometheus /usr/local/bin/
$ sudo cp prometheus-2.20.0.linux-amd64/promtool /usr/local/bin/
Set directory ownership. The prometheus
account will manage these.
$ sudo chown -R prometheus:prometheus /usr/local/bin/prometheus
$ sudo chown -R prometheus:prometheus /usr/local/bin/promtool
Copy the content files to the following locations.
$ sudo cp -r prometheus-2.20.0.linux-amd64/consoles /etc/prometheus
$ sudo cp -r prometheus-2.20.0.linux-amd64/console_libraries /etc/prometheus
Set directory and file (-R) ownership. The prometheus
account will manage these.
$ sudo chown -R prometheus:prometheus /etc/prometheus/consoles
$ sudo chown -R prometheus:prometheus /etc/prometheus/console_libraries
Remove the downloaded archive.
$ rm -rf prometheus-2.20.0.linux-amd64.tar.gz prometheus-2.20.0.linux-amd64
Edit the Configuration File
Prometheus uses a configuration file so it knows where to scrape the data from. We will set this up here.
Open the YAML config file for editing.
$ sudo nano /etc/prometheus/prometheus.yml
Paste the following into the file taking care not to make any additional edits and exit and save the file.
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
- job_name: 'nodes'
metrics_path: /metrics
static_configs:
- targets: ['localhost:5054']
- job_name: 'node_exporter'
static_configs:
- targets: ['localhost:9100']
The scrape_configs define the output target for the different job names. We have 2 job names: beacon node and node_exporter. The first is obvious, the second is for metrics related to the server instance itself (memory, CPU, disk, network etc.). We will install and configure node_exporter in the next step.
Set ownership for the config file. The prometheus account will own this.
$ sudo chown -R prometheus:prometheus /etc/prometheus/prometheus.yml
Finally, let’s test the service is running correctly.
$ sudo -u prometheus /usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries
Output should look something like this. Press Ctrl + C to exit.
level=info ts=2020-08-02T04:56:51.414Z caller=main.go:805 msg="Loading configuration file" filename=/etc/prometheus/prometheus.yml
level=info ts=2020-08-02T04:56:51.415Z caller=main.go:833 msg="Completed loading of configuration file" filename=/etc/prometheus/prometheus.yml
level=info ts=2020-08-02T04:56:51.415Z caller=main.go:652 msg="Server is ready to receive web requests."
Set Prometheus to Auto-Start as a Service
Create a systemd service file to store the service config which tells systemd to run Prometheus as the prometheus user, with the configuration file located in the /etc/prometheus/prometheus.yml directory, and to store its data in the /var/lib/prometheus directory.
$ sudo nano /etc/systemd/system/prometheus.service
Paste the following into the file. Exit and save.
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target[Service]
Type=simple
User=prometheus
Group=prometheus
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries[Install]
WantedBy=multi-user.target
Reload systemd to reflect the changes.
$ sudo systemctl daemon-reload
And then start the service with the following command and check the status to make sure it’s running correctly.
$ sudo systemctl start prometheus
$ sudo systemctl status prometheus
Output should look something like this.

If you did everything right, it should say active (running) in green. If not then go back and repeat the steps to fix the problem. Press Q to quit.
Lastly, enable Prometheus to start on boot.
$ sudo systemctl enable prometheus
Step 11 — Install Node Exporter
Prometheus will provide metrics about the beacon chain and validators. If we want metrics about our Ubuntu instance, we’ll need an extension called Node_Exporter. You can find the latest stable version here if you want to specify a different version below. Rpi users remember to get the ARM binary.
$ cd ~
$ curl -LO https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz
Unpack the downloaded software.
$ tar xvf node_exporter-1.0.1.linux-amd64.tar.gz
Copy the binary to the /usr/local/bin directory and set the user and group ownership to the node_exporter user we created above.
$ sudo cp node_exporter-1.0.1.linux-amd64/node_exporter /usr/local/bin
$ sudo chown -R node_exporter:node_exporter /usr/local/bin/node_exporter
Remove the downloaded archive.
$ rm -rf node_exporter-1.0.1.linux-amd64.tar.gz node_exporter-1.0.1.linux-amd64
Set Node Exporter to Auto-Start as a Service
Create a systemd service file to store the service config which tells systemd to run Node_Exporter as the node_exporter user.
$ sudo nano /etc/systemd/system/node_exporter.service
Paste the following into the file. Exit and save.
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter[Install]
WantedBy=multi-user.target
Reload systemd to reflect the changes.
$ sudo systemctl daemon-reload
And then start the service with the following command and check the status to make sure it’s running correctly.
$ sudo systemctl start node_exporter
$ sudo systemctl status node_exporter
Output should look something like this.

If you did everything right, it should say active (running) in green. If not then go back and repeat the steps to fix the problem. Press Q to quit.
Finally, enable Node Exporter to start on boot.
$ sudo systemctl enable node_exporter
Test Prometheus and Node Exporter (Optional)
Everything should be ready to go. You may optionally test the functionality by opening a port in the firewall (see Step 1) and browsing to http://<yourserverip>:9090
. From there you can run queries to view different metrics. For example try this query to see how much memory is free in bytes:
http://<yourserverip>:9090/new/graph?g0.expr=node_memory_MemFree_bytes&g0.tab=1&g0.stacked=0&g0.range_input=1h
Step 12 — Install Grafana
While Prometheus is our data source, Grafana is going provide our reporting dashboard capability. Let’s install it and configure a dashboard.
We will install using an APT repository because it is easier to install and update. Grafana is available in the official Ubuntu packages repository, however the version of Grafana there may not be the latest, so we will use Grafana’s official repository.
Download the Grafana GPG key with wget, then pipe the output to apt-key. This will add the key to your APT installation’s list of trusted keys.
$ wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
Add the Grafana repository to the APT sources.
$ sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
Refresh the apt cache.
$ sudo apt update
Make sure Grafana is installed from the repository.
$ apt-cache policy grafana
Output should look like this.
grafana:
Installed: (none)
Candidate: 7.1.1
Version table:
7.1.1 500
500 https://packages.grafana.com/oss/deb stable/main amd64 Packages
7.1.0 500
500 https://packages.grafana.com/oss/deb stable/main amd64 Packages
7.0.6 500
500 https://packages.grafana.com/oss/deb stable/main amd6
...
Verify the version at the top matches the latest version shown here. Then proceed with the installation.
$ sudo apt install grafana
Start the Grafana server and heck the status to make sure it’s running correctly.
$ sudo systemctl start grafana-server
$ sudo systemctl status grafana-server
Output should look something like this.

If you did everything right, it should say active (running) in green. If not then go back and repeat the steps to fix the problem. Press Q to quit.
Enable Grafana to start on boot.
$ sudo systemctl enable grafana-server
Configure Grafana Login
Great job on getting this far! Now that you have everything up and running you can go to http://<yourserverip>:3000/
in a browser and the Grafana login screen should come up.
Enter admin
for the username and password. It will prompt you to change your password and you should definitely do that.
Configure the Grafana Data Source
Let’s configure a datasource. Move your mouse over the gear icon on the left menu bar. A menu will pop-up — choose Data Sources
.

Click on Add data source
and then choose Prometheus
. Enter http://localhost:9090
for the URL then click on Save and Test
.


Import a Grafana Dashboard
Now let’s import a dashboard. Move your mouse over the +
icon on the left menu bar. A menu will pop-up - choose Import
.
Copy/paste the JSON from here and click Load
then Import
. You may need to select the data source.
You should be able to view the dashboard. At first you may not have sufficient data, but after the testnet starts and validators are activated for a while you will see some metrics and alerts.

Final Remarks
Okay… That’s it! We are done! I hope you enjoyed this guide.
- A future update includes a more comprehensive dashboard (hardware metrics and metrics on the eth1 node) and information on alerting.
- If you have feedback you can reach me on Twitter or Reddit.
- If you liked this guide and think others would benefit from it then please share it using the friends link!
- Tips: somer.eth
Appendix — Updating Lighthouse
If you need to update the code due to changes in the Git repository follow these steps to get the latest files and build your binaries:
Check for any Rust updates.
$ rustup update
Pull latest Lighthouse code and build. Replace <release>
with the desired release as listed here. E.g. $ git fetch --tags && git checkout v1.0.0
.
Then we stop the beacon chain and validator services and copy the binaries over to the /usr/local/bin
directory and then start the services again.
$ cd ~
$ cd lighthouse
$ git fetch --tags && git checkout <release>
$ make$ sudo systemctl stop lighthousevalidator
$ sudo systemctl stop lighthousebeacon
$ sudo cp /$HOME/.cargo/bin/lighthouse /usr/local/bin$ sudo systemctl start lighthousebeacon
$ sudo systemctl status lighthousebeacon # <-- Check errors.
$ sudo journalctl -fu lighthousebeacon # <-- Check errors.$ sudo systemctl start lighthousevalidator
$ sudo systemctl status lighthousevalidator # <-- Check errors.
$ sudo journalctl -fu lighthousevalidator # <-- Check errors.
That’s it, the services have been updated.