Skip to content

Seed / bootnode

A seed is a CometBFT seed/bootnode for peer discovery — the smallest, cheapest role. It runs the same beacond + bera-reth stack as every node, non-validating (PAYLOAD_BUILDER=false) and with tight memory limits, and helps new validators, RPC, and edge/light nodes find peers. This page covers install → deploy → operate on the public testnet (chain-id 473374).

Why a seed

Seeds are the cheapest box on the network — a Pi 5 or a mini-PC behind a VPN tunnel is enough. They hold no key and tolerate restarts, so a residential line is fine.

Hardware

vCPURAMDiskAWSBaremetal
28 GB100 GB SSDt3.large / m6i.large2-core, 8 GB, 100 GB SSD

Still NVMe/SSD required for the EL — bera-reth's MDBX corrupts/wears slow or SD-card storage even for a small pruned node. A seed runs pruned (--full). Full matrix and cost tiers: Hardware specs.

Install

Every host needs the shared base — see Prerequisites: Docker Engine + Compose v2, an NVMe/SSD volume at DATA_DIR, NTP time-sync, a host firewall, and the non-root UID (10000:10000).

bash
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 .env

Images (pin by @sha256 digest in production — see Building the images):

LayerImage
CLghcr.io/foreseerco/krypton-beacond:v1.3.9-473374
ELghcr.io/foreseerco/krypton-bera-reth:v1.3.3

Deploy

A seed always joins an existing testnet — no genesis ceremony, no validator key. You need the published bundle URL and the EL_BOOTNODES / CL_SEEDS peer strings. See Genesis & the network bundle.

Configure .env (seed preset)

Set the shared core (MONIKER, EXT_IP, EL_BOOTNODES, CL_SEEDS, paths), then uncomment the seed preset:

VarValueWhy
KRYPTON_ROLEseeddocumentation only
PAYLOAD_BUILDERfalsenon-validating
RPC_HOST127.0.0.1RPC stays on loopback
RPC_APIeth,net,web3minimal namespace
EL_SYNC_MODE--fullpruned
EL_MEM_LIMIT6gsmall — per the HW matrix
CL_MEM_LIMIT3gsmall

EXT_IP must be reachable

A seed exists to be dialled by other nodes, so its EXT_IP (advertised via --p2p.external-address on the CL and --nat=extip: on the EL) must be a reachable public, LAN, or Tailscale/WireGuard address. Behind dynamic IP / CGNAT, set EXT_IP to a VPN tunnel address rather than paying for a static IP — fine for this non-validating role.

Bring it up

bash
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 -f

Once it is up, publish its peer addresses so others can use it as a seed: the EL enode (port 30303) and the CometBFT node-id (<nodeid>@<ip>:26656). These feed other operators' EL_BOOTNODES / CL_SEEDS.

Operate

Config recap

A seed is the simplest role: non-validating, pruned, loopback RPC, small memory limits. Co-locating a seed with one or two full nodes on a capable box is fine to amortize cost; do not co-locate multiple validators.

Monitoring signals

See Monitoring. Quick checks:

SignalCommandHealthy
Synccurl -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 and serving — a seed with no peers is doing nothing
EL heightcast block-number --rpc-url http://127.0.0.1:8545climbing
Chain-idcast chain-id --rpc-url http://127.0.0.1:8545473374

For a seed, peer count is the primary signal — a healthy seed maintains and hands out peers. docker compose ps shows the compose healthchecks; logs are JSON-file, rotated 20m × 5.

Upgrade & rollback

Same coordinated, pinned-digest flow: edit the image digests in .env, then sudo systemctl restart krypton-node. Stop order CL first, then EL:

bash
docker compose stop cl      # 5m grace
docker compose stop el      # 2m grace

A seed holds no key — no double-sign hazard, and restarts are low-risk. If its EXT_IP changes (dynamic IP), re-publish its peer strings.

Troubleshooting

SymptomLikely causeFix
Seed has no peers / nobody connectsWrong/unreachable EXT_IP; firewall not opening 30303/26656Confirm EXT_IP is reachable; open 30303 tcp+udp + 26656 tcp from 0.0.0.0/0; re-publish the enode/node-id
Stuck syncFew peers; slow diskCheck peers; confirm NVMe/SSD; check EL logs for MDBX/IO errors
Dynamic IP keeps changingResidential/CGNAT lineUse a WireGuard/Tailscale address for EXT_IP and publish that
Engine auth 401sEL/CL JWT mismatchBoth mount the same JWT_PATH; restart both; 0600/correct owner
EL OOMEL_MEM_LIMIT=6g too low under loadRaise modestly; ensure NVMe/SSD

More in Troubleshooting.

Security

  • Public surface is only the P2P ports (30303, 26656) — which a seed must expose to do its job. JSON-RPC (8545), engine API (8551), CometBFT RPC (26657), and metrics (9001) stay loopback/VPN-only. See Ports & firewall.
  • Containers run as a non-root UID; DATA_DIR is 0700; the JWT is 0600; the bundle is mounted read-only; images pinned by digest; SSH to an admin CIDR.
  • A seed holds no signing key and no state worth attacking beyond availability — the main risk is exposing RPC/engine ports, which the firewall prevents.

Status

These deploy artifacts are config-validated but not yet run end-to-end on real cloud/baremetal hardware. Treat your first seed as a bring-up — verify chain-id, sync, and that peers actually connect. Mainnet (47337) reuses this procedure post-audit. See Networks & chain IDs.

Operator docs. Testnet chain-id 473374; mainnet 47337 (gated on external audit). Not financial advice.