# Lukso Validator Node Guide
> **_Disclaimer_**
This article (the guide) is for informational purposes only and does not constitute professional advice. The author does not guarantee accuracy of the information in this article and the author is not responsible for any damages or losses incurred by following this article. A full disclaimer can be found at the bottom of this page — please read it before continuing.
This is a guide to setup a Lukso validator node in a home environment. It suggests the use of a dedicated machine to run a node with validation, separate from a personal client for remote access.
> **_NOTE_**
> Most of the following steps require working in a terminal
## Pre-Requisites :spiral_note_pad:
- [Ubuntu](https://ubuntu.com/)
- Dedicated mini-PC
### My Setup :computer:
- Ubuntu 22.04.1 LTS
- Intel NUC 12 Pro core i7 1260p
- Kingston Fury Impact 32GB (16GBx2) DDR4 3200MHz
- Seagate Firecuda 530 Gen4 NVME 2TB with heatsink
#### **Auto Start**
I had to manually change the BIOS settings to ensure that, if power gets reset, my NUC always auto starts. A simple test is to unplug and plug power cord right back in.
For NUC I followed the following steps:
1. Press F2 during boot to enter BIOS setup
2. Go to `Power` -> `Secondary Power Settings` menu
3. Set the option for `After Power Failure` to `Power On`
4. Press F10 to save changes and exit BIOS
## System Setup :gear:
> **_NOTE_**
> The following steps are performed directly on a node machine.
### Update Manually and Install Dependencies
```shell=
sudo apt-get update
sudo apt-get upgrade -y
sudo apt dist-upgrade -y
sudo apt-get autoremove
sudo apt-get autoclean
sudo apt-get install -y wget make curl git net-tools
```
### Keep your System Up to Date Automatically
```shell=
sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
```
### Disable Root Access and Check Time Synchronization
Root access should not be used. Instead a user should be using `sudo` to perform privileged operations on a system.
```shell=
sudo passwd -l root
timedatectl
```
### Configure Firewall
By default deny all traffic:
```shell=
sudo ufw default deny incoming
sudo ufw default allow outgoing
```
Allow P2P ports for Lukso clients:
```shell=
sudo ufw allow 30303/tcp
sudo ufw allow 13000/tcp
sudo ufw allow 12000/udp
sudo ufw allow 30303/udp
```
Optionally it's a good security measure to totally block the following ports as mentioned in the prysm config docs:
```shell=
sudo ufw deny out 8545/tcp
sudo ufw deny out 3500/tcp
sudo ufw deny out 8551/tcp
sudo ufw deny out 4000/tcp
```
Enable Firewall:
```shell=
sudo ufw enable
```
Verify firewall configuration:
```shell=
sudo ufw status verbose
```
It should look something like this:
```
Status: active
To Action From
-- ------ ----
12000/udp ALLOW IN Anywhere
13000/tcp ALLOW IN Anywhere
30303/tcp ALLOW IN Anywhere
30303/udp ALLOW IN Anywhere
12000/udp (v6) ALLOW IN Anywhere (v6)
13000/tcp (v6) ALLOW IN Anywhere (v6)
30303/tcp (v6) ALLOW IN Anywhere (v6)
30303/udp (v6) ALLOW IN Anywhere (v6)
8545/tcp DENY OUT Anywhere
3500/tcp DENY OUT Anywhere
8551/tcp DENY OUT Anywhere
4000/tcp DENY OUT Anywhere
8545/tcp (v6) DENY OUT Anywhere (v6)
3500/tcp (v6) DENY OUT Anywhere (v6)
8551/tcp (v6) DENY OUT Anywhere (v6)
4000/tcp (v6) DENY OUT Anywhere (v6)
```
> **_NOTE_**
> Make sure to open the same ports on your home router and after firewall changes always run `sudo ufw reload`
## Secure Remote Access :closed_lock_with_key:
### WireGuard tunnel via PiVPN
Please read [this](https://hackmd.io/@JohnnyEBD-LYX/HyTqm4ejc) dedicated guide with detailed steps on how to easily setup a VPN host using the PiVPN installation script. Even though this is a more budget friendly solution, it's highly recommended to acquire a router that does VPN tunneling instead if this feature is absolutely needed, as this script isn't guaranteed to work on Ubuntu due to it being an untested OS. Tailscale seems to also be a viable and user friendly option with a generous free to use plan.
### OpenSSH Server Setup
Also refer to [this](https://hackmd.io/@JohnnyEBD-LYX/HkXf-1SC9) essential guide on how to setup and securely access your Ubuntu server with SSH service.
### Hardening SSH Security :muscle:
Optionally follow [this](https://hackmd.io/@JohnnyEBD-LYX/HJAio-lzo) guide to vastly improve the security of SSH service on your Ubuntu server by enabling 2FA and Fail2Ban.
#### **Improve SSH Connection**
While setting up a system, SSH terminal may seem to be slow due to wifi power management settings on a node machine. To disable it, modify the config:
```shell=
sudo nano /etc/NetworkManager/conf.d/default-wifi-powersave-on.conf
```
Config:
```
[connection]
wifi.powersave = 2
```
Close editor by pressing `ctrl` + `X`, then save. Restart `NetworkManager` service:
```shell=
sudo systemctl restart NetworkManager
```
## Node Execution, Consensus and Validation Setup
> **_NOTE_**
> Please follow LUKSO team's instructions found at:
> https://docs.lukso.tech/networks/mainnet/running-a-node/
> https://github.com/lukso-network/tools-lukso-cli
## Monitoring :telescope:
Sets up a dashboard to monitor state of a node machine, node, and validators.
> **_NOTE:_** Following steps are performed on personal machine.
Access your remote node machine
```shell=
ssh johnnyebd
```
### Prometheus
Identify latest version for `linux-amd64` [here](https://prometheus.io/download/), e.g. `2.54.0`, and install prometheus with the following:
```shell=
cd
wget https://github.com/prometheus/prometheus/releases/download/v2.54.0/prometheus-2.54.0.linux-amd64.tar.gz
tar xzvf prometheus-2.54.0.linux-amd64.tar.gz
cd prometheus-2.54.0.linux-amd64
sudo cp promtool /usr/local/bin/
sudo cp prometheus /usr/local/bin/
sudo chown root:root /usr/local/bin/promtool /usr/local/bin/prometheus
sudo chmod 755 /usr/local/bin/promtool /usr/local/bin/prometheus
cd
rm prometheus-2.54.0.linux-amd64.tar.gz
rm -rf prometheus-2.54.0.linux-amd64
```
#### **Configure**
```shell=
sudo mkdir -p /etc/prometheus/console_libraries /etc/prometheus/consoles /etc/prometheus/files_sd /etc/prometheus/rules /etc/prometheus/rules.d
```
Edit configuration file:
```shell=
sudo nano /etc/prometheus/prometheus.yml
```
Content of the configuration file should have:
```
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
scrape_interval: 5s
static_configs:
- targets: ['127.0.0.1:9090']
- job_name: 'beacon node'
scrape_interval: 5s
static_configs:
- targets: ['127.0.0.1:8080']
- job_name: 'node_exporter'
scrape_interval: 5s
static_configs:
- targets: ['127.0.0.1:9100']
- job_name: 'validator'
scrape_interval: 5s
static_configs:
- targets: ['127.0.0.1:8081']
- job_name: 'ping_google'
metrics_path: /probe
params:
module: [icmp]
static_configs:
- targets:
- 8.8.8.8
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9115 # The blackbox exporter's real hostname:port.
- job_name: 'ping_cloudflare'
metrics_path: /probe
params:
module: [icmp]
static_configs:
- targets:
- 1.1.1.1
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9115 # The blackbox exporter's real hostname:port.
- job_name: json_exporter
static_configs:
- targets:
- 127.0.0.1:7979
- job_name: json
metrics_path: /probe
static_configs:
- targets:
- https://api.coingecko.com/api/v3/simple/price?ids=lukso-token&vs_currencies=usd
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:7979
```
Prepare data directory for prometheus:
```shell=
sudo adduser --system prometheus --group --no-create-home
sudo chown -R prometheus:prometheus /etc/prometheus
sudo mkdir /var/lib/prometheus
sudo chown -R prometheus:prometheus /var/lib/prometheus
sudo chmod 755 /var/lib/prometheus
```
Open port to access metrics. This is optional, only for external use:
```shell=
sudo ufw allow 9090/tcp
```
#### **Configure Service**
```shell=
sudo nano /etc/systemd/system/prometheus.service
```
The content of service configuration file:
```
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--storage.tsdb.retention.time=31d \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries
[Install]
WantedBy=multi-user.target
```
Enable service:
```shell=
sudo systemctl daemon-reload
sudo systemctl start prometheus
sudo systemctl enable prometheus
```
#### **Prometheus update script**
In order to easily update Prometheus you can run this [script](https://raw.githubusercontent.com/eth-educators/ethstaker-guides/main/scripts/update-prometheus.py), for which you need to have one of python's latest version and you can check that with:
```shell=
python3 --version
```
If it's an older version than 3.10 or not installed at all you can run this command:
```shell=
sudo apt install python3.10 -y
```
After that you can download the script and run it.
```shell=
wget https://raw.githubusercontent.com/eth-educators/ethstaker-guides/main/scripts/update-prometheus.py
python3 update-prometheus.py
```
The script will check the current installed version and it will compare it with the latest stable release version on Github. If there is a new version available, it will prompt you to update it.
### Grafana
Install:
```shell=
cd
sudo apt-get install -y apt-transport-https software-properties-common
sudo wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install grafana
```
#### **Configure Service**
```shell=
sudo nano /lib/systemd/system/grafana-server.service
```
The content of service configuration file:
```
[Unit]
Description=Grafana instance
Documentation=http://docs.grafana.org
Wants=network-online.target
After=network-online.target
After=postgresql.service mariadb.service mysql.service
[Service]
EnvironmentFile=/etc/default/grafana-server
User=grafana
Group=grafana
Type=simple
Restart=on-failure
WorkingDirectory=/usr/share/grafana
RuntimeDirectory=grafana
RuntimeDirectoryMode=0750
ExecStart=/usr/sbin/grafana-server \
--config=${CONF_FILE} \
--pidfile=${PID_FILE_DIR}/grafana-server.pid \
--packaging=deb \
cfg:default.paths.logs=${LOG_DIR} \
cfg:default.paths.data=${DATA_DIR} \
cfg:default.paths.plugins=${PLUGINS_DIR} \
cfg:default.paths.provisioning=${PROVISIONING_CFG_DIR}
LimitNOFILE=10000
TimeoutStopSec=20
CapabilityBoundingSet=
DeviceAllow=
LockPersonality=true
MemoryDenyWriteExecute=false
NoNewPrivileges=true
PrivateDevices=true
PrivateTmp=true
PrivateUsers=true
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectProc=invisible
ProtectSystem=full
RemoveIPC=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
SystemCallArchitectures=native
UMask=0027
[Install]
Alias=grafana.service
WantedBy=multi-user.target
```
Enable service:
```shell=
sudo systemctl daemon-reload
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
```
Open port to access metrics. This is optional and only for external use:
```shell=
sudo ufw allow 3000/tcp
```
#### **Configure Dashboard**
Login to grafana by navigating to webrowser `http://192.168.86.29:3000`. Replace `192.168.86.29` with the IP of your node machine. This is same IP used to ssh.
Default credentials are username and password `admin`. Set a new secure (long) password when prompted by grafana.
##### **Data Source**
1. On the left-hand menu, hover over the gear menu and click on `Data Sources`
2. Then click on the Add Data Source button
3. Hover over the Prometheus card on screen, then click on the Select button
4. Enter http://127.0.0.1:9090/ into the URL field, then click Save & Test
##### **Install Dashboard**
1. Hover over the plus symbol icon in the left-hand menu, then click on Import
2. Copy and paste [the dashboard](https://github.com/JohnnyEBD-LYX/lukso-node-guide/blob/main/grafana/dashboard.json) into the `Import via panel json` text box on the screen
3. Then click the Load button
4. Then click the Import button
##### **Enable Alerts**
1. On the left-hand menu, hover over the alarm menu and click on `Notification channels`
2. Click on `New channel`
3. Select `Type` and [configure](https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/)
On lukso dashboard:
1. Scroll down on a dashboard to `Alerts` section
2. Select each alert and click `Edit`
3. In `Alert` tab, select notifications `send to`
4. Save and repeat for each alert
### Node Exporter
Add user to monitor node stats:
```shell=
sudo adduser --system node_exporter --group --no-create-home
```
Install:
```shell=
cd
wget https://github.com/prometheus/node_exporter/releases/download/v1.5.0/node_exporter-1.5.0.linux-amd64.tar.gz
tar xzvf node_exporter-1.5.0.linux-amd64.tar.gz
sudo cp node_exporter-1.5.0.linux-amd64/node_exporter /usr/local/bin/
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter
rm node_exporter-1.5.0.linux-amd64.tar.gz
rm -rf node_exporter-1.5.0.linux-amd64
```
#### **Configure Service**
```shell=
sudo nano /etc/systemd/system/node_exporter.service
```
The content of service configuration file:
```
[Unit]
Description=Node Exporter
[Service]
Type=simple
Restart=always
RestartSec=5
User=node_exporter
ExecStart=/usr/local/bin/node_exporter
[Install]
WantedBy=multi-user.target
```
Enable service:
```shell=
sudo systemctl daemon-reload
sudo systemctl start node_exporter
sudo systemctl enable node_exporter
```
#### **Node Exporter update script**
In order to easily update Node Exporter you can run this [script](https://raw.githubusercontent.com/eth-educators/ethstaker-guides/main/scripts/update-node-exporter.py). Download and run it with:
```shell=
wget https://raw.githubusercontent.com/eth-educators/ethstaker-guides/main/scripts/update-node-exporter.py
python3 update-node-exporter.py
```
The script will check the current installed version and it will compare it with the latest stable release version on Github. If there is a new version available, it will prompt you to update it.
### Json Exporter
#### **Prerequisites**
Check `go` version if installed:
```shell=
go version
```
If it is less than `1.23.0` please install following:
```shell=
wget https://go.dev/dl/go1.23.0.linux-amd64.tar.gz
sudo tar -xvf go1.23.0.linux-amd64.tar.gz
rm go1.23.0.linux-amd64.tar.gz
sudo mv go /usr/local/go-1.23.0
sudo ln -sf /usr/local/go-1.23.0/bin/go /usr/bin/go
go version
```
#### **Build and Install**
User:
```shell=
sudo adduser --system json_exporter --group --no-create-home
```
Install:
```shell=
cd
git clone https://github.com/prometheus-community/json_exporter.git
cd json_exporter
make build
sudo cp json_exporter /usr/local/bin/
sudo chown json_exporter:json_exporter /usr/local/bin/json_exporter
cd
rm -rf json_exporter
```
#### **Configure**
```shell=
sudo mkdir /etc/json_exporter
sudo chown json_exporter:json_exporter /etc/json_exporter
```
Setup `LYX` token price:
```shell=
sudo nano /etc/json_exporter/json_exporter.yml
```
The content of configuration file:
```
modules:
default:
metrics:
- name: lyxusd
path: "{.lukso-token.usd}"
help: Lukso (LYX) price in USD
```
Change ownership of configuration file:
```shell=
sudo chown json_exporter:json_exporter /etc/json_exporter/json_exporter.yml
```
#### **Configure Service**
```shell=
sudo nano /etc/systemd/system/json_exporter.service
```
The content of service configuration file:
```
[Unit]
Description=JSON Exporter
[Service]
Type=simple
Restart=always
RestartSec=5
User=json_exporter
ExecStart=/usr/local/bin/json_exporter --config.file /etc/json_exporter/json_exporter.yml
[Install]
WantedBy=multi-user.target
```
Enable service:
```shell=
sudo systemctl daemon-reload
sudo systemctl start json_exporter
sudo systemctl enable json_exporter
```
### Ping
Pings google and cloudflare to track latency.
```shell=
sudo adduser --system blackbox_exporter --group --no-create-home
```
Install:
```shell=
cd
wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.25.0/blackbox_exporter-0.25.0.linux-amd64.tar.gz
tar xvzf blackbox_exporter-0.25.0.linux-amd64.tar.gz
sudo cp blackbox_exporter-0.25.0.linux-amd64/blackbox_exporter /usr/local/bin/
sudo chown blackbox_exporter:blackbox_exporter /usr/local/bin/blackbox_exporter
sudo chmod 755 /usr/local/bin/blackbox_exporter
rm blackbox_exporter-0.25.0.linux-amd64.tar.gz
rm -rf blackbox_exporter-0.25.0.linux-amd64
```
Enable ping permissions:
```shell=
sudo setcap cap_net_raw+ep /usr/local/bin/blackbox_exporter
```
#### **Configure**
```shell=
sudo mkdir /etc/blackbox_exporter
sudo chown blackbox_exporter:blackbox_exporter /etc/blackbox_exporter
```
```shell=
sudo nano /etc/blackbox_exporter/blackbox.yml
```
The content of configuration file:
```
modules:
icmp:
prober: icmp
timeout: 10s
icmp:
preferred_ip_protocol: ipv4
```
Change ownership of configuration file:
```shell=
sudo chown blackbox_exporter:blackbox_exporter /etc/blackbox_exporter/blackbox.yml
```
#### **Configure Service**
```shell=
sudo nano /etc/systemd/system/blackbox_exporter.service
```
The content of service configuration file:
```
[Unit]
Description=Blackbox Exporter
[Service]
Type=simple
Restart=always
RestartSec=5
User=blackbox_exporter
ExecStart=/usr/local/bin/blackbox_exporter --config.file /etc/blackbox_exporter/blackbox.yml
[Install]
WantedBy=multi-user.target
```
Enable service:
```shell=
sudo systemctl daemon-reload
sudo systemctl start blackbox_exporter
sudo systemctl enable blackbox_exporter
```
Temps control (sensors command):
```shell=
sudo apt-get install lm-sensors
```
Validator aggregation for monitoring rewards:
```shell=
cat validator.log | grep -o 'index=[0-9]* ' | awk -F'=' '{printf "%s,", $2}' | sed 's/,$//' | tr -d ' ' | awk '{print "https://explorer.consensus.mainnet.lukso.network/dashboard?validators=" $0}'
```
Luksoverse wishes prosperous validation to everyone in hopes that this guide was complete and easy enough to follow. Any suggestions you might have please don't hesitate to reach out to any of us.
> **_Full Disclaimer_**
This article (the guide) is for informational purposes only and does not constitute professional advice. The author does not warrant or guarantee the accuracy, integrity, quality, completeness, currency, or validity of any information in this article. All information herein is provided “as is” without warranty of any kind and is subject to change at any time without notice. The author disclaims all express, implied, and statutory warranties of any kind, including warranties as to accuracy, timeliness, completeness, or fitness of the information in this article for any particular purpose. The author is not responsible for any direct, indirect, incidental, consequential or any other damages arising out of or in connection with the use of this article or in reliance on the information available on this article. This includes any personal injury, business interruption, loss of use, lost data, lost profits, or any other pecuniary loss, whether in an action of contract, negligence, or other misuse, even if the author has been informed of the possibility.
## Credits
- https://github.com/metanull-operator/eth2-ubuntu
- https://github.com/lykhonis/lukso-node-guide
- https://github.com/remyroy/ethstaker
- https://github.com/SomerEsat/ethereum-staking-guides