Skip to content

Mainnet validator runbook

One-shot setup for a sanect mainnet validator on a fresh NVMe box.

What you'll need

  • A VPS or bare-metal host with:
    • Ubuntu 22.04 or 24.04
    • ≥ 4 vCPU, ≥ 8 GB RAM minimum (16 GB recommended for archive nodes)
    • ≥ 200 GB local NVMe (not networked storage; not spinning rust)
    • Public IPv4
  • Hosts that work well:
    • Vultr High Frequency — 3 vCPU / 8 GB / 128 GB NVMe (~$24/mo) minimum, or 4 vCPU / 16 GB / 256 GB NVMe (~$48/mo) recommended
    • Hetzner CCX22 — 4 vCPU / 16 GB / 160 GB NVMe (~$32/mo)
    • Latitude.sh c2.small.x86 — bare metal, NVMe (~$130/mo)

⚠️ Hardware floor is real. A 2 GB instance was tested on testnet 2026-06-16 and sanectd was OOM-killed by the kernel within ~12 hours of running (the chain state + IAVL cache + EVM rebuild grows past 1.7 GB). Caddy survives the OOM and the container reports "Up" but all RPC requests 502. The entrypoint now exits the container when either process dies (so Docker --restart recycles), but you still need real RAM. Do not size below 8 GiB.

  • The seed node's CometBFT id (ask in #validators or run sanectd cometbft show-node-id on any existing mainnet node)
  • (Optional) A subdomain you control, e.g. val1.example.com
  • (Optional) The EOA private key that will self-stake — only if you want to auto-register on-chain from this box. Recommended: leave it off the validator and register from the dApp in your browser.

Step 1: provision the box

Pick a region close to the rest of the validator set's center of mass (Variant A targets Singapore as the hub — see CLAUDE.md). Spin up the VPS, take note of the public IPv4, and ssh root@<ip>.

Step 2: pull the repo

bash
apt-get update && apt-get install -y git
git clone https://github.com/sanect/sanect-node /opt/sanect
cd /opt/sanect

Step 3: run the one-shot script

bash
sudo bash scripts/spin-up-mainnet-validator.sh

The wizard will:

  1. Pre-flight — OS, RAM, disk, NVMe, public IPv4. Fails loud if any are missing.
  2. Ask for config — moniker, optional domain, seed node id, seed peer host, optional private key (read silently).
  3. Install Docker + jq + ufw — idempotent; skips what's already there.
  4. Open the firewall — 22 (SSH), 80 + 443 (TLS RPC if you attach Caddy later), 46430 (CometBFT P2P). Default-deny on incoming.
  5. DNS reminder — if you provided a domain, prints the A record to add at your registrar (we don't have your Cloudflare API).
  6. Pull and run the sanect-node container with mainnet env: CHAIN_ID=sanect_7628-1, EVM_CHAIN_ID=7628, EXTERNAL_P2P_ADDRESS=<your-ip>:46430, PRUNING=custom (validator, not archive), MIN_GAS_PRICE=1000000000.
  7. Wait for sync — polls localhost:80/health every 30s, printing height + catching_up progress. Typical sync: ~30 min if a snapshot manifest is available, hours otherwise.
  8. Print the consensus pubkey — copy this into the staking dApp's Register as Validator form. Don't lose it; the script also tells you how to retrieve it later.

Step 4: register on-chain

Open the mainnet staking dApp in your browser, connect MetaMask with the EOA you want to self-stake from, click Register as Validator, paste the consensus pubkey from Step 3, and submit. The minimum self-stake at genesis is 1000 SNCT (mainnet param).

Step 5 (optional): attach a public RPC

If you want this node to serve a public RPC endpoint at your domain:

bash
sudo bash scripts/sanect-publish-rpc.sh

This handles Caddy + Let's Encrypt automatically. If you skip this, the node still participates in consensus — it just won't be reachable from the explorer or wallets.

Operations cheat sheet

bash
# Tail logs
docker logs -f sanect-node

# Check sync state
curl -s localhost:80/rpc/status | jq .result.sync_info

# Retrieve consensus pubkey / node id
docker exec sanect-node sanectd cometbft show-validator --home /data/.sanectd
docker exec sanect-node sanectd cometbft show-node-id   --home /data/.sanectd

# Restart
docker restart sanect-node

When things break

  • Container restarts in a loopdocker logs sanect-node --tail 200 almost always shows the cause. Common issue: stale data/ from a previous chain id. Wipe /var/lib/sanectd and re-run the script.
  • catching_up = true for hours — your seed may not be serving snapshots. Set SNAPSHOT_MANIFEST_URL env on the container and re-create it.
  • Jailed after a redeploysigned_blocks_window is 10,000 blocks (~1h on mainnet). Use the staking dApp's Unjail button to bring the validator back into the active set.
  • priv_validator_key.json reuse — NEVER copy this file between boxes. CometBFT will see the duplicate signing and slash you 5% for double-sign. Each new validator gets a fresh /var/lib/sanectd.

Backups

The only file that matters cryptographically is /var/lib/sanectd/.sanectd/config/priv_validator_key.json. Back it up to encrypted offline storage (e.g., a hardware wallet seed-backup card) the first time the node boots. State is replayable from any seed node; the consensus key is not.