Rippled Setup Runbook — Hetzner CPX32¶
Author: Vesper Date: 2026-04-22 Updated: 2026-04-22 — CPX32 (US-only SKU) replaced with CPX32 Nuremberg per Atlas ruling Atlas directive: "Treat rippled as infrastructure, not as an experiment. Boring setup, documented, health checks, clear separation from engine runtime, no improvising once the install starts." Atlas ruling: CPX32 Nuremberg approved — operational sufficiency + cost sanity + architectural alignment beats exact SKU symmetry. Status: Ready to execute
Overview¶
This runbook rescales the existing Hetzner CPX22 (neo-engine, 178.104.245.3, Nuremberg) to CPX32 and installs a stock rippled XRPL node for use as the NEO engine's local RPC endpoint. It replaces the external managed RPC dependency (QuikNode → public bridge → self-hosted).
What this is: A stock rippled node — keeps recent ledger history only (default 256 ledgers). Sufficient for all engine operations: account_offers, account_info, submit, account_tx.
What this is not: A full-history archive node. We do not need that.
Phase 0 — Pre-Setup Checklist¶
Complete all before touching the server.
- Hetzner account access confirmed
- SSH key pair ready (use existing key from CPX22 if available)
- Public RPC bridge (
s1.ripple.com) confirmed working (fallback during setup) - Engine is NOT running during server setup
-
neo_live_stage1.dbis backed up locally before any migration steps
Note on CPX22: The existing CPX22 server (178.104.245.3) will be rescaled to CPX32 in-place. Same IP is retained. Nothing is deployed on CPX22, so there is no data to migrate.
Phase 1 — Rescale CPX22 → CPX32 on Hetzner¶
1.1 Rescale the server¶
In Hetzner Cloud console (console.hetzner.com):
- Navigate to Servers → neo-engine (CPX22, 178.104.245.3)
- Click the Rescale tab
- Select Regular Performance → x86 (AMD)
- Select CPX32 (4 vCPU, 8 GB RAM, 80 GB SSD)
- Leave "CPU and RAM only" unchecked — no disk expansion needed (disk stays at 80 GB, which is the CPX32 default)
- Click Rescale and confirm
Cost: ~$16.49/month + $0.60 IPv4 = ~$17.09/month (Hetzner Nuremberg) Downtime: Brief reboot — server powers off, rescales, powers back on. Typically 2–5 minutes. IP retained: 178.104.245.3 — same IP after rescale.
1.2 Wait for rescale to complete¶
Monitor the server status in the Hetzner console. Status will go: Running → Off (rescaling) → Running.
Note the server's IP address (178.104.245.3 — unchanged).
1.2 First login¶
Confirm you are on the right server:
Expected: Ubuntu 22.04, ~7.7 GB RAM free, ~160 GB disk.
Phase 2 — Basic Server Hardening¶
Run once, takes ~5 minutes.
2.1 Update packages¶
2.2 Set timezone to UTC¶
2.3 Configure firewall (UFW)¶
rippled needs ports 51235 (peer protocol — other XRPL nodes connect here). RPC port 5005 stays localhost-only (not exposed).
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 51235/tcp # XRPL peer protocol
ufw enable
ufw status
Do NOT expose port 5005 to the internet. Engine connects to localhost.
2.4 Create a non-root user for engine operations (optional but recommended)¶
adduser neo
usermod -aG sudo neo
# Copy SSH key
mkdir -p /home/neo/.ssh
cp /root/.ssh/authorized_keys /home/neo/.ssh/
chown -R neo:neo /home/neo/.ssh
chmod 700 /home/neo/.ssh
chmod 600 /home/neo/.ssh/authorized_keys
Phase 3 — Install rippled¶
Official Ripple packages for Ubuntu 22.04. Do not install from source or unofficial repos.
3.1 Add Ripple apt repository¶
apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL https://repos.ripple.com/repos/api/gpg/key/public | \
gpg --dearmor > /usr/share/keyrings/ripple-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/ripple-archive-keyring.gpg] \
https://repos.ripple.com/repos/rippled-deb jammy stable" | \
tee /etc/apt/sources.list.d/ripple.list
apt-get update
3.2 Install rippled¶
Verify installation:
rippled is installed as a systemd service but NOT started yet. Do not start until configured.
Phase 4 — Configure rippled (Stock Node)¶
The default config file is at /etc/opt/ripple/rippled.cfg. We replace it with a clean stock config.
4.1 Back up the default config¶
4.2 Write the stock node config¶
cat > /etc/opt/ripple/rippled.cfg << 'EOF'
# NEO Engine — stock rippled node config
# Author: Vesper | Date: 2026-04-22
# Stock node: recent ledger history only (no full archive)
[server]
port_rpc_admin_local
port_peer
[port_rpc_admin_local]
port = 5005
ip = 127.0.0.1
admin = 127.0.0.1
protocol = http
[port_peer]
port = 51235
ip = 0.0.0.0
protocol = peer
[node_size]
medium
[node_db]
type=NuDB
path=/var/lib/rippled/db/nudb
advisory_delete=0
[database_path]
/var/lib/rippled/db
[debug_logfile]
/var/log/rippled/debug.log
[sntp_servers]
time.windows.com
time.apple.com
time.nist.gov
pool.ntp.org
[validators_file]
/etc/opt/ripple/validators.txt
[rpc_startup]
{ "command": "log_level", "severity": "warning" }
[ssl_verify]
0
EOF
4.3 Verify validators file exists¶
If missing (rare), reinstall the package: apt-get install --reinstall rippled
4.4 Set correct permissions¶
Phase 5 — Start rippled and Monitor Sync¶
5.1 Enable and start the service¶
Status should show active (running).
5.2 Watch the log for sync progress¶
What you will see:
- Initial: LedgerConsensus: Syncing... — normal, syncing from network
- Progress: NetworkOPs: STATE->Tracking — connected to peers, downloading ledger
- Healthy: NetworkOPs: STATE->Full — fully synced, ready to serve RPC
Expected sync time: 2–6 hours on CPX32 with NVMe storage and Hetzner's network. Do not interrupt.
5.3 Check peer connections during sync¶
Should show 5–20 peers within a few minutes of starting. If 0 peers after 10 minutes, check firewall (port 51235).
5.4 Check sync state¶
States in order: disconnected → connected → syncing → tracking → full
Only proceed to Phase 6 when state = full.
Phase 6 — Validate RPC Endpoint¶
Run these from the server itself (localhost only).
6.1 Basic connectivity check¶
curl -s -X POST http://127.0.0.1:5005 \
-H "Content-Type: application/json" \
-d '{"method":"server_info","params":[{}]}' | \
python3 -m json.tool | grep server_state
Expected: "server_state": "full"
6.2 Account info check (use the NEO wallet address)¶
curl -s -X POST http://127.0.0.1:5005 \
-H "Content-Type: application/json" \
-d '{
"method": "account_info",
"params": [{
"account": "rPzFU5zgphszGzC86GfTbZ8nkVGe3Trmn4",
"ledger_index": "current"
}]
}' | python3 -m json.tool | grep -E "Balance|account"
Expected: shows current XRP balance (in drops, divide by 1,000,000 for XRP).
6.3 Fee check¶
curl -s -X POST http://127.0.0.1:5005 \
-H "Content-Type: application/json" \
-d '{"method":"fee","params":[{}]}' | \
python3 -m json.tool | grep median_fee
Expected: a reasonable fee value (not null, not error).
All three checks must pass before the engine is pointed at this node.
Phase 7 — Health Check Setup¶
Add a simple health check alias for ongoing monitoring.
cat >> /root/.bashrc << 'EOF'
# rippled health check
alias rip-status='rippled server_info | python3 -m json.tool | grep -E "server_state|complete_ledgers|peers|uptime"'
alias rip-log='journalctl -u rippled -n 50 --no-pager'
EOF
source /root/.bashrc
Usage:
- rip-status — quick state check
- rip-log — last 50 log lines
7.1 Confirm systemd auto-restart is enabled¶
Expected: enabled — rippled restarts automatically on reboot or crash.
Phase 8 — Update Engine Config¶
Once Phase 6 validation passes, update the engine to use the local node.
8.1 Update config_live_stage1.yaml¶
Change the RPC URLs in config/config_live_stage1.yaml on Katja's local machine (and later on the VPS copy):
rpc_url: "http://127.0.0.1:5005"
websocket_url: "wss://127.0.0.1:6006" # if websocket needed; use ws:// for localhost
Note: The local rippled endpoint is HTTP (not HTTPS). This is correct and intentional for localhost — TLS adds no security value for loopback traffic.
8.2 Verify engine can reach the node¶
Run the realignment dry-run from the repo (once engine is on the VPS or while still local with SSH tunnel):
python tools/realign_inventory_to_onchain.py \
--config config/config_live_stage1.yaml \
--db neo_live_stage1.db \
--dry-run
Expected: connects cleanly, shows current on-chain balances. No connection errors.
Phase 9 — Decommission CPX22¶
Once CPX32 is running and the engine is migrated:
- Confirm all data is copied off CPX22
- Take a final snapshot in Hetzner console (optional, cheap insurance)
- Delete CPX22 server in Hetzner console
Do not delete CPX22 until at least one full clean session has run on CPX32.
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
rippled not starting |
Config syntax error | rippled --conf /etc/opt/ripple/rippled.cfg to see error |
| 0 peers after 10 min | Firewall blocking 51235 | ufw allow 51235/tcp && ufw reload |
Stuck in syncing > 6 hours |
Network issue or bad peers | Restart service: systemctl restart rippled |
| RPC returns error | Node not yet full |
Wait for sync; check rip-status |
| Engine can't connect | Wrong URL or port | Confirm http:// (not https://) and port 5005 |
Reference¶
- Ripple official install docs: https://xrpl.org/install-rippled-on-ubuntu.html
- rippled config reference: https://xrpl.org/rippled-server-config.html
- Server states: https://xrpl.org/rippled-server-states.html
Vesper — 2026-04-22 Atlas-approved: Option C, CPX32, stock node