Skip to main content

Ports & Endpoints

The canonical answer to "which ports do I open?" — it differs by role, and the difference is not cosmetic.


The matrix

PortDevelopmentPublic RPCIndexer archiveValidator
30333 P2Plocalpublicoutbound onlypublic
9944 RPClocalloopback, Caddy in frontloopback onlyloopback only
9615 metricshost NIC — firewall ithost NIC — firewall itloopback by default
443 / 80public, Cloudflare only

Only two things face the internet on purpose: P2P on 30333, and HTTPS on 443 for the public RPC. Everything else is either loopback or firewalled to a specific source.


Why the roles differ so much

RPC and indexer nodes run with network_mode: host. There is no port mapping at all — the values in .env are the sockets the node listens on, and the firewall is the only thing containing them. Get a ufw rule wrong and the port is genuinely open.

The validator runs on bridge networking with an explicit ports: block, and its defaults fail closed:

RPC_BIND=127.0.0.1        # leave this. NEVER 0.0.0.0 or a public IP
METRICS_BIND=127.0.0.1 # forget to set it and nothing is exposed

Those loopback defaults are why the validator's RPC is safe despite the node serving unsafe methods — see Node Flags.

The indexer archive takes no inbound P2P at all. It deliberately sets no --public-addr, so no peer tries to connect to it; outbound connections still get their replies. Do not open 30333 inbound for it.


Firewall

Every role:

sudo ufw allow 22/tcp        # SSH — restrict to your own IP if you can
sudo ufw allow 30333/tcp # P2P (skip on the indexer archive)
sudo ufw enable

Public RPC adds the Cloudflare-only rules for 80/443 and explicitly denies the node's own ports — Caddy reaches the node over loopback:

sudo ufw deny 9944           # RPC
sudo ufw deny 9615 # Prometheus

node-deploy ships scripts/sync-cloudflare-ufw.sh to load the Cloudflare ranges and keep them current; run it from cron monthly. It fails closed — if the range fetch fails it aborts rather than wiping the allow-list and locking Cloudflare out.

Metrics on a private interface:

sudo ufw allow from <monitoring-ip> to any port 9615 proto tcp
sudo ufw deny 9615
The metrics endpoint has no authentication

Source-address restriction is the only thing protecting 9615. Never replace it with a blanket ufw allow.


Endpoints a public RPC serves

URLUse
https://<your-domain>HTTP JSON-RPC
wss://<your-domain>WebSocket — Polkadot.js, Talisman, SubWallet

Both terminate at Caddy, which proxies to the node on loopback and applies rate limits per client IP.

There is no port 9933

The Docker image still EXPOSEs it, but nothing uses it. Substrate serves HTTP and WebSocket on the same --rpc-port.