Ports & firewall
Krypton's public attack surface is only the two P2P ports. JSON-RPC, the Engine API, the CometBFT RPC, and metrics all stay on loopback or a VPN. This page is the canonical port table plus the baremetal (nftables) and AWS (Security Group) rules.
Port table
| Port | Proto | Service | Exposure |
|---|---|---|---|
| 30303 | tcp + udp | EL devp2p + discovery | PUBLIC (0.0.0.0/0) |
| 26656 | tcp | CL CometBFT p2p | PUBLIC (0.0.0.0/0) |
| 8545 | tcp | EL JSON-RPC | loopback or VPN only — RPC nodes: VPN/WireGuard; validators/seeds: 127.0.0.1 |
| 8551 | tcp | EL engine authrpc | CL-only, NEVER public — exposed to the internal network, not published |
| 26657 | tcp | CL CometBFT RPC | loopback only (bound 127.0.0.1) |
| 9001 | tcp | EL metrics | private (loopback/VPN; not in the firewall allow-list) |
| 26660 | tcp | CL CometBFT metrics | private (on by default; published to loopback, scrape over the internal net) |
The CL reaches the EL engine API at http://el:8551 over the internal network — 8551 is never published to the host. CL metrics (26660) are on by default — beacond's baked config forces instrumentation.prometheus = true at :26660, so no config.toml edit is needed. The compose publishes it to loopback only; scrape it privately (see Monitoring).
Rule of thumb
Only 30303/tcp+udp and 26656/tcp are open to the world. Everything else (8545, 8551, 26657, 9001, 26660) is reached via loopback or a VPN.
Baremetal — nftables
Install from-source/deploy/nftables.conf (edit ADMIN_CIDR to your SSH/bastion CIDR first):
sudo cp nftables.conf /etc/nftables.conf
sudo systemctl enable --now nftablesThe ruleset is default-drop input; it allows loopback, established/related, SSH from ADMIN_CIDR only, the two P2P ports, and rate-limited ICMP:
define ADMIN_CIDR = 203.0.113.0/24 # REPLACE: the CIDR you SSH from / your bastion
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state established,related accept
ct state invalid drop
ip saddr $ADMIN_CIDR tcp dport 22 accept # SSH — admin CIDR only
tcp dport 30303 accept # bera-reth devp2p
udp dport 30303 accept # bera-reth discovery
tcp dport 26656 accept # CometBFT p2p
ip protocol icmp icmp type echo-request limit rate 5/second accept
ip6 nexthdr icmpv6 accept
# NOT opened (intentionally): 8545, 8551, 26657, 9001 — loopback/VPN only.
}
chain forward { type filter hook forward priority 0; policy drop; }
chain output { type filter hook output priority 0; policy accept; }
}It intentionally does NOT open 8545, 8551, 26657, or 9001.
AWS — Security Group (mirror of the above)
| Direction | Port | Proto | Source |
|---|---|---|---|
| Inbound | 30303 | TCP + UDP | 0.0.0.0/0 |
| Inbound | 26656 | TCP | 0.0.0.0/0 |
| Inbound | 22 | TCP | admin CIDR only |
| Inbound | 8545 | TCP | VPN/WireGuard SG or peered subnet only (RPC nodes) — never 0.0.0.0/0 |
| Outbound | all | — | allow (peer dialing, image pulls) |
Never expose 8545 to the world
Do not add an 8545 rule for 0.0.0.0/0. Put RPC nodes' JSON-RPC behind a WireGuard interface (the RPC_HOST bind address) and a private SG. Metrics (9001) and CometBFT RPC (26657) likewise stay private.
Kubernetes
On Kubernetes the same exposure model is enforced by Service type, not a host firewall: the p2p Service (30303 + 26656) is public (LoadBalancer/NodePort) and the rpc Service (8545 + 26657) is ClusterIP-internal. See Kubernetes (Helm).