Run a full / RPC node
A full node stores the entire chain state and validates every block, but does not sign blocks. It can serve eth_* JSON-RPC and Cosmos RPC/REST publicly. Anyone can run one — no permission needed.
This page covers two paths:
- One-click Railway deploy — production-style, public HTTPS in minutes.
- Local devnet on your laptop — for iteration and contract dev.
Prefer your own server? See Run a node on a VPS / dedicated server for a full Ubuntu + Docker guide (firewall, join config, health checks, TLS, updates).
Option 1 — Deploy on Railway
The repo's docker/ contains everything needed.
- Fork or use the repo.
- In Railway → New service → GitHub repo → this repo.
- Railway auto-detects
railway.jsonat the repo root and buildsdocker/Dockerfile. For mainnet add the build variableTARGET_EVM_CHAIN_ID=7628(the image defaults to the testnet ID76287; with the wrong valueeth_chainIdis wrong and wallets reject the node). - Attach a Volume mounted at
/data. Without this, every redeploy wipes the chain (genesis regenerated, height resets to 0). - Settings → Networking → Generate Domain.
That generated domain serves four things behind one HTTPS port (via Caddy):
| Path | Backend | Use |
|---|---|---|
/ | EVM JSON-RPC :8545 | MetaMask / ethers / web3 |
/ws | EVM WebSocket :8546 | subscriptions, hardhat-network |
/rpc/* | CometBFT RPC :26657 | Cosmos clients / explorer |
/rest/* | Cosmos REST :1317 | LCD / explorer |
Joining the existing network
The default entrypoint generates a fresh single-node chain if the volume is empty. To join the existing public sanect network instead, set JOIN_NETWORK=true and the entrypoint handles everything automatically: fetching genesis, configuring peers, and state-syncing to the chain tip.
Join mainnet
SEED_NODE_ID and SEED_PEER_HOST are required — the node refuses to start without them. Read the current values from the public RPC:
curl -s https://rpc.sanect.com/rpc/status | jq -r '.result.node_info.id, .result.node_info.listen_addr'
# 3446053b0b871ce94199a312f87ccdd17db22953 <- SEED_NODE_ID
# p2p.sanect.com:35998 <- SEED_PEER_HOSTJOIN_NETWORK=true
CHAIN_ID=sanect_7628-1
EVM_CHAIN_ID=7628
SEED_NODE_URL=https://rpc.sanect.com
SEED_NODE_ID=3446053b0b871ce94199a312f87ccdd17db22953
SEED_PEER_HOST=p2p.sanect.com:35998
MONIKER=my-sanect-node
HOMEDIR=/data/.sanectdThe id is stable for the life of the primary's key, but the public P2P port belongs to a Railway TCP proxy and can change if that proxy is recreated — always take SEED_PEER_HOST from the listen_addr command above.
Join testnet
JOIN_NETWORK=true
CHAIN_ID=sanect_76287-1
EVM_CHAIN_ID=76287
SEED_NODE_URL=https://rpc.testnet.sanect.com
SEED_NODE_ID=<curl -s https://rpc.testnet.sanect.com/rpc/status | jq -r .result.node_info.id>
SEED_PEER_HOST=<curl -s https://rpc.testnet.sanect.com/rpc/status | jq -r .result.node_info.listen_addr>
MONIKER=my-sanect-testnet-node
HOMEDIR=/data/.sanectdOn first boot with JOIN_NETWORK=true, the entrypoint:
- Generates a fresh validator key (unique per service).
- Fetches genesis from
$SEED_NODE_URL/rpc/genesis. - Wires
persistent_peersto point at the seed. - Configures state sync from the seed (trust height = current - 2000).
- Starts the node and syncs to tip.
Snapshot fast-start
For large chains (>100k blocks), you can speed up the initial sync by downloading a tarball snapshot. Set one of:
SNAPSHOT_MANIFEST_URL=https://snapshots.sanect.com/LATEST.json
# or an explicit URL:
# SNAPSHOT_URL=https://snapshots.sanect.com/sanect-<height>.tar.lz4This is optional. The entrypoint tries the snapshot first; if the manifest is unreachable or the download fails it falls back to state sync, and ultimately to block sync from genesis. Leave it unset to use state sync directly.
Verify it's working
Once Railway shows the service "Active", check the logs for:
>>> Node up at block <N>. Running REST gateway self-test...
>>> REST SELF-TEST: OK (gRPC gateway serving — explorer will work)
>>> sanect | block=<N> | txs_in_block=0 | mempool_pending=0Then from anywhere:
curl https://<your-domain>/rpc/status | jq .result.sync_info.latest_block_heightOption 2 — Local devnet
Single command for laptop development:
# Prerequisites: Go 1.25+, jq, a C toolchain (CGO).
git clone https://github.com/cosmos/evm && cd evm && make install
export PATH=$PATH:$(go env GOPATH)/bin
git clone https://github.com/sanect/sanect-node
cd sanect-node
./scripts/localnet.shThis wipes ~/.sanectd and starts a single-validator chain at:
| Endpoint | URL |
|---|---|
| EVM JSON-RPC | http://localhost:8545 |
| Cosmos RPC | http://localhost:26657 |
| Cosmos REST | http://localhost:1317 |
Env overrides: CHAIN_ID, MONIKER, HOMEDIR, BASEFEE, LOGLEVEL, DENOM, DISPLAY. Set SETUP_ONLY=true to build genesis without starting.
Public RPC node = full node + a public domain
There's no separate "RPC node" mode — a full node already serves the JSON-RPC. Once it's reachable on the internet (Railway domain or your own DNS), it's a public RPC node. You can run many for load: see 1 → 50 validators on Railway §"RPC replicas".
Next step
→ Run a validator to also sign blocks and earn stake rewards.