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
--restartrecycles), but you still need real RAM. Do not size below 8 GiB.
- The seed node's CometBFT id (ask in
#validatorsor runsanectd cometbft show-node-idon 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
apt-get update && apt-get install -y git
git clone https://github.com/sanect/sanect-node /opt/sanect
cd /opt/sanectStep 3: run the one-shot script
sudo bash scripts/spin-up-mainnet-validator.shThe wizard will:
- Pre-flight — OS, RAM, disk, NVMe, public IPv4. Fails loud if any are missing.
- Ask for config — moniker, optional domain, seed node id, seed peer host, optional private key (read silently).
- Install Docker + jq + ufw — idempotent; skips what's already there.
- Open the firewall — 22 (SSH), 80 + 443 (TLS RPC if you attach Caddy later), 46430 (CometBFT P2P). Default-deny on incoming.
- DNS reminder — if you provided a domain, prints the A record to add at your registrar (we don't have your Cloudflare API).
- Pull and run the
sanect-nodecontainer 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. - Wait for sync — polls
localhost:80/healthevery 30s, printing height +catching_upprogress. Typical sync: ~30 min if a snapshot manifest is available, hours otherwise. - 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:
sudo bash scripts/sanect-publish-rpc.shThis 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
# 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-nodeWhen things break
- Container restarts in a loop —
docker logs sanect-node --tail 200almost always shows the cause. Common issue: staledata/from a previous chain id. Wipe/var/lib/sanectdand re-run the script. catching_up = truefor hours — your seed may not be serving snapshots. SetSNAPSHOT_MANIFEST_URLenv on the container and re-create it.- Jailed after a redeploy —
signed_blocks_windowis 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.jsonreuse — 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.