Set Up a Private RPC Node: A Step Guide

Set Up a Private RPC Node: A Step Guide

Published
AuthorDevansh

A private RPC node is a blockchain node you run for yourself, so your wallets and apps talk to your endpoint instead of a shared public one. That gives you your own rate limits, your own latency, and a fallback you control. During a launch, when public endpoints slow down under shared load, a private RPC is often the difference between an app that works and an app that times out. This guide shows you how to set one up with Docker, how to add a fallback, and how to monitor it, without assuming you already run a validator.

The answer in one paragraph: run a full node (not necessarily a validator) on Ubuntu with Docker, expose its RPC port only to your apps (not to the whole internet, unless you add authentication), add a second synced endpoint as fallback, check sync and latency, set rate limits, and alert on chain-tip lag. If you need history for an indexer or explorer, you need an archival node, not just a full node - decide that before you sync, not after.

What an RPC node is, in plain English

RPC stands for Remote Procedure Call. In blockchain terms, it is how an app asks a node a question: "What is this wallet's balance?", "What is the latest block?", "Send this signed transaction." Your wallet does not hold the whole chain. It asks an RPC endpoint, which asks a node, which answers from its copy of the chain.

Public RPC endpoints are shared by many users. They are convenient, but they have rate limits, and during a spike, everyone shares the same limit. A private RPC endpoint is yours. You set the limits, you see the logs, and you can scale it. You do not need to be a validator to run an RPC node - a full node that serves RPC is enough for most apps.

Full node vs RPC endpoint vs archival node

A full node keeps current state and checks new blocks. An RPC endpoint is a full node with its RPC service turned on, so apps can query it. An archival node keeps full history, so it can answer questions about old blocks. If your app only needs current balances and recent transactions, a full node with RPC is enough and much cheaper in disk. If you run an indexer, explorer, or analytics that needs history, you need archival, and you should plan disk accordingly - archival can be several times larger than a full node, depending on the chain.

Step 1: Server and Docker setup

Use the same Ubuntu + Docker setup as in Post 3 of this series: fresh Ubuntu, non-root user, firewall, Docker and Docker Compose installed. For an RPC node, disk speed matters more than for a casual test node - use SSD, not slow spinning disk, and leave headroom for chain growth.

sudo apt update && sudo apt upgrade -y
docker --version
docker compose version
df -h

Step 2: Start the node with RPC enabled (template)

Again, this is a template. Replace image, ports, and RPC flags with your chain's official docs. Do not expose RPC to the public internet without authentication or an allow-list - an open RPC endpoint can be abused, and it can leak information about your traffic.

# docker-compose.yml - TEMPLATE, replace with your chain's docs
services:
  rpc-node:
    image: <chain-node-image>:<version>
    container_name: rpc-node
    restart: unless-stopped
    ports:
      - "127.0.0.1:8545:8545"
    volumes:
      - ./rpc-data:/data
    command: ["--chain", "mainnet", "--datadir", "/data", "--http", "--http.addr", "0.0.0.0"]

Notes: The example binds RPC to localhost (127.0.0.1) on the host, so only apps on the same server can reach it directly. For remote apps, put a reverse proxy with authentication in front, or use a VPN / private network. Never leave an unauthenticated RPC port open to the world.

docker compose up -d
docker compose logs -f --tail=100

Step 3: Check sync and latency

An RPC node that is not synced gives wrong answers confidently. Check sync before you point any app at it, and keep checking it. Use your chain's sync status command or RPC method, and compare block height to a public explorer.

# Example for an Ethereum-style JSON-RPC endpoint - adapt to your chain
curl -s -X POST -H "Content-Type: application/json"   --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}'   http://127.0.0.1:8545
# If the result is false, the node reports itself as synced. If it returns an object, it is still syncing.
curl -s -X POST -H "Content-Type: application/json"   --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'   http://127.0.0.1:8545

Measure latency from where your app runs, not just from the server itself. A node that answers in 50ms locally but 2 seconds from your app's region is not a good RPC for that app.

Step 4: Fallback endpoint and health checks

One RPC endpoint is a single point of failure. The minimum viable setup is two synced endpoints with a health check that switches traffic when the primary lags. Lag here means: primary block height is behind the chain tip by more than your threshold (for example, more than a few blocks, depending on your chain's block time), or error rate spikes, or latency spikes.

A simple health check script, run every minute, can be enough to start: check block height on both endpoints, compare to an explorer or to each other, and alert if the primary lags. For production, use a load balancer or RPC proxy that does this automatically, and test the failover by actually stopping the primary in a staging environment. An untested fallback is a second outage waiting for its turn.

Step 5: Rate limits, cost, and monitoring

Set rate limits deliberately. Without limits, one buggy app or one abusive client can fill your node's request queue and slow everyone else. With limits that are too low, your own app will fail during a spike. Start with your app's realistic peak, add headroom, and monitor 429 / error rates.

Cost for an RPC node is similar to a full node: server, disk, bandwidth. Archival RPC costs more in disk. Bandwidth can surprise teams during a launch, when many clients poll frequently. If your app polls every second, consider websockets, batching, or caching for read-heavy calls that do not need fresh data every second. Caching a balance for a few seconds is often fine; caching a transaction submission is not.

Monitor, at minimum: block height lag, RPC latency (p50 and p95, not just average), error rate, peer count, disk, and CPU/memory. Alert a human on lag and error spikes; send the rest to chat first. If your first alert about an RPC outage comes from users, your monitoring was decoration.

Troubleshooting

  • RPC returns old data: Node is not synced, or you are querying a fallback that is behind. Check sync on each endpoint separately.
  • Connection refused: Port binding, firewall, or container not running. Check docker compose ps and firewall rules.
  • Slow responses: Disk, CPU, or too many concurrent requests. Check resource use, and check if you are syncing (sync + serving RPC at full load is slow on undersized hardware).
  • CORS or auth errors from a browser app: Your RPC proxy or auth layer is blocking the app's origin. Fix the proxy config, do not just open RPC to everyone.

When to hire help

Private RPC sounds simple until launch week, when traffic spikes, a client upgrades, and a fallback needs testing at the same time. DevOpsBY runs private RPC for Web3 teams, with monitoring, failover, and cost control, so your app team can focus on the product. If your app depends on RPC uptime, get a free infra audit first - we will check sync, latency, fallback, and security before you depend on it in production.

CTA: Hire DevOpsBY for private RPC setup and node operations, or start with a free infra audit at /contact. Tell us your chain, your app's traffic, and whether you need archival history, and we will scope the right setup.

Related Articles

DevOps & Infrastructure Services

Need hands-on help? We build and manage the infrastructure behind the concepts covered in this article.

DevOpsBy Assistant

How can we help?

Select a topic to get started: