RPC / full node (L5)
An RPC node is a non-validating full node — the L5 fleet that serves eth_getProof (EIP-1186) and JSON-RPC to wallets, dApps, the block explorer, and the edge / light clients that verify their reads against it. It runs the same beacond + bera-reth stack as a validator but with PAYLOAD_BUILDER=false and no signing key. This page covers install → deploy → operate on the public testnet (chain-id 473374).
It serves edge/light clients
Edge nodes are verifying light clients — they hold no state and fetch proofs from this fleet. Your node must serve CometBFT RPC (/status, /commit, /block) and EL eth_getProof at the needed depth on a fixed, reachable address. See Edge node.
Hardware
| vCPU | RAM | Disk | AWS | Baremetal |
|---|---|---|---|---|
| 8 | 32 GB | 1–2 TB NVMe (pruned; archive = larger) | m6i.2xlarge + gp3/io2 1–2 TB | 8-core, 32–64 GB, 2 TB NVMe |
A non-validating node tolerates restarts and a residential line — you can run one cheaply at home behind a VPN tunnel. The EL state under DATA_DIR/el grows continuously; archive RPC nodes (EL_SYNC_MODE= empty) grow much larger — provision 1–2 TB and expect to expand. Full matrix and cost tiers: Hardware specs.
Install
Every host needs the shared base — see Prerequisites: Docker Engine + Compose v2, an NVMe volume at DATA_DIR, NTP time-sync, a host firewall, and the non-root UID (10000:10000).
git clone https://github.com/foreseerco/block-l1-evm-mainnet krypton
sudo mkdir -p /opt/krypton/deploy
sudo cp krypton/l1/from-source/deploy/{docker-compose.yml,.env.example,bootstrap.sh,nftables.conf,krypton-node.service} /opt/krypton/deploy/
cd /opt/krypton/deploy
sudo cp .env.example .envImages (pin by @sha256 digest in production — see Building the images):
| Layer | Image |
|---|---|
| CL | ghcr.io/foreseerco/krypton-beacond:v1.3.9-473374 |
| EL | ghcr.io/foreseerco/krypton-bera-reth:v1.3.3 |
Deploy
An RPC node always joins an existing testnet — it never runs the genesis ceremony and holds no validator key. You need the published bundle URL and the EL_BOOTNODES / CL_SEEDS peer strings. See Genesis & the network bundle.
Configure .env (rpc preset)
Set the shared core (MONIKER, EXT_IP, EL_BOOTNODES, CL_SEEDS, paths), then uncomment the rpc preset:
| Var | Value | Why |
|---|---|---|
KRYPTON_ROLE | rpc | documentation only |
PAYLOAD_BUILDER | false | non-validating |
RPC_HOST | a VPN/WireGuard addr (e.g. 10.8.0.5) | never a public IP |
RPC_API | eth,net,web3,debug | the public wallet/dApp namespace |
EL_SYNC_MODE | --full, or empty for archive | archive serves deep historical proofs |
EL_MEM_LIMIT | 24g | per the HW matrix |
CL_MEM_LIMIT | 6g |
Never expose JSON-RPC publicly
The RPC node's 8545 is bound to RPC_HOST — a VPN/WireGuard or peered-subnet address only, never 0.0.0.0 on a public host without auth. The firewall intentionally does not open 8545. Front public access with a reverse proxy / auth gateway, not a raw public bind. See TLS / reverse proxy (Caddy) and Ports & firewall.
Bring it up
BUNDLE_URL=https://…/krypton-testnet-bundle.tar.gz sudo -E ./bootstrap.sh
# then run under systemd:
sudo cp krypton-node.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now krypton-node
journalctl -u krypton-node -fThe explorer's indexer node is separate
The public wallet/dApp RPC above and the RPC node that backs the block explorer (Blockscout @ kryscan.com) are not the same node.
Indexer node: private, archive, trace-enabled
Blockscout deploys against a separate RPC node that is:
- Archive (
EL_SYNC_MODE=empty) — full historical state, much larger disk. - Trace-enabled —
RPC_API=eth,net,web3,debug,trace(thetrace/debugnamespaces, which the public wallet RPC does not expose). - Private — reachable only by the explorer stack, not the public, and provisioned with extra headroom because Blockscout is RPC-heavy.
Do not point public wallet traffic at the indexer node, and do not expose trace on the public RPC. See Block explorer.
Operate
Config recap
- Public RPC: pruned or archive as needed,
RPC_API=eth,net,web3,debug, bound to a VPN address. - Indexer RPC (explorer only): archive +
trace, private. - Both keep CometBFT RPC (
26657) on loopback and metrics (9001) private.
Monitoring signals
See Monitoring for the Prometheus + Grafana stack. Quick checks (run from the VPN side for the RPC bind):
| Signal | Command | Healthy |
|---|---|---|
| Sync | curl -s http://127.0.0.1:26657/status | jq '.result.sync_info' | catching_up: false, height climbing |
| Peers (CL) | curl -s http://127.0.0.1:26657/net_info | jq '.result.n_peers' | > 0, stable |
| EL height | cast block-number --rpc-url http://<rpc-bind>:8545 | climbing |
| Chain-id | cast chain-id --rpc-url http://<rpc-bind>:8545 | 473374 |
eth_getProof | a proof request at your serving depth | returns a proof, not an error |
The compose healthchecks (EL: tool-free TCP connect to 8551; CL: curl /health) are visible via docker compose ps. Logs are JSON-file, rotated 20m × 5.
Upgrade & rollback
Same coordinated, pinned-digest flow as any node: edit KRYPTON_CL_IMAGE / KRYPTON_EL_IMAGE in .env to the agreed digests, then sudo systemctl restart krypton-node. Stop order is CL first, then EL:
docker compose stop cl # 5m grace
docker compose stop el # 2m graceRollback: revert the digests and restart. An RPC node holds no key, so there is no double-sign hazard — but archive nodes re-sync slowly, so avoid unnecessary head rollbacks.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| No peers | Wrong EXT_IP; firewall; bad bootnodes/seeds | Confirm EXT_IP; open 30303 tcp+udp + 26656 tcp; recheck peer strings |
| Stuck sync | Few peers; slow disk; EL behind | Check peers; confirm NVMe; check EL logs for MDBX/IO errors |
eth_getProof errors on old blocks | Node is pruned, not archive | Run archive (EL_SYNC_MODE= empty) if serving deep historical proofs |
| Engine auth 401s | EL/CL JWT mismatch | Both mount the same JWT_PATH; restart both; 0600/correct owner |
| EL OOM / restarts | EL_MEM_LIMIT too low; archive disk full | Raise mem per matrix; expand the NVMe; on AWS use gp3/io2 |
| RPC unreachable from a client | 8545 bound to loopback, or VPN down | Set RPC_HOST to the VPN addr; confirm the WireGuard interface is up |
More in Troubleshooting.
Security
- Public surface is only the P2P ports (
30303,26656). JSON-RPC (8545) goes behind a VPN/WireGuard bind — never a public0.0.0.0/0rule. Engine API (8551), CometBFT RPC (26657), and metrics (9001) stay loopback/VPN-only. See Ports & firewall. - Containers run as a non-root UID;
DATA_DIRis0700; the JWT is0600; the bundle is mounted read-only; images pinned by digest; SSH to an admin CIDR. - The
trace/debugnamespaces are powerful — keeptraceto the private indexer node and gate evendebugbehind the VPN.
Status
These deploy artifacts are config-validated but not yet run end-to-end on real cloud/baremetal hardware. Treat your first RPC node as a bring-up — verify chain-id, peers, sync, and a sample eth_getProof before edge/light clients rely on it. Mainnet (47337) reuses this procedure post-audit. See Networks & chain IDs.