Infrastructure operations: setting up and running an XRPL node (rippled), configuration, monitoring, and understanding the network topology.
What you'll learn
Up to now you've treated the XRP Ledger as a service you connect to — a WebSocket endpoint someone else keeps online. In this module you flip that around and become the someone else. You'll run your own node: the same server software that thousands of machines run worldwide to form the network you've been querying.
The server is called rippled (the binary is now named xrpld), an open-source C++ daemon maintained at XRPLF/rippled. Every node speaks a peer-to-peer protocol with its neighbors, exchanges transactions and proposed ledgers, and independently applies the same rules to arrive at the same answer. There is no central server to ask — the ledger is the agreement of all these nodes. When you run one, you stop trusting someone else's view of history and start verifying it yourself.
By the end you'll have a node running locally in Docker, synced against a test network, answering API calls — and you'll understand the handful of config knobs that matter and how to tell, at a glance, whether your node is healthy.
There are three honest reasons to run a node, and it's worth being clear about which one you're after, because it changes how you configure things.
Independence. A public endpoint can rate-limit you, go down, or quietly lag behind. Your own node answers only to you. If you're building a product that submits transactions or reads balances at volume, running your own server is the difference between a dependency and infrastructure you control.
Verification. Your node doesn't take anyone's word for the state of the ledger. It re-applies every transaction and checks every signature itself. Running one is the most concrete way to internalize that the XRPL is trustless: you're not asking a server "what's the balance?" — your server computes it.
Participation. A node can go further than observing and actually help secure the network by validating. We'll get to that distinction next, because it's the most common point of confusion.
Almost everyone's first node should be a stock server, and understanding why means understanding the three modes.
A stock server is a node with a near-default config. It connects to peers, downloads and verifies ledgers, applies new transactions, and serves the API. It does everything you need to read the ledger, submit transactions, and stay in sync. Think of it as a fully-participating listener: it hears every proposal and checks every result, but it doesn't cast a vote.
A validator is a stock server that has been given a signing key and turned on to vote in consensus. Validation is disabled by default — you opt in. A validator proposes which transactions belong in the next ledger and helps the network agree. Crucially, validating doesn't make your node faster or give it more data; it's a contribution to the network, not a feature for you. It also raises the stakes: a validator needs a carefully-managed cryptographic key pair, and there's little benefit to one operator running several validators. Run a validator when you want to help secure a network and have earned a place in others' trust lists — not as a default.
A full-history server keeps every ledger since the genesis of the network, so it can answer questions about ancient transactions. Most nodes keep only a recent window of history to save disk. Full history is expensive and, for serving historical API queries at scale, the XRPL ecosystem usually reaches for Clio — a separate API server purpose-built to sit alongside rippled and serve history efficiently — rather than a giant full-history rippled.
For this module you'll run a stock server. It's the foundation; the other modes are configuration changes on top of it.
Before you launch anything, a reality check on resources, because a node that can't keep up is worse than no node — it silently falls behind.
The published production recommendations are substantial: a multi-GHz 64-bit x86_64 CPU with 8+ cores, 64 GB of RAM, and fast local SSD/NVMe storage rated for high sustained IOPS (on the order of 10,000 sustained), with at least ~50 GB for the database partition to start. The storage advice is the one people ignore at their peril: network-attached disks (like Amazon EBS) often have too much latency for a node to stay synced, so local NVMe is strongly preferred.
That sounds heavy — and for a production mainnet node carrying real traffic, it is. For learning on a test network in Docker, you can get away with far less, because test networks are smaller and you'll keep only recent history. Treat the big numbers as the target for the day you run this for real, not as a barrier to your first sync today.
The fastest path to a running node is Docker — it bundles the binary and its dependencies so you don't have to build C++ from source. (Building from source is real and documented in the repo's BUILD.md using CMake and Conan for dependencies; it's the right move when you need a custom build, but it's not where you start.)
Start from a published rippled/xrpld image and a config that points at a test network rather than mainnet. A minimal docker-compose.yml looks like this:
services:
rippled:
image: xrpllabsofficial/xrpld:latest
container_name: xrpld
ports:
- '5005:5005' # JSON-RPC admin/API
- '6006:6006' # WebSocket API
volumes:
- ./config:/config # your rippled.cfg lives here
- ./data:/var/lib/rippled/db # ledger database persists here
restart: unless-stopped
The two volumes lines are the important part. One mounts your config into the container so you control the node's behavior. The other persists the ledger database on the host, so restarting the container doesn't throw away the sync progress you've already made — re-syncing from scratch is slow and pointless.
Bring it up with:
docker compose up -d
docker compose logs -f rippled
In the logs you'll watch the node find peers, request ledgers, and grind toward sync. The first sync takes a while — be patient and watch the state climb.
rippled.cfg is long, but only a few sections decide what your node is. The example configs in the repo's cfg/ folder are the canonical starting point — copy one and change these:
[server] and the port stanzas ([port_rpc_admin_local], [port_ws_public], …) define which APIs your node exposes, on which ports, and who's allowed to call admin commands. These map to the ports you published in Docker.[ips_fixed] / [ips] tell the node which peers to connect to. To join a test network instead of mainnet, you point these at that network's published peer addresses — this single choice is what determines which ledger your node syncs.[node_db] sets the database backend and where ledger data is stored, plus online_delete — how many recent ledgers to keep. This is the knob that decides whether you're a lean recent-history node or heading toward full history.[validator_list_sites] / [validator_list_keys] point the node at the trusted validator list (the UNL) for the network you're joining. A node uses this list to decide whose consensus votes to trust — even a non-validating stock server needs it to know what "agreement" looks like.You do not set a validation key for a stock server. The moment you add a [validator_token] you've crossed into running a validator, with all the key-management responsibility that implies. Leave it out.
A running container isn't the same as a healthy node. The single most useful command is server_info, which reports the node's own assessment of its health. Call it against your node:
curl -s -X POST http://localhost:5005 \
-H 'Content-Type: application/json' \
-d '{"method":"server_info","params":[{}]}' | jq '.result.info'
Three fields tell you almost everything:
server_state — the headline. While catching up you'll see connected or syncing; a healthy stock node settles into full (and a validator into proposing). Anything stuck in connected or disconnected means it can't keep up — check peers and disk.complete_ledgers — the range of ledger sequences your node actually holds, e.g. "a-b". A widening, recent range means you're tracking the network. A single number or empty value means you have almost nothing yet.peers — how many neighbors you're talking to. Zero peers means a networking or [ips] problem; you'll never sync without them.You can ask the same thing over WebSocket on the 6006 port — the API is identical to the public endpoints you've used all module, except now you're talking to your server. That's the whole point: every account_info, ledger, and submit call you've made against someone else's node, you can now make against your own.
You're done when a node you launched is genuinely participating in a network — not just a container that started. Concretely: your node reaches a synced server_state of full (or proposing if you went as far as a validator), shows a non-zero peers count and a recent complete_ledgers range, and answers a server_info call over its own API. Capture that server_info response as proof. Make the run reproducible by committing your docker-compose.yml / Dockerfile and your rippled.cfg (redact any secrets) with a short README of the steps, and have a peer follow it to a synced node of their own.
Assignments
0 of 1 complete