🟤 Espresso Network Mainnet 1 — Validator Node Setup Guide (English)
A complete guide to running an Espresso Network validator node and applying to the Validator Bootstrap Program
Docker installation, key generation, validator registration, systemd service setup — step by step.
Author: HazenNetworkSolutions
Network: Espresso Mainnet 1
Image Tag: 20260828
Last Updated: 31 August 2026
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 8b — Register P2P Address and x25519 Key (Cliquenet)
- 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
- Troubleshooting
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, legacy), 9977/TCP (Cliquenet P2P, required for fast finality upgrade) |
✅ 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-plugin
Verify installation:
docker --version && systemctl status docker
Expected 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:20260828
Pull 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:20260828 \
keygen -o /keys
The 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.env
Expected 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~...
Next, generate the x25519 key (required for the upcoming Cliquenet protocol upgrade) and append it to the same file:
docker run --rm \
-v /opt/espresso/keys:/keys \
ghcr.io/espressosystems/espresso-sequencer/sequencer:20260828 \
keygen --scheme x25519 -o /keys
This command overwrites 0.env with only the x25519 key. You must manually reconstruct the full key file by combining all keys:
cat > /opt/espresso/keys/0.env << 'EOF'
# Seed: YOUR_ORIGINAL_SEED_HERE
ESPRESSO_SEQUENCER_PUBLIC_STAKING_KEY=BLS_VER_KEY~YOUR_BLS_PUBLIC_KEY
ESPRESSO_SEQUENCER_PRIVATE_STAKING_KEY=BLS_SIGNING_KEY~YOUR_BLS_PRIVATE_KEY
ESPRESSO_SEQUENCER_PUBLIC_STATE_KEY=SCHNORR_VER_KEY~YOUR_SCHNORR_PUBLIC_KEY
ESPRESSO_SEQUENCER_PRIVATE_STATE_KEY=SCHNORR_SIGNING_KEY~YOUR_SCHNORR_PRIVATE_KEY
ESPRESSO_SEQUENCER_PUBLIC_X25519_KEY=YOUR_X25519_PUBLIC_KEY
ESPRESSO_SEQUENCER_PRIVATE_X25519_KEY=X25519_SK~YOUR_X25519_PRIVATE_KEY
EOF
Verify all 3 public keys are present:
grep "PUBLIC" /opt/espresso/keys/0.env
You should see 3 lines: PUBLIC_STAKING_KEY, PUBLIC_STATE_KEY, PUBLIC_X25519_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 ESPRESSO_SEQUENCER_PRIVATE_X25519_KEYX25519_SK~...Required for Cliquenet protocol upgrade 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 nginx
Get your server's public IPv4 address:
curl -s -4 ifconfig.me
Create 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"
}
EOF
Replace 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.json
Expected output: the JSON content you just created.
💡 The
pub_keyfield must match your registered BLS key — this prevents impersonation on the dashboard.
Adding a Validator Logo (Optional)
You can display your logo on the Espresso staking dashboard by adding an icon field to your metadata.
1. Prepare your logo image (JPG or PNG, minimum 400x400px recommended) and copy it to the server:
scp /path/to/logo.jpg root@YOUR_SERVER_IP:/var/www/html/espresso/logo.jpg
2. Install ImageMagick and generate icon sizes:
apt-get install -y imagemagick && \
cd /var/www/html/espresso/ && \
convert logo.jpg -resize 14x14 [email protected] && \
convert logo.jpg -resize 28x28 [email protected] && \
convert logo.jpg -resize 42x42 [email protected] && \
convert logo.jpg -resize 24x24 [email protected] && \
convert logo.jpg -resize 48x48 [email protected] && \
convert logo.jpg -resize 72x72 [email protected] && \
chown www-data:www-data icon-*.png && \
chmod 644 icon-*.png
3. Update metadata.json with the icon URLs:
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",
"client_version": "20260828",
"icon": {
"14x14": {
"@1x": "https://YOUR_DOMAIN/espresso/[email protected]",
"@2x": "https://YOUR_DOMAIN/espresso/[email protected]",
"@3x": "https://YOUR_DOMAIN/espresso/[email protected]"
},
"24x24": {
"@1x": "https://YOUR_DOMAIN/espresso/[email protected]",
"@2x": "https://YOUR_DOMAIN/espresso/[email protected]",
"@3x": "https://YOUR_DOMAIN/espresso/[email protected]"
}
}
}
EOF
⚠️ Icon URLs must use HTTPS — plain
http://URLs are not rendered by the staking dashboard.
💡 No node restart required — metadata changes take effect immediately.
4. Preview and validate metadata before publishing:
docker run --rm \
ghcr.io/espressosystems/espresso-sequencer/staking-cli:main \
staking-cli preview-metadata --metadata-uri http://YOUR_SERVER_IP/espresso/metadata.json
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.
🔄 Alternative providers: If you notice a high missed-vote rate on the staking dashboard, it can be caused by L1 provider latency or intermittent 401/timeout errors. In that case, switching to ValidationCloud or Tenderly (both offer generous free tiers) can help. Just replace the
L1_PROVIDER/L1_WS_PROVIDERvalues in Step 9 with the new endpoints and restart the service — no re-registration needed.
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 8b — Register P2P Address and x25519 Key (Cliquenet)
Mainnet is upgrading to a new fast-finality protocol with a new P2P networking layer called Cliquenet. This replaces the old UDP-based LibP2P layer with an authenticated, encrypted TCP mesh. Every validator must publish an x25519 public key and a P2P address (host:port) on the stake table contract — this is a one-time registration, separate from Step 8.
You already generated an x25519 keypair in Step 4. Derive the public key from it using the current node image (the format changed over time, so always re-derive with the image tag you're actually running):
docker run --rm -v /opt/espresso/keys:/keys \
ghcr.io/espressosystems/espresso-sequencer/sequencer:20260828 \
pub-key --scheme x25519 --key-file /keys/0.env
Expected output: X25519_PK~...
⚠️ If this output does not match the
ESPRESSO_SEQUENCER_PUBLIC_X25519_KEYvalue already stored in0.env, trust the freshly derived value — the private key is the source of truth, and the node will present whatever public key the current binary derives from it at runtime. Update0.envwith the correct value before continuing.
Register the key and P2P address on the stake table contract:
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" \
ghcr.io/espressosystems/espresso-sequencer/staking-cli:main \
staking-cli update-network-config \
--x25519-key X25519_PK~YOUR_DERIVED_PUBLIC_KEY \
--p2p-addr YOUR_SERVER_IP:9977
Use the same wallet (mnemonic + account index) that registered the validator in Step 8.
Successful output:
Success! transaction hash: 0x...
event: X25519KeyUpdated { validator: 0xYOUR_ADDRESS, x25519Key: 0x... }
event: P2pAddrUpdated { validator: 0xYOUR_ADDRESS, p2pAddr: YOUR_SERVER_IP:9977 }
Requirements for the P2P address:
| Requirement | Detail |
|---|---|
| Reachability | Must be reachable over TCP from the public internet on port 9977 (or your custom ESPRESSO_NODE_CLIQUENET_BIND_ADDRESS port) |
| Address type | Public IP or DNS name — never private/loopback |
| Outgoing traffic | If registering an IP, the node's outgoing connections must also originate from that same IP. Peers verify the source IP of every incoming connection against the registered address |
| Behind a load balancer / NAT with a different egress IP | Register a DNS name instead of an IP — this disables the source-IP check |
💡 Timing: A registered address takes effect after one full epoch (~1 day). Until the fast-finality upgrade actually activates on Mainnet, registration mistakes can be fixed without consequence — but double-check before the upgrade date, since afterward an incorrect/unreachable address will affect your node's participation until a corrected registration takes effect.
💡 You can verify your outgoing IP matches your server's public IP with
curl -s -4 ifconfig.me— if it doesn't match, you're likely behind NAT/a load balancer and should register a DNS name.
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
ESPRESSO_NODE_CLIQUENET_BIND_ADDRESS=0.0.0.0:9977
ESPRESSO_NODE_STORAGE_PATH=/store
ESPRESSO_NODE_TELEMETRY_LOGS_ENABLE=true
ESPRESSO_NODE_TELEMETRY_METRICS_ENABLE=true
ESPRESSO_NODE_IDENTITY_COMPANY_NAME=Your Company Name
ESPRESSO_NODE_IDENTITY_NODE_NAME=YourValidatorName
EOF
Replace:
YOUR_API_KEY→ your Infura API key (in both HTTP and WS lines)YOUR_SERVER_IP→ your server's public IPv4 addressESPRESSO_NODE_IDENTITY_COMPANY_NAME/ESPRESSO_NODE_IDENTITY_NODE_NAME→ your operator identity (same values ascompany_name/nameinmetadata.jsonfrom Step 5)
💡 Since the
20260710release: ifESPRESSO_SEQUENCER_STORAGE_PATHis set,ESPRESSO_NODE_STORAGE_PATHmust be set to the same value. Telemetry vars let the Foundation collect your logs/metrics for network health monitoring — enabling them is recommended but optional. Identity vars are used to label your node in Foundation-side dashboards.💡 Since the
20260828release (fast-finality staging):ESPRESSO_NODE_CLIQUENET_BIND_ADDRESS(default9977) is required for the new Cliquenet P2P layer used in Step 8b. Your key file (ESPRESSO_SEQUENCER_KEY_FILE/ESPRESSO_NODE_KEY_FILE) must contain a valid x25519 private key — either the deprecatedESPRESSO_SEQUENCER_PRIVATE_X25519_KEYor the currentESPRESSO_NODE_PRIVATE_X25519_KEYname both work, but if you use a mnemonic instead of a key file, setESPRESSO_NODE_KEY_MNEMONICdirectly.
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 \
-p 9977:9977/tcp \
ghcr.io/espressosystems/espresso-sequencer/sequencer:20260828 \
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 espresso
Check the service status:
systemctl status espresso
Expected 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/healthcheck
Expected output:
{"status":"available","modules":{"catchup":{"0":200,"1":200},"state-signature":{"0":200,"1":200},"status":{"0":200,"1":200}}}
⚠️ Since the
20260828release: the/healthcheckresponse format changed —modulesmay come back empty ({"status":"available","modules":{}}) even on a healthy node. If you have external monitoring that checks the root/endpoint or parses the oldmodulesstructure, switch it to/v1/status/metricsor/v1/status/block-heightinstead — these are the endpoints the Foundation recommends going forward.
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).
Backup & Recovery
What Must Be Backed Up
| File / Info | Critical | Notes |
|---|---|---|
/opt/espresso/keys/0.env | 🔴 YES | Contains all 3 private keys — cannot be recovered if lost |
| Ethereum wallet mnemonic | 🔴 YES | Required for all L1 operations (rewards, commission, deregister) |
/opt/espresso/espresso.env | 🟡 Recommended | Infura key + server IP — easily recreated but good to have |
Backing Up Keys
Before running any keygen command, always create a backup first:
cp /opt/espresso/keys/0.env /opt/espresso/keys/0.env.backup
Download 0.env to your local machine:
scp root@YOUR_SERVER_IP:/opt/espresso/keys/0.env ~/espresso-keys-backup.env
Save the contents in a password manager (Bitwarden, 1Password, etc.).
⚠️ Warning: The
keygen --scheme x25519command overwrites0.enventirely. Always back up before running any keygen command.
Recovery: Moving to a New Server
If you lose access to your server but have your 0.env backup:
- Set up a new server following this guide from Step 1
- Restore your key file:
scp ~/espresso-keys-backup.env root@NEW_SERVER_IP:/opt/espresso/keys/0.env - Update
ESPRESSO_SEQUENCER_LIBP2P_ADVERTISE_ADDRESSinespresso.envwith the new server IP - Update
metadata.jsonwith the new server IP (if using IP-based URL) - Start the node — no re-registration on Ethereum needed, your validator identity is preserved
Monitoring the Node
Check service status:
systemctl status espresso
View last 50 log lines:
journalctl -u espresso -n 50 --no-pager
Healthcheck:
curl -s http://localhost:8585/healthcheck
Check connected peers:
curl -s http://localhost:8585/status/metrics | grep libp2p_num_connected_peers
Restart the node:
systemctl restart espresso
Stop the node:
systemctl stop espresso
Updating the Node
When a new image version is released (announced in the Espresso Discord #mainnet-node-operator channel):
- Pull the new image:
docker pull ghcr.io/espressosystems/espresso-sequencer/sequencer:NEW_TAG
- Update the tag in the systemd service file (replace
OLD_TAGwith the currently running tag):
sed -i 's/sequencer:OLD_TAG/sequencer:NEW_TAG/g' /etc/systemd/system/espresso.service
-
If the release notes mention new/renamed environment variables, add them to
/opt/espresso/espresso.env(old variables usually keep working, but it's best to migrate). -
Reload and restart:
systemctl daemon-reload && systemctl restart espresso
- Check startup logs for deprecated env var warnings:
sleep 15 && journalctl -u espresso --no-hostname -o cat -n 200 | grep -i "warning:"
- Verify the node is running and on the correct version:
systemctl status espresso && \
curl -s http://localhost:8585/healthcheck && \
curl -s http://localhost:8585/v1/status/metrics | grep consensus_version
- Update
client_versionin your public metadata file:
sed -i 's/OLD_TAG/NEW_TAG/g' /var/www/html/espresso/metadata.json
💡 Stay updated via the Espresso Network GitHub Releases page and the Discord
#mainnet-node-operatorchannel.⚠️ Some releases include a DB migration for query nodes (nodes running the
querymodule). If yourExecStartcommand does not includequeryin the module list, this does not apply to you. Query node operators should check/database/migration-statusafter updating — migrations can take up to several weeks and rolling back the binary during a migration is not supported.
Troubleshooting
High missed-vote rate on the dashboard:
- Check
consensus_number_of_timeoutsin/v1/status/metrics— if it's climbing fast, something is wrong. - Check logs for
Event sender queue overflow(ERROR level) — this indicates the node's internal event queue can't keep up, often caused by CPU/RAM contention from other services on the same server. Stop unrelated services andsystemctl restart espressoto clear the queue. - Check logs for
L1 client error/401— your L1 RPC provider may be rate-limited or misconfigured. See the alternative providers note in Step 7. AutoNAT: probe reports this node may not be publicly reachableright after a restart is usually transient — recheck after a minute. If it persists, verify port9000/UDPis open andESPRESSO_SEQUENCER_LIBP2P_ADVERTISE_ADDRESSmatches your real public IP.
Node not signing at all:
- Verify
consensus_last_voted_viewis close toconsensus_current_view(within 1–2) via/v1/status/metrics. - Verify your BLS key in
0.envmatches the key used at registration — akeygencommand run without care can silently overwrite0.env(see Backup & Recovery section).
cliquenet::connection "Connection refused" warnings in logs after the 20260828+ update:
- This is expected during the staging period before the fast-finality upgrade activates — the node is attempting early Cliquenet handshakes with peers, but many haven't opened port
9977yet. It does not affect consensus, which still runs over the legacy LibP2P/UDP layer until the upgrade activates. - Confirm your own node's health is unaffected by checking
consensus_number_of_timeoutsandconsensus_last_voted_viewvsconsensus_current_viewin/v1/status/metrics— these should look normal regardless of Cliquenet warnings. - Confirm your own
9977/TCPport is listening and mapped:ss -tlnp | grep 9977anddocker port espresso.
About the Author
This guide was prepared by HazenNetworkSolutions.
🌐 hazennetworksolutions.com