How to Run a Polkadot RPC Node: Step-by-Step
Reliable access to blockchain data is essential for applications, wallets, explorers, exchanges, and other services built on Polkadot. While public RPC endpoints provide a convenient way to connect to the network, they may introduce rate limits, restricted functionality, or dependence on third-party infrastructure.
Running a dedicated Polkadot RPC node gives you greater control over performance, availability, security, and how requests to the network are handled.
This guide explains how to deploy a Polkadot RPC node, configure its RPC interface, secure the endpoint, verify synchronization, and run the node reliably in production.
Set up your Polkadot server in minutes
Run your Polkadot workloads on powerful custom bare metal with 24/7 human support. Pay in crypto.
#What is a Polkadot RPC node?
A Polkadot Remote Procedure Call (RPC) node provides an interface through which applications and services can read blockchain data and submit transactions to the Polkadot network. Wallets, block explorers, exchanges, and decentralized applications can connect to the node instead of relying on a third-party RPC provider.
Unlike a validator, an RPC node does not participate in block production or network consensus. Its primary role is to stay synchronized with the blockchain and respond to requests from connected clients.
RPC nodes can generally be configured as pruned/full nodes or archive nodes. A pruned node retains only the state required for normal operation, while an archive node preserves historical blockchain state, making it more suitable for applications that need extensive historical queries.
Further reading:
- Polkadot Node Cost [With Examples]
- Polkadot Node Requirements
- How to Run a Polkadot Validator Node
- Polkadot Staking Rewards
#Polkadot RPC Requirements
An RPC node must remain synchronized with Polkadot while handling queries from applications and users. The required Polkadot RPC hardware therefore depends on the amount of RPC traffic and whether you run a pruned or archive node.
For a production deployment, use the following Polkadot RPC requirements as a practical starting point:
| Component | Production RPC Node | High-Traffic RPC Node |
|---|---|---|
| CPU | 8+ cores | 16+ cores |
| RAM | 64 GB | 128 GB+ |
| Storage | 2 TB+ NVMe SSD | 2 TB+ NVMe SSD |
| Network | 1 Gbps | 1 Gbps or higher |
| OS | Ubuntu 22.04/24.04 LTS | Ubuntu 22.04/24.04 LTS |
Fast NVMe storage is particularly important because RPC workloads can generate frequent database reads. Polkadot's current RPC infrastructure guidance recommends at least 8 CPU cores and 64 GB of RAM for production workloads, increasing to 16 cores and 128 GB for high-traffic deployments.
Storage requirements also depend heavily on pruning. As of August 25, 2026, the official Polkadot snapshot service lists a pruned RocksDB relay-chain database at about 1.13 TB, while the archive database is already about 4.02 TB. A 2 TB NVMe drive therefore provides reasonable capacity for a pruned RPC node, while an archive RPC node should start with at least 5 TB of fast NVMe storage and additional room for continued growth.
#How to Run a Polkadot RPC: Step-by-Step
The following setup uses Ubuntu 24.04 LTS on a Cherry Servers bare metal server. The same steps should also work on other dedicated or cloud servers that meet the hardware and network requirements discussed earlier.
We will configure a pruned RPC node first, then adjust the pruning settings later if you need an archive node.
#Step 1: Prepare the server
Provision a server that meets the recommended requirements, assign it a public IP address, and connect to it over SSH:
ssh root@YOUR_SERVER_IP
Update the system packages:
sudo apt update && sudo apt upgrade -y
Then install the basic utilities required during setup:
sudo apt install -y curl wget ca-certificates gnupg
At this stage, you only need SSH access to the server. We will configure the Polkadot peer-to-peer and RPC ports when the node is ready.
#Step 2: Download the Polkadot binary
For this guide, we will use the stable2606 Polkadot release. However, Polkadot releases are updated regularly, so you should always check the official Polkadot SDK releases page and use the latest supported stable release before installing your node.
Download the Linux binary for the stable2606 release:
wget https://github.com/paritytech/polkadot-sdk/releases/download/polkadot-stable2606/polkadot
Move the binary to /usr/local/bin and make it executable:
sudo mv polkadot /usr/local/bin/polkadot
sudo chmod +x /usr/local/bin/polkadot
Then verify the installation:
polkadot --version
The command should return the installed Polkadot version. If you are following this guide at a later date, confirm the current stable release on the official Polkadot SDK GitHub repository and replace stable2606 where necessary.
Paying too much for your cloud infrastructure?
Switch to blockchain-optimized dedicated bare metal—save up to 60% on your cloud bill and double the performance compared to hyperscale cloud.
#Step 3: Create a Dedicated Polkadot User and Data Directory
For a production setup, it is better to run the node under a dedicated system user instead of the root account. This limits the permissions available to the Polkadot process.
Create the polkadot user:
sudo useradd -r -s /bin/bash polkadot
Then create a directory for the node database and other persistent data:
sudo mkdir -p /var/lib/polkadot
Give the polkadot user ownership of the directory:
sudo chown -R polkadot:polkadot /var/lib/polkadot
We will later use /var/lib/polkadot as the node's --base-path, which determines where Polkadot stores its blockchain database and other persistent node data. This dedicated-user approach is also used in Polkadot's current systemd deployment guidance.
#Step 4: Configure the Firewall
Before starting the node, configure the firewall to allow SSH access and Polkadot peer-to-peer (P2P) traffic.
If UFW is not already enabled, allow SSH first so you do not lock yourself out of the server:
sudo ufw allow OpenSSH
Then allow Polkadot's default P2P port:
sudo ufw allow 30333/tcp
Enable the firewall and check the active rules:
sudo ufw enable
sudo ufw status
Port 30333 allows the node to communicate with other peers on the Polkadot network. The RPC service typically uses port 9944, but we will not expose it directly to the public internet yet. We will configure and secure RPC access in the next steps.
#Step 5: Start the Polkadot RPC Node
Now start the node using the dedicated polkadot user:
sudo -u polkadot polkadot \
--chain polkadot \
--base-path /var/lib/polkadot \
--name "polkadot-rpc" \
--rpc-port 9944 \
--rpc-methods safe \
--state-pruning 256
Here, --chain polkadot connects the node to the Polkadot relay chain, while --base-path specifies where blockchain data will be stored. --rpc-port 9944 starts the JSON-RPC server, and --rpc-methods safe restricts the endpoint to methods considered safer for external use. The --state-pruning 256 option keeps a limited amount of historical state instead of storing the full state history.
Once the command runs successfully, the node should begin discovering peers and synchronizing with the Polkadot network. You should see logs similar to the following:
2026-08-28 15:17:53 Parity Polkadot
2026-08-28 15:17:53 ✌️ version 1.24.0-660acefe665
2026-08-28 15:17:53 ❤️ by Parity Technologies <admin@parity.io>, 2017-2026
2026-08-28 15:17:53 📋 Chain specification: Polkadot
2026-08-28 15:17:53 🏷 Node name: polkadot-rpc
2026-08-28 15:17:53 👤 Role: FULL
2026-08-28 15:17:53 💾 Database: RocksDb at /var/lib/polkadot/chains/polkadot/db/full
2026-08-28 15:17:55 🔨 Initializing Genesis block/state (state: 0x29d0…4e17, header-hash: 0x91b1…90c3)
2026-08-28 15:17:55 Creating transaction pool txpool_type=ForkAware ready=Limit { count: 8192, total_bytes: 20971520 } future=Limit { count: 819, total_bytes: 2097152 }
2026-08-28 15:17:55 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2026-08-28 15:17:55 👶 Creating empty BABE epoch changes on what appears to be first startup.
2026-08-28 15:17:55 Local node identity is: 12D3KooWCe9tqiQVKXDunLWhZvPcbepscHo2jeStNYvsCPRD6SPh
2026-08-28 15:17:55 Running litep2p network backend
2026-08-28 15:17:55 💻 Operating system: linux
2026-08-28 15:17:55 💻 CPU architecture: x86_64
2026-08-28 15:17:55 💻 Target environment: gnu
2026-08-28 15:17:55 💻 CPU: AMD Ryzen 7 7700X 8-Core Processor
2026-08-28 15:17:55 💻 CPU cores: 8
2026-08-28 15:17:55 💻 Memory: 63388MB
2026-08-28 15:17:55 💻 Kernel: 6.17.0-23-generic
2026-08-28 15:17:55 💻 Linux distribution: Ubuntu 24.04.4 LTS
2026-08-28 15:17:55 💻 Virtual machine: no
2026-08-28 15:17:55 📦 Highest known block at #0
2026-08-28 15:17:55 〽️ Prometheus exporter started at 127.0.0.1:9615
2026-08-28 15:17:55 Running JSON-RPC server: addr=127.0.0.1:9944,[::1]:9944
2026-08-28 15:17:55 🏁 CPU single core score: 1.46 GiBs, parallelism score: 1.47 GiBs with expected cores: 8
2026-08-28 15:17:55 🏁 Memory score: 7.43 GiBs
2026-08-28 15:17:55 🏁 Disk score (seq. writes): 1.02 GiBs
2026-08-28 15:17:55 🏁 Disk score (rand. writes): 298.88 MiBs
2026-08-28 15:17:55 🥩 BEEFY gadget waiting for BEEFY pallet to become available...
2026-08-28 15:18:00 ⚙️ Syncing, target=#32753518 (2 peers), best: #640 (0xf129…7625), finalized #512 (0xc8e7…f16a), ⬇ 105.5kiB/s ⬆ 3.3kiB/s
2026-08-28 15:18:01 🔍 Discovered new external address for our node: /ip4/84.32.220.85/tcp/30333/ws/p2p/12D3KooWCe9tqiQVKXDunLWhZvPcbepscHo2jeStNYvsCPRD6SPh
2026-08-28 15:18:05 ⚙️ Syncing 512.0 bps, target=#32753518 (2 peers), best: #3200 (0xd72c…5871), finalized #3072 (0xa4d5…5251), ⬇ 234.1kiB/s ⬆ 3.0kiB/s
2026-08-28 15:18:10 ⚙️ Syncing 588.8 bps, target=#32753519 (3 peers), best: #6144 (0xeced…4008), finalized #5632 (0x9ed9…5a2a),
Look for messages showing that the node has connected to peers and started importing or synchronizing blocks. This confirms that the Polkadot process is running correctly.
By default, the RPC interface is not exposed publicly. We will configure external RPC access securely in a later step rather than opening port 9944 directly to the internet.
#Step 6: Verify the RPC Node and Synchronization
While the node is running, open another SSH session to the server and query the local RPC endpoint.
First, check the node's health:
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"system_health","params":[]}' \
http://127.0.0.1:9944
You should get a response similar to:
{
"jsonrpc": "2.0",
"result": {
"peers": 9,
"isSyncing": true,
"shouldHavePeers": true
},
"id": 1
}
The peers value shows how many peers the node is connected to, while isSyncing indicates whether it is still catching up with the network.
You can also check the synchronization progress:
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"system_syncState","params":[]}' \
http://127.0.0.1:9944
This returns the node's current and highest known block numbers. Once the node is fully synchronized, isSyncing should return false, and the current block should be close to the highest known block.
{
"jsonrpc": "2.0",
"result": {
"startingBlock":0,
"currentBlock":452608,
"highestBlock":32753593
},
"id": 1
}
For a fresh node, synchronization can take some time depending on the server hardware, storage performance, and network connectivity.
#Step 7: Expose the RPC Endpoint Through Nginx
To access the RPC node from another machine, we will place Nginx in front of the local Polkadot RPC service. Polkadot will continue listening on 127.0.0.1:9944, while Nginx accepts external requests through the server's public IP address.
This avoids exposing the Polkadot RPC port directly to the internet.
Install Nginx:
sudo apt install -y nginx
Create a new Nginx configuration:
sudo nano /etc/nginx/sites-available/polkadot-rpc
Add the following:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:9944;
proxy_http_version 1.1;
proxy_set_header Host 127.0.0.1:9944;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The Host header is set to 127.0.0.1:9944 because Polkadot applies host validation to RPC requests. Forwarding the server's public IP as the host can result in a Provided Host header is not whitelisted error.
Enable the configuration:
sudo ln -s /etc/nginx/sites-available/polkadot-rpc /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
Check the Nginx configuration:
sudo nginx -t
If there are no errors, reload Nginx:
sudo systemctl reload nginx
Then allow HTTP traffic through the firewall:
sudo ufw allow 80/tcp
Your RPC endpoint should now be accessible externally through:
http://YOUR_SERVER_IP
WebSocket clients can use:
ws://YOUR_SERVER_IP
Test the endpoint from your local machine:
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"system_health","params":[]}' \
http://YOUR_SERVER_IP
A successful response confirms that Nginx is forwarding external requests to the Polkadot RPC service correctly.
{"jsonrpc":"2.0","id":1,"result":{"peers":11,"isSyncing":true,"shouldHavePeers":true}}
At this point, the node can be queried from outside the server without exposing port 9944 directly. In the next step, we can use this endpoint from a simple application to retrieve actual Polkadot account data.
#Step 7: Expose the RPC Endpoint Through Nginx
To access the RPC node from another machine, we will place Nginx in front of the local Polkadot RPC service. Polkadot will continue listening on 127.0.0.1:9944, while Nginx accepts external requests through the server's public IP address.
Note:
YOUR_SERVER_IPrefers to the public IP address assigned to the server you provisioned earlier. You can find it in your server provider's dashboard or provisioning details.
Install Nginx:
sudo apt install -y nginx
Create a new Nginx configuration:
sudo nano /etc/nginx/sites-available/polkadot-rpc
Add the following:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:9944;
proxy_http_version 1.1;
proxy_set_header Host 127.0.0.1:9944;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The Host header is set to 127.0.0.1:9944 because Polkadot applies host validation to RPC requests. Forwarding the server's public IP as the host can result in a Provided Host header is not whitelisted error.
Enable the configuration:
sudo ln -s /etc/nginx/sites-available/polkadot-rpc /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
Check the Nginx configuration:
sudo nginx -t
If there are no errors, reload Nginx:
sudo systemctl reload nginx
Then allow HTTP traffic through the firewall:
sudo ufw allow 80/tcp
Your RPC endpoint should now be accessible externally through:
http://YOUR_SERVER_IP
WebSocket clients can use:
ws://YOUR_SERVER_IP
Test the endpoint from your local machine:
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"system_health","params":[]}' \
http://YOUR_SERVER_IP
A successful response confirms that Nginx is forwarding external requests to the Polkadot RPC service correctly.
{"jsonrpc":"2.0","id":1,"result":{"peers":11,"isSyncing":true,"shouldHavePeers":true}}
At this point, the node can be queried from outside the server without exposing port 9944 directly.
#Step 8: Query the RPC Node from an External Application
Once the node has finished synchronizing, you can test it from an application running outside the RPC server.
In this example, we will use Node.js and Dedot to connect to the RPC endpoint and query account information from Polkadot.
Note: Make sure the RPC node has finished syncing before running this example. Some client libraries depend on the current runtime metadata and may fail while the node is still processing older blocks.
You can confirm the sync status with:
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"system_health","params":[]}' \
http://YOUR_SERVER_IP
Wait until the response shows:
"isSyncing": false
On your local computer, make sure Node.js and npm are installed. Then create a small test project:
mkdir polkadot-rpc-test
cd polkadot-rpc-test
npm init -y
npm pkg set type=module
npm install dedot
Create the script file:
touch query-account.js
Open query-account.js in your preferred text editor and add:
import { DedotClient, WsProvider } from 'dedot';
const RPC_URL = 'ws://YOUR_SERVER_IP';
const ADDRESS = 'YOUR_POLKADOT_ADDRESS';
const provider = new WsProvider(RPC_URL);
const client = await DedotClient.new(provider);
const account = await client.query.system.account(ADDRESS);
const blockNumber = await client.query.system.number();
console.log(`Connected to: ${RPC_URL}`);
console.log(`Current block: ${blockNumber}`);
console.log(`Address: ${ADDRESS}`);
console.log(`Nonce: ${account.nonce}`);
console.log(`Free balance: ${account.data.free}`);
await client.disconnect();
Replace YOUR_SERVER_IP with the public IP address of your RPC server and YOUR_POLKADOT_ADDRESS with any valid Polkadot account address. Since this is a read-only query, no private key or seed phrase is required.
Run the script:
node query-account.js
A successful request should return output similar to:
Connected to: wss://84.32.220.85
Current block: 32754395
Address: 1344zprT7A4VFrQ46GJycLrjhBoYjf1RcsjbRLmk5DtsYshV
Nonce: 0
Free balance: 0
At this point, the application is running on your local machine while retrieving blockchain data through your own Polkadot RPC node. The same RPC endpoint can be used by wallets, backend services, explorers, and decentralized applications.
#Step 9: Run the Polkadot RPC Node with systemd
So far, the Polkadot node has been running directly from the terminal. For a persistent setup, configure it as a systemd service so it can run in the background, restart automatically if it fails, and start again after a server reboot.
If the node is still running in your terminal, stop it first with:
Ctrl+C
The synchronized blockchain data already stored in /var/lib/polkadot will remain intact, so the node will continue from where it stopped when restarted.
Create a systemd service file:
sudo nano /etc/systemd/system/polkadot-rpc.service
Add the following configuration:
[Unit]
Description=Polkadot RPC Node
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=polkadot
Group=polkadot
ExecStart=/usr/local/bin/polkadot \
--chain polkadot \
--base-path /var/lib/polkadot \
--name polkadot-rpc \
--rpc-port 9944 \
--rpc-methods safe \
--state-pruning 256
Restart=always
RestartSec=10
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
This uses the same configuration we used earlier, but systemd now manages the process. Restart=always restarts the node if it exits unexpectedly, while LimitNOFILE raises the number of file descriptors available to the process.
Reload systemd so it recognizes the new service:
sudo systemctl daemon-reload
Enable the service and start it:
sudo systemctl enable --now polkadot-rpc.service
Check its status:
sudo systemctl status polkadot-rpc.service
You should see the service reported as:
● polkadot-rpc.service - Polkadot RPC Node
Loaded: loaded (/etc/systemd/system/polkadot-rpc.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-08-28 16:47:43 UTC; 7s ago
Main PID: 45872 (polkadot)
Tasks: 73 (limit: 75735)
Memory: 506.9M (peak: 525.5M)
CPU: 9.471s
CGroup: /system.slice/polkadot-rpc.service
└─45872 /usr/local/bin/polkadot --chain polkadot --base-path /var/lib/polkadot --name polkadot-rpc --rpc-port 9944 --rpc-methods safe --state-pruning 256
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 💻 Virtual machine: no
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 📦 Highest known block at #4836612
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 〽️ Prometheus exporter started at 127.0.0.1:9615
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 Running JSON-RPC server: addr=127.0.0.1:9944,[::1]:9944
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 🏁 CPU single core score: 1.46 GiBs, parallelism score: 1.46 GiBs with expected cores: 8
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 🏁 Memory score: 18.96 GiBs
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 🏁 Disk score (seq. writes): 1.01 GiBs
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 🏁 Disk score (rand. writes): 235.91 MiBs
Aug 28 16:47:50 noted-guppy polkadot[45872]: 2026-08-28 16:47:50 🥩 BEEFY gadget waiting for BEEFY pallet to become available...
Aug 28 16:47:51 noted-guppy polkadot[45872]: 2026-08-28 16:47:51 🔍 Discovered new external address for our node: /ip4/84.32.220.85/tcp/30333/ws/p2p/12D3KooWCe9tqiQVKXDunLWhZvPcbepscHo2jeStNYvsCPRD6SPh
You can also follow the node logs in real time with:
sudo journalctl -u polkadot-rpc.service -f
Since Nginx continues forwarding requests to 127.0.0.1:9944, your external RPC endpoint will continue working after moving the node to systemd.
#Step 10: Harden the Public RPC Endpoint
Your RPC endpoint is now publicly reachable, so it is important to limit how it can be used. We already configured Polkadot with:
--rpc-methods safe
This restricts the node to the safer subset of RPC methods rather than exposing every available method. Polkadot also provides controls for connection limits, request sizes, subscriptions, and RPC rate limiting.
One useful additional protection is rate limiting. Edit the systemd service:
sudo nano /etc/systemd/system/polkadot-rpc.service
Add a rate limit to the existing ExecStart command:
ExecStart=/usr/local/bin/polkadot \
--chain polkadot \
--base-path /var/lib/polkadot \
--name polkadot-rpc \
--rpc-port 9944 \
--rpc-methods safe \
--rpc-rate-limit 100 \
--rpc-rate-limit-trust-proxy-headers \
--state-pruning 256
--rpc-rate-limit 100 allows up to 100 RPC calls per minute per client connection. Because the node sits behind Nginx, --rpc-rate-limit-trust-proxy-headers allows Polkadot to use headers such as X-Real-IP and X-Forwarded-For, which our Nginx configuration already sets.
Reload systemd and restart the node:
sudo systemctl daemon-reload
sudo systemctl restart polkadot-rpc.service
Then confirm that it is running:
sudo systemctl status polkadot-rpc.service
The value 100 is only a starting point. For a production RPC service, adjust the limit according to the expected application traffic and server capacity.
Also keep port 9944 closed to external traffic. Only Nginx should be publicly accessible, while Polkadot continues listening on localhost.
Security note: Our current endpoint uses
http://andws://, so traffic is not encrypted. This is suitable for demonstrating the setup, but an internet-facing production RPC endpoint should use HTTPS/WSS. If you do not have a domain, TLS can also be configured for a public IP address using a certificate authority that supports IP certificates.
#Conclusion
Running your own Polkadot RPC node gives you direct control over how your applications access the network, without depending entirely on public RPC providers.
In this guide, we configured a Polkadot RPC node on a bare metal server, exposed it safely through Nginx, tested it from an external application, and set it up as a persistent systemd service.
From here, you can build on the setup by adding HTTPS/WSS, stricter rate limits, monitoring, or additional RPC nodes for redundancy and higher availability.
Set up your Web3 server in minutes
Optimize cost and performance with custom or pre-built dedicated bare metal servers for blockchain workloads. High uptime, instant 24/7 support, pay in crypto.
Deploy secure and high-performance nodes on dedicated infrastructure.