Installation
A complete guide to running an Espresso Network validator node and applying to the Validator Bootstrap Program.
💢 Table of Contents
- Hardware Requirements
- Step 1 — Install Docker
- Step 2 — Create Directory Structure
- Step 3 — Pull Docker Images
- Step 4 — Generate Validator Keys
- Step 5 — Create Metadata JSON
- Step 6 — Prepare Ethereum Wallet
- Step 7 — Get Ethereum RPC Endpoint
- Step 8 — Register Validator on Ethereum
- Step 9 — Create Environment File
- Step 10 — Create Systemd Service
- Step 11 — Start the Node
- Step 12 — Verify Node Health
- Step 13 — Apply to Bootstrap Program
- Monitoring the Node
- Updating the Node
💢 Hardware Requirements
| Component | Minimum |
|---|---|
| Operating System | Ubuntu 22.04+ |
| CPU | 1 Core (any modern CPU works) |
| RAM | 8 GB |
| Storage | Negligible (kilobytes) |
| Network | Stable internet, public IP required |
| Open Ports | 8585/TCP (API), 9000/UDP (LibP2P) |
✅ This is a Regular Node (non-DA). DA nodes are only required for the DA committee — most operators do not need them.
💢 Step 1 — Install Docker
Install Docker from the official repository (do not use snap or apt install docker.io):
apt-get update && apt-get install -y ca-certificates curl gnupg && \
install -m 0755 -d /etc/apt/keyrings && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
chmod a+r /etc/apt/keyrings/docker.gpg && \
echo "deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \$(. /etc/os-release && echo \"\$VERSION_CODENAME\") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && \
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginVerify installation:
docker --version && systemctl status dockerExpected output: Docker version 29.x.x and active (running).
💢 Step 2 — Create Directory Structure
mkdir -p /opt/espresso/keys /opt/espresso/store| Directory | Purpose |
|---|---|
/opt/espresso/keys | Stores BLS and Schnorr private keys |
/opt/espresso/store | Stores node SQLite database |
💢 Step 3 — Pull Docker Images
Pull the Espresso sequencer image (Mainnet 1):
docker pull ghcr.io/espressosystems/espresso-sequencer/sequencer:20260722Pull the staking CLI image:
docker pull ghcr.io/espressosystems/espresso-sequencer/staking-cli:main💡 The sequencer image is ~500MB and may take a few minutes to download.
⚠️ Note: The official Espresso docs reference
espresso-network/sequenceras the image path, but the correct registry path isespresso-sequencer/sequenceras used above. Use the commands in this guide.
💢 Step 4 — Generate Validator Keys
Run the key generator to create your BLS (staking) and Schnorr (state) keys:
docker run -v /opt/espresso/keys:/keys \
ghcr.io/espressosystems/espresso-sequencer/sequencer:20260407 \
keygen -o /keysThe command produces no terminal output — this is normal. The keys are saved silently to the file. Verify the file was created:
cat /opt/espresso/keys/0.envExpected output:
# Seed: <random_hex>
ESPRESSO_SEQUENCER_PUBLIC_STAKING_KEY=BLS_VER_KEY~...
ESPRESSO_SEQUENCER_PRIVATE_STAKING_KEY=BLS_SIGNING_KEY~...
ESPRESSO_SEQUENCER_PUBLIC_STATE_KEY=SCHNORR_VER_KEY~...
ESPRESSO_SEQUENCER_PRIVATE_STATE_KEY=SCHNORR_SIGNING_KEY~...🔐 CRITICAL: Back up the following immediately to a secure location (password manager, external drive):
Key Prefix Description ESPRESSO_SEQUENCER_PRIVATE_STAKING_KEYBLS_SIGNING_KEY~...Signs consensus messages ESPRESSO_SEQUENCER_PRIVATE_STATE_KEYSCHNORR_SIGNING_KEY~...Signs finalized states Seedhex string Used to regenerate keys Download to your local machine:
scp root@SERVER_IP:/opt/espresso/keys/0.env ./espresso-keys-backup.env⚠️ Never share your private keys or seed with anyone.
⚠️ Each BLS key can only be registered once on the Ethereum mainnet.
💢 Step 5 — Create Metadata JSON
Your validator metadata is hosted publicly and displayed in the Espresso staking dashboard. Nginx must be installed and running on your server.
If nginx is not installed, install it first:
apt-get install -y nginx && systemctl enable nginx && systemctl start nginxGet your server's public IPv4 address:
curl -s -4 ifconfig.meCreate the metadata file (replace the values with your own information):
mkdir -p /var/www/html/espresso && cat > /var/www/html/espresso/metadata.json << 'EOF'
{
"pub_key": "BLS_VER_KEY~YOUR_PUBLIC_STAKING_KEY_HERE",
"name": "YourValidatorName",
"description": "Your description here",
"company_name": "Your Company Name",
"company_website": "https://yourwebsite.com"
}
EOFReplace BLS_VER_KEY~YOUR_PUBLIC_STAKING_KEY_HERE with your ESPRESSO_SEQUENCER_PUBLIC_STAKING_KEY value from Step 4.
Test that it is accessible:
curl -s http://YOUR_SERVER_IP/espresso/metadata.jsonExpected output: the JSON content you just created.
💡 The
pub_keyfield must match your registered BLS key — this prevents impersonation on the dashboard.
💢 Step 6 — Prepare Ethereum Wallet
You need a dedicated Ethereum wallet for this validator. Do not reuse existing wallets.
- Create a new wallet in MetaMask (or any Ethereum wallet)
- Save the 12-word seed phrase securely
- Note the Ethereum address (starts with
0x) - Send 0.01–0.02 ETH (Ethereum Mainnet) to this address for gas fees
⚠️ Registration costs approximately 300,000 gas (~$1–2 at current prices).
⚠️ Each Ethereum address can only register one validator.
⚠️ Do NOT send ETH on any other chain (not BSC, not Polygon — Ethereum Mainnet only).
💢 Step 7 — Get Ethereum RPC Endpoint
You need an Ethereum Mainnet RPC endpoint for the validator to read from L1.
Recommended: Infura (free tier — 3M credits/day, more than sufficient)
- Go to infura.io and create a free account
- Create a new project → select Ethereum
- Copy your API key
Your endpoints will be:
- HTTP:
https://mainnet.infura.io/v3/YOUR_API_KEY - WebSocket:
wss://mainnet.infura.io/ws/v3/YOUR_API_KEY
💡 A regular Espresso node uses approximately 15,000–20,000 API requests per day — well within the free tier limit.
💢 Step 8 — Register Validator on Ethereum
This step registers your validator in the Espresso stake table contract on Ethereum mainnet. You only need to do this once.
Run the registration command (replace all placeholder values):
docker run --rm \
-e MNEMONIC="your twelve word seed phrase here" \
-e ACCOUNT_INDEX=0 \
-e L1_PROVIDER="https://mainnet.infura.io/v3/YOUR_API_KEY" \
-e STAKE_TABLE_ADDRESS="0xCeF474D372B5b09dEfe2aF187bf17338Dc704451" \
-e CONSENSUS_PRIVATE_KEY="BLS_SIGNING_KEY~YOUR_PRIVATE_STAKING_KEY" \
-e STATE_PRIVATE_KEY="SCHNORR_SIGNING_KEY~YOUR_PRIVATE_STATE_KEY" \
ghcr.io/espressosystems/espresso-sequencer/staking-cli:main \
staking-cli register-validator \
--commission 10.00 \
--metadata-uri "http://YOUR_SERVER_IP/espresso/metadata.json"| Parameter | Description |
|---|---|
MNEMONIC | Your 12-word seed phrase (in quotes, space-separated) |
ACCOUNT_INDEX | Derivation index, use 0 for the first account |
L1_PROVIDER | Your Infura HTTP RPC URL |
CONSENSUS_PRIVATE_KEY | Your BLS_SIGNING_KEY~... from Step 4 |
STATE_PRIVATE_KEY | Your SCHNORR_SIGNING_KEY~... from Step 4 |
--commission | Your commission rate (0.00–100.00) |
--metadata-uri | URL to your metadata.json from Step 5 |
Successful output:
Success! transaction hash: 0x...
event: ValidatorRegisteredV2 { account: 0xYOUR_ADDRESS, blsVK: BLS_VER_KEY~..., ... }After running, clear your terminal history immediately:
history -c && history -w⚠️ Note your Ethereum account address from the output — you will need it for the Bootstrap Program form.
💢 Step 9 — Create Environment File
Create the environment configuration file for the node:
cat > /opt/espresso/espresso.env << 'EOF'
ESPRESSO_SEQUENCER_CDN_ENDPOINT=cdn.main.net.espresso.network:1737
ESPRESSO_STATE_RELAY_SERVER_URL=https://state-relay.main.net.espresso.network
ESPRESSO_SEQUENCER_GENESIS_FILE=/genesis/mainnet.toml
ESPRESSO_SEQUENCER_EMBEDDED_DB=true
RUST_LOG=warn,libp2p=off
RUST_LOG_FORMAT=json
ESPRESSO_SEQUENCER_STATE_PEERS=https://query.main.net.espresso.network
ESPRESSO_SEQUENCER_CONFIG_PEERS=https://cache.main.net.espresso.network
ESPRESSO_SEQUENCER_L1_PROVIDER=https://mainnet.infura.io/v3/YOUR_API_KEY
ESPRESSO_SEQUENCER_L1_WS_PROVIDER=wss://mainnet.infura.io/ws/v3/YOUR_API_KEY
ESPRESSO_SEQUENCER_API_PORT=8585
ESPRESSO_SEQUENCER_STORAGE_PATH=/store
ESPRESSO_SEQUENCER_KEY_FILE=/keys/0.env
ESPRESSO_SEQUENCER_LIBP2P_BIND_ADDRESS=0.0.0.0:9000
ESPRESSO_SEQUENCER_LIBP2P_ADVERTISE_ADDRESS=YOUR_SERVER_IP:9000
EOFReplace:
YOUR_API_KEY→ your Infura API key (in both HTTP and WS lines)YOUR_SERVER_IP→ your server's public IPv4 address
Verify the file:
cat /opt/espresso/espresso.env💢 Step 10 — Create Systemd Service
Create the systemd service file that manages the Docker container:
cat > /etc/systemd/system/espresso.service << 'EOF'
[Unit]
Description=Espresso Sequencer Node
After=docker.service
Requires=docker.service
[Service]
TimeoutStartSec=0
Restart=always
RestartSec=10
ExecStartPre=-/usr/bin/docker stop espresso
ExecStartPre=-/usr/bin/docker rm espresso
ExecStart=/usr/bin/docker run --name espresso \
--env-file /opt/espresso/espresso.env \
-v /opt/espresso/keys:/keys \
-v /opt/espresso/store:/store \
-p 8585:8585 \
-p 9000:9000/udp \
ghcr.io/espressosystems/espresso-sequencer/sequencer:20260407 \
sequencer -- http -- catchup -- status
ExecStop=/usr/bin/docker stop espresso
[Install]
WantedBy=multi-user.target
EOF💢 Step 11 — Start the Node
Enable and start the service:
systemctl daemon-reload && \
systemctl enable espresso && \
systemctl start espressoCheck the service status:
systemctl status espressoExpected output: active (running).
View live logs:
journalctl -u espresso -n 50 --no-pager💡 On first startup, the node loads network config from peers. This may take 10–30 seconds. You will see:
loaded configand view numbers incrementing — this is normal and expected.
💢 Step 12 — Verify Node Health
Healthcheck (all modules should return 200):
curl -s http://localhost:8585/healthcheckExpected output:
{"status":"available","modules":{"catchup":{"0":200,"1":200},"state-signature":{"0":200,"1":200},"status":{"0":200,"1":200}}}Verify your validator appears on the dashboard:
- Go to stake.espresso.network
- Search for your Ethereum address:
0xYOUR_ADDRESS - Your validator should appear with status
INACTIVE(this is correct — it becomesACTIVEafter receiving delegation)
✅ What is normal:
WARNlevel logs — expected behaviorVote sending timed out— node is trying to participate but has no delegation yetLCV3 signature posted by nodes not on the stake table— expected until delegation arrives- View numbers advancing every ~1 second — this confirms the node is following the chain
❌ What is NOT normal:
- Service showing
failedorinactive (dead)- Healthcheck not returning 200
- View numbers stuck for more than 5 minutes
💢 Step 13 — Apply to Bootstrap Program
The Espresso Foundation Validator Bootstrap Program offers up to 30 selected validators an initial delegation of 1,000,000 ESP.
Apply here: Bootstrap Program Application Form
| Field | Value |
|---|---|
| Operator name | Your operator/company name |
| Operator website | Your website URL |
| Primary contact name | Your name |
| Primary contact email | Your email (optional) |
| Telegram / Discord handle | Your handle |
| Ethereum account | The address used in Step 8 (e.g. 0xCaA51...) |
| Region | Your server's region (e.g. EU - Finland) |
| Validator experience | Describe your infrastructure experience |
💡 The Foundation evaluates operators on uptime, missed slots, responsiveness, and software update speed. Every 6 months, top-performing validators become eligible for the main delegation program (larger delegation).
💢 Monitoring the Node
Check service status:
systemctl status espressoView last 50 log lines:
journalctl -u espresso -n 50 --no-pagerHealthcheck:
curl -s http://localhost:8585/healthcheckCheck connected peers:
curl -s http://localhost:8585/status/metrics | grep libp2p_num_connected_peersRestart the node:
systemctl restart espressoStop the node:
systemctl stop espresso💢 Updating the Node
When a new image version is released:
- Pull the new image:
docker pull ghcr.io/espressosystems/espresso-sequencer/sequencer:NEW_TAG- Update the tag in the systemd service file:
nano /etc/systemd/system/espresso.serviceReplace 20260407 with the new tag.
- Reload and restart:
systemctl daemon-reload && systemctl restart espresso- Verify the node is running:
systemctl status espresso && curl -s http://localhost:8585/healthcheck💡 Stay updated via the Espresso Network GitHub Releases page.
