Lumera Protocol
Validators (Testnet)

Node Setup

Install dependencies, build lumerad, and sync your lumera testnet node using a snapshot.

Step 1: Install Dependencies

SSH into your server then update the system and install the required packages:

sudo apt update && sudo apt upgrade -y
sudo apt install build-essential jq curl git wget lz4 unzip gpg -y

Step 2: Install Go

Use the version pinned in the chain's go.mod, currently Go 1.26.2.

GO_VERSION=1.26.2
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf /tmp/go.tar.gz
 
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.profile
source ~/.profile
go version
 
# go version go1.26.2 linux/amd64

Step 3: Install lumerad

Lumera publishes a prebuilt linux/amd64 binary for every release, so there is nothing to compile. Run the version testnet is on, currently v1.20.1.

# what testnet is running right now
curl -fsSL https://lumera-testnet-rpc.polkachu.com/abci_info | jq -r .result.response.version
# 1.20.1
 
LUMERA_VERSION=v1.20.1
 
mkdir -p ~/lumera-install && cd ~/lumera-install
curl -fsSL -O "https://github.com/LumeraProtocol/lumera/releases/download/${LUMERA_VERSION}/release_checksum"
 
# the archive is named differently across releases, so take the name from the checksum
ASSET=$(awk '{print $2}' release_checksum)
curl -fsSL -O "https://github.com/LumeraProtocol/lumera/releases/download/${LUMERA_VERSION}/${ASSET}"

Verify the download before you install it.

sha256sum -c release_checksum
# Expected: <archive>: OK

If this prints FAILED, stop. Delete the files and download them again. Do not install an unverified binary on a machine that will hold a consensus key.

Extract the archive and run the bundled installer. It copies lumerad into /usr/local/bin, installs libwasmvm.x86_64.so into /usr/lib, and refreshes the linker cache.

tar -xzf "$ASSET"
sudo ./install.sh

Confirm the binary runs.

lumerad version
# 1.20.1 — must match what the chain reports above

Step 4: Initialize the Node

Pick a moniker. This is the public name for your validator. Replace my-validator with your own name, then initialize.

MONIKER="my-validator"
lumerad init "$MONIKER" --chain-id lumera-testnet-2

This creates ~/.lumera with a config/ directory. It generates your node key and consensus key, and writes default config.toml, app.toml, and client.toml.

Back up your keys right away.

mkdir -p ~/lumera-key-backup
chmod 700 ~/lumera-key-backup
cp ~/.lumera/config/priv_validator_key.json ~/lumera-key-backup/
cp ~/.lumera/config/node_key.json ~/lumera-key-backup/
chmod 600 ~/lumera-key-backup/*.json
chmod 600 ~/.lumera/config/priv_validator_key.json ~/.lumera/config/node_key.json

priv_validator_key.json is your validator identity. Anyone who holds it can double-sign on your behalf. That is punished by permanent tombstoning and a slash of your stake. Copy these files off the server to encrypted offline storage now. Verify you can restore them. Never run two nodes with the same key.

Step 5: Download and Verify Genesis

Download the testnet genesis file and check its hash.

GENESIS_URL="https://raw.githubusercontent.com/LumeraProtocol/lumera-networks/master/testnet-2/genesis.json"
GENESIS_SHA256="8d30d41d2711b43d1f27f49816c68c6bafb799f0f08fb7e4a6676c4158150031"
 
curl -fsSL -o ~/.lumera/config/genesis.json "$GENESIS_URL"
echo "$GENESIS_SHA256  $HOME/.lumera/config/genesis.json" | sha256sum -c -
# Expected: ...genesis.json: OK

Confirm the chain ID inside the file.

jq -r .chain_id ~/.lumera/config/genesis.json
# Expected: lumera-testnet-2

Step 6: Configure the Node

Set the seed node and the minimum gas price.

SEEDS="faff7c1350468c53121a669ac40e317a4a70c425@seeds.testnet.lumera.io:26656"
 
sed -i "s|^seeds *=.*|seeds = \"$SEEDS\"|" "$HOME/.lumera/config/config.toml"
sed -i "s|^minimum-gas-prices *=.*|minimum-gas-prices = \"0.025ulume\"|" "$HOME/.lumera/config/app.toml"

Load a maintained address book so a new node has peers to dial if the seed is unreachable.

curl -fsSL -o "$HOME/.lumera/config/addrbook.json" \
  https://snapshots.polkachu.com/testnet-addrbook/lumera/addrbook.json

Enable pruning so disk usage stays under control. Skip this only if you specifically need an archive node.

sed -i \
  -e 's|^pruning *=.*|pruning = "custom"|' \
  -e 's|^pruning-keep-recent *=.*|pruning-keep-recent = "100"|' \
  -e 's|^pruning-interval *=.*|pruning-interval = "10"|' \
  "$HOME/.lumera/config/app.toml"
 
sed -i 's|^indexer *=.*|indexer = "null"|' "$HOME/.lumera/config/config.toml"
StrategyKeepsDisk usage
defaultLast 362,880 statesMedium
nothingEverything (full archive)Very high
everythingLast 2 states onlyLowest
customWhatever you set aboveConfigurable

indexer = "null" turns off the transaction indexer and saves disk. Leave it as "kv" if you need to query historical transactions by hash from this node.

Turn on Prometheus metrics.

sed -i 's|^prometheus *= *false|prometheus = true|' "$HOME/.lumera/config/config.toml"

Bind the RPC to localhost. A validator only needs the P2P port reachable.

sed -i "/^\[rpc\]/,/^\[/{ s|^laddr *=.*|laddr = \"tcp://127.0.0.1:26657\"| }" "$HOME/.lumera/config/config.toml"
 
# [rpc] should be 127.0.0.1:26657, [p2p] still 0.0.0.0:26656
grep -n "^laddr" "$HOME/.lumera/config/config.toml"

lumerad can listen on the ports below. Everything except 26656 should be firewalled or bound to 127.0.0.1.

PortServiceConfig key
26656P2P (must be reachable)config.toml[p2p].laddr
26657CometBFT RPCconfig.toml[rpc].laddr
1317REST API (LCD)app.toml[api].address
9090gRPCapp.toml[grpc].address
8545EVM JSON-RPC (HTTP)app.toml[json-rpc].address
8546EVM JSON-RPC (WebSocket)app.toml[json-rpc].ws-address

Step 7: Harden the Server

Firewall

Allow SSH and the P2P port. Deny everything else inbound.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 26656/tcp comment "Lumera P2P"
sudo ufw --force enable
sudo ufw status

Dedicated user

Run the node as its own user rather than root.

sudo useradd -m -s /bin/bash validator
sudo usermod -aG sudo validator
sudo passwd validator
 
# Give it your SSH key
sudo rsync --archive --chown=validator:validator ~/.ssh /home/validator/

Confirm ssh validator@YOUR_SERVER_IP and sudo -v both work from a second terminal now. The next section disables root SSH, so if this account is not reachable you lose access to the server.

Move the node directory from Step 4 across, so ~/.lumera resolves to the same data before and after the switch.

sudo rsync -a ~/.lumera ~/lumera-key-backup /home/validator/
sudo chown -R validator:validator /home/validator/.lumera /home/validator/lumera-key-backup
 
# Drop the originals only once the consensus key is confirmed identical
sudo diff ~/.lumera/config/priv_validator_key.json \
          /home/validator/.lumera/config/priv_validator_key.json \
  && sudo rm -rf ~/.lumera ~/lumera-key-backup

Switch users. Steps 8 to 10 and the whole of Create Validator run as validator, and $HOME must already be /home/validator when you write the systemd unit in Step 9.

su - validator

Do the move before Step 8. Migrating afterwards means shifting the whole synced database instead of a few config files.

SSH

Harden SSH on a machine that holds a consensus key. Disable password logins and root SSH.

This locks root out of SSH. Do not run it until the user above exists and you have logged in as it.

Drop-ins in /etc/ssh/sshd_config.d/ override the main file. Check for conflicting values first.

grep -rn -iE "permitrootlogin|passwordauthentication" /etc/ssh/sshd_config.d/ 2>/dev/null
sudo sed -i \
  -e 's|^#\?PermitRootLogin.*|PermitRootLogin no|' \
  -e 's|^#\?PasswordAuthentication.*|PasswordAuthentication no|' \
  -e 's|^#\?MaxAuthTries.*|MaxAuthTries 3|' \
  /etc/ssh/sshd_config
 
# Ubuntu 24.04+ activates SSH through a socket unit. Restart whichever one is in use.
if systemctl is-active --quiet ssh.socket; then
  sudo systemctl restart ssh.socket
else
  sudo systemctl restart ssh
fi

Verify the settings actually took effect:

sudo sshd -T | grep -iE "^permitrootlogin|^passwordauthentication|^maxauthtries"
# Expected: permitrootlogin no / passwordauthentication no / maxauthtries 3

Keep your current session open and confirm you can log in from a second terminal before closing it. The new config applies to the next connection. Locking yourself out of a validator means downtime and eventual jailing.

Do not open 26657 (RPC), 1317 (LCD), 9090 (gRPC), or 8545 and 8546 (EVM JSON-RPC) on a validator. Exposing RPC publicly is a common cause of DDoS-induced downtime and jailing. Run a separate full node if you need to serve those endpoints. In a sentry setup, the validator should accept inbound connections only from its sentries.

Step 8: Sync the Chain

Pick one of the two options below. The snapshot is fastest and is the recommended path.

Copy the current URL from Polkachu's Lumera testnet snapshots, currently about 55 GB.

# example — the height changes daily
SNAP_URL="https://snapshots.polkachu.com/testnet-snapshots/lumera/lumera_5875101.tar.lz4"

Reset local state, then stream the snapshot straight into the data directory.

lumerad comet unsafe-reset-all --home "$HOME/.lumera" --keep-addr-book
curl -o - -L "$SNAP_URL" | lz4 -c -d - | tar -x -C "$HOME/.lumera"

Option B: State sync

State sync fetches a verified state snapshot over the P2P layer instead of downloading a database. It uses no third-party storage. It depends on the RPC provider having snapshots enabled.

SNAP_RPC="https://lumera-testnet-rpc.polkachu.com:443"
 
LATEST_HEIGHT=$(curl -fsSL "$SNAP_RPC/block" | jq -r .result.block.header.height)
TRUST_HEIGHT=$((LATEST_HEIGHT - 2000))
TRUST_HASH=$(curl -fsSL "$SNAP_RPC/block?height=$TRUST_HEIGHT" | jq -r .result.block_id.hash)
echo "trust_height=$TRUST_HEIGHT trust_hash=$TRUST_HASH"
 
sed -i "/^\[statesync\]/,/^\[/{
  s|^enable *=.*|enable = true|
  s|^rpc_servers *=.*|rpc_servers = \"$SNAP_RPC,$SNAP_RPC\"|
  s|^trust_height *=.*|trust_height = $TRUST_HEIGHT|
  s|^trust_hash *=.*|trust_hash = \"$TRUST_HASH\"|
  s|^trust_period *=.*|trust_period = \"168h0m0s\"|
}" "$HOME/.lumera/config/config.toml"
 
lumerad comet unsafe-reset-all --home "$HOME/.lumera" --keep-addr-book

The edit is scoped to the [statesync] section. Confirm the result before you start.

sed -n '/\[statesync\]/,/^\[/p' "$HOME/.lumera/config/config.toml" | head -20

If state sync stalls at "discovering snapshots" for more than a few minutes, no peer is serving snapshots. Fall back to Option A.

Do not try to replay the chain from block 1 with a single current binary. The chain has passed through many governance upgrades. Replaying historical blocks needs the binary that was live at each height. Use a snapshot or state sync.

Step 9: Create the systemd Service

Create the service unit. $USER and which lumerad resolve on their own, so you can paste this as is.

sudo tee /etc/systemd/system/lumera.service > /dev/null <<EOF
[Unit]
Description=Lumera Testnet Validator Node
After=network-online.target
Wants=network-online.target
 
[Service]
User=$USER
ExecStart=$(which lumerad) start --home $HOME/.lumera
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
 
[Install]
WantedBy=multi-user.target
EOF
 
sudo systemctl daemon-reload
sudo systemctl enable lumera

Before your first upgrade, switch this unit to run under Cosmovisor so binary swaps happen automatically at the upgrade height. See Operations, Chain Upgrades.

Step 10: Start and Verify

Start the node and watch the logs.

sudo systemctl start lumera
sudo journalctl -fu lumera

You should see blocks being committed.

INF committed state height=5830900 module=state

Press Ctrl+C to stop tailing. This does not stop the node.

Wait a minute or two, then check the sync status.

lumerad status 2>&1 | jq '.sync_info | {latest_block_height, catching_up}'

Wait until catching_up is false. Compare your height against the live chain.

echo "local : $(lumerad status 2>&1 | jq -r .sync_info.latest_block_height)"
echo "chain : $(curl -fsSL https://lumera-testnet-rpc.polkachu.com/status | jq -r .result.sync_info.latest_block_height)"

Confirm you have peers.

lumerad status 2>&1 | jq '.node_info.id'
curl -fsSL localhost:26657/net_info | jq -r '.result.n_peers'

If zero peers persists, check the logs. Couldn't connect to any seeds with connection refused means the seed is down. In that case, stop the node, refresh seeds from the chain-registry and install a current addrbook, then start it again — config.toml is only read at startup, so edits do nothing until you restart.

Verification Checklist

Everything below should pass before you create your validator.

lumerad version                                                  # prints a version
systemctl is-active lumera                                       # active
lumerad status 2>&1 | jq -r .sync_info.catching_up               # false
lumerad status 2>&1 | jq -r .node_info.network                   # lumera-testnet-2
curl -fsSL localhost:26657/net_info | jq -r .result.n_peers      # 1 or more
sudo ufw status | grep 26656                                     # ALLOW

Next Steps

Once catching_up is false, register your validator.

Edit this page