Mainnet Node Guide
How to run your own rippled node connected to the XRP Ledger mainnet: installation, configuration, systemd operation, monitoring, and — critically — keeping it updated so it never becomes amendment-blocked.
For a local development node see the Standalone Node Guide.
Why run your own node
- Your applications talk to
ws://localhost— no rate limits, no third-party trust, lowest latency forsubmitand subscriptions - Full control over history retention and API load
- Public clusters (
wss://xrplcluster.com,wss://s1.ripple.com) throttle heavy users and may lag behind on busy days
Node roles (this guide covers the first one):
| Role | Purpose |
|---|---|
| Stock node | Tracks the network, serves API, submits transactions — what an application needs |
| Full-history node | Same + complete ledger history from ledger 32570; tens of TB of NVMe |
| Validator | Participates in consensus; separate hardening/key ceremony — see xrpl.org validator docs |
Hardware (stock node, 2026)
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 4 cores / 8 threads, high clock | 8+ physical cores |
| RAM | 32 GB | 64 GB |
| Disk | NVMe SSD, 10k+ sustained IOPS. No HDD, no network storage | NVMe RAID |
| Disk size | ~50 GB for a few days of history | 300+ GB for ~1 month (see online_delete) |
| Network | 100 Mbit, stable | 1 Gbit |
Disk usage is driven entirely by history retention: mainnet produces a ledger every 3–5 seconds around the clock.
Installation (Ubuntu / Debian)
Packages are published to the XRP Ledger Foundation apt repository (channel stable).
The server binary was renamed from
rippledtoxrpld, and packaging moved fromrepos.ripple.comtopackages.xrplf.orgin August 2026. The old repository still answers but stopped at 3.3.0, so a node installed from it silently stays a release behind. A host set up the old way needs the source list replaced, not just anapt upgrade./usr/local/bin/rippledremains as a symlink to the new binary.
# prerequisites: curl fetches the key, gnupg shows it, ca-certificates makes the TLS work
sudo apt update && sudo apt install -y ca-certificates curl gnupg
# repository key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsS https://packages.xrplf.org/xrplf.asc -o /etc/apt/keyrings/xrplf.asc
# check it before trusting it: a key added unverified defeats the point of signing
gpg --show-keys /etc/apt/keyrings/xrplf.asc
The fingerprint must read:
pub rsa4096 2026-08-18 [SC]
B655 4167 4122 1F78 0FBC FBC9 AA84 D41A 11D2 9FA9
Do not continue if it differs.
# repository — one suite, "any main", for every distribution
echo "deb [signed-by=/etc/apt/keyrings/xrplf.asc] https://packages.xrplf.org/repository/deb-stable any main" | \
sudo tee /etc/apt/sources.list.d/xrplf.list
sudo apt update && sudo apt -y install xrpld
The package installs:
| Path | Purpose |
|---|---|
/usr/bin/xrpld |
binary |
/etc/xrpld/xrpld.cfg |
main config |
/etc/xrpld/validators.txt |
UNL (trusted validator list) source |
/usr/lib/systemd/system/xrpld.service |
systemd unit |
/var/lib/xrpld/ |
databases (point this at the NVMe volume) |
Configuration
Edit /etc/xrpld/xrpld.cfg. A production-sane skeleton for an application node:
[server]
port_rpc_admin_local
port_ws_admin_local
port_ws_public
port_peer
# admin — localhost ONLY, never expose
[port_rpc_admin_local]
port = 5005
ip = 127.0.0.1
admin = 127.0.0.1
protocol = http
[port_ws_admin_local]
port = 6006
ip = 127.0.0.1
admin = 127.0.0.1
protocol = ws
# public WebSocket for your applications (bind to a private interface,
# or keep 127.0.0.1 and put nginx/TLS in front)
[port_ws_public]
port = 6005
ip = 0.0.0.0
protocol = ws
# limit resource use by public clients:
# send_queue_limit = 500
# peer protocol — open this one to the internet
[port_peer]
port = 51235
ip = 0.0.0.0
protocol = peer
[node_size]
huge # medium for 32 GB RAM, huge for 64 GB+
[node_db]
type = NuDB # NuDB for production nodes (append-only, SSD-friendly)
path = /var/lib/xrpld/db/nudb
online_delete = 512000 # keep ~512k ledgers (~3-4 weeks); minimum 256
advisory_delete = 0
[database_path]
/var/lib/xrpld/db
[ledger_history]
256 # how many ledgers to backfill on start; <= online_delete
[debug_logfile]
/var/log/xrpld/debug.log
[sntp_servers]
time.windows.com
time.apple.com
time.nist.gov
pool.ntp.org
[validators_file]
validators.txt
[ssl_verify]
1
Key points:
network_idis not set for mainnet (it defaults to mainnet). Setting it wrongly is a classic way to end up on the wrong network.- UNL: the stock
validators.txtpoints at the dUNL publishers (vl.ripple.com,unl.xrplf.org). Do not edit it unless you know exactly why. online_deleteis what keeps your disk finite: the node keeps a rotating window of ledgers and deletes older shards. Size the disk for the window, not the other way around.- Never expose admin ports.
admin = 127.0.0.1, and if you need remote API — publish onlyport_ws_publicbehind nginx with TLS (the reverse-proxy pattern with WebSocket upgrade headers). - Firewall: inbound
51235/tcpopen to the world (peer protocol benefits from inbound connectivity), everything else closed or internal.
Running under systemd
sudo systemctl enable --now xrpld
sudo systemctl status xrpld
# logs
journalctl -u xrpld -f
First start on mainnet: the node fetches the latest validated ledger and backfills ledger_history. Expect 10–30 minutes to reach "server_state": "full" (longer on modest hardware).
Health check
/usr/bin/xrpld server_info | jq '.result.info | {build_version, server_state, complete_ledgers, peers, load_factor, amendment_blocked}'
| Field | Healthy value |
|---|---|
server_state |
full (a validator shows proposing) |
complete_ledgers |
a contiguous range, e.g. 95000000-95120000 — not empty |
peers |
10+ |
load_factor |
1 (spikes under fee escalation are normal) |
amendment_blocked |
must be absent — see below |
Updating — and why it is not optional
XRPL evolves through amendments. Two weeks after an amendment gains >80% validator support it activates network-wide. A node whose binary does not implement an active amendment becomes amendment-blocked: it stops tracking the network, refuses to submit transactions, and server_info shows "amendment_blocked": true. The only fix is upgrading.
Practical policy:
- Subscribe to rippled releases and the XRPL blog; upgrade within days of a release, not months
- The amendment voting dashboard (
featurecommand, or xrpscan.com/amendments) shows what is queued — anything at >80% is your deadline timer
Upgrade procedure (apt):
sudo apt update
sudo apt install --only-upgrade xrpld
sudo systemctl restart xrpld
watch -n 5 "/usr/bin/xrpld server_info | jq -r '.result.info.server_state'"
Downtime is minutes: after a restart the node re-syncs to the current ledger quickly (it does not replay history). Config files are not overwritten by upgrades; compare with the shipped example after major versions (/etc/xrpld/xrpld.cfg.dpkg-dist if present).
To pin against surprise major upgrades, use apt-mark hold xrpld and upgrade deliberately.
Connecting XrplCSharp
using Xrpl.Client;
// plain ws:// is acceptable ONLY inside a trusted private network / localhost
IXrplClient client = new XrplClient("ws://10.0.0.5:6005");
// anything reachable from outside must go through TLS (nginx in front of port_ws_public):
// IXrplClient client = new XrplClient("wss://xrpl-node.example.com");
await client.Connect();
ServerInfo info = await client.ServerInfo();
Console.WriteLine(info.Info.CompleteLedgers);
Recommendations for production use with this SDK:
- Point the client at your node's public WS port; keep admin ports for operations only
- Check
complete_ledgerscovers the range you query —account_txbeyond the retention window returns partial data; for deep history use a full-history provider or Clio SubmitAndWaitrelies onLastLedgerSequence— a healthy, synced node is what makes those guarantees real
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
"amendment_blocked": true |
Binary too old for an activated amendment | Upgrade rippled immediately |
server_state stuck in connected/syncing |
Underpowered disk (IOPS), bad clock, too few peers | NVMe only; verify NTP ([sntp_servers], timedatectl); open inbound 51235 |
complete_ledgers: empty after long uptime |
Node keeps losing sync, history resets | Same as above — almost always disk IOPS or RAM pressure |
| Disk keeps growing | online_delete not set |
Set online_delete in [node_db] and restart |
noCurrent / noNetwork errors via API |
Node not synced yet or lost quorum view | Wait for full; check peers and clock |
High load_factor on your requests |
Public port under-provisioned or abusive clients | Rate-limit at nginx; scale node_size/hardware |
| Crash loop after config edit | Syntax error or unknown section for this version | journalctl -u xrpld -n 50; validate against the shipped example config |