Self-host a Monero node on a VPS: monerod, pruning, public RPC and Tor

· 9 min read

Run monerod on an Ubuntu 24.04 VPS: disk sizing, hash verification, systemd unit, pruning, public restricted RPC on 18089, Tor tx-proxy, wallet setup.

What you get from your own monerod

Monero wallets scan every transaction on the chain to find their outputs, which means a wallet pointed at a public remote node tells that node your IP, your wallet’s refresh height and roughly when you transact. Running monerod yourself removes that observer. On a VPS it is also always on, so your phone and desktop wallets sync in seconds instead of catching up on days of blocks.

This guide sets up a pruned node, exposes a restricted RPC endpoint you can point your own wallets at (and optionally share as a public node), and pushes transaction broadcasts through Tor so the node’s IP is not the origin of your transactions.

Disk, RAM and bandwidth sizing

Monero’s blockchain is larger than most people expect because ring signatures and range proofs make each transaction a few kilobytes. Pruning keeps about a third of the data for roughly seven eighths of blocks and still fully validates everything.

  • Pruned: around 100 GB today, growing a few GB a month. A 40 GB plan is out; you need a plan with at least 160 GB of NVMe, and 240 GB or more if you want it to last without resizing.
  • Full (unpruned): roughly 250 GB and up. Only worth it if you intend to serve pruned sync to other nodes or run analytics.
  • RAM: monerod sits at 1.5 to 3 GB during sync. 4 GB is the comfortable minimum; on 2 GB add swap and expect slower initial sync.
  • Bandwidth: initial sync is about 100 GB inbound with --sync-pruned-blocks. A public node afterwards can push 20 to 100 GB a day, so set rate limits as shown below.

Prepare the server

Everything below assumes a fresh Ubuntu 24.04 image and a root shell (prefix sudo if you created a user). Patch first, then lock down SSH and the firewall before anything else is listening.

apt update && apt full-upgrade -y
apt install -y ufw unattended-upgrades curl gnupg

# SSH: keys only. Put your public key in /root/.ssh/authorized_keys first and
# confirm you can log in with it before disabling passwords.
cat > /etc/ssh/sshd_config.d/00-keys-only.conf <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
EOF
sshd -t && systemctl restart ssh

# Firewall: deny everything inbound except SSH for now.
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw --force enable

Download and verify the Monero CLI

getmonero.org publishes a GPG-signed hashes.txt for every release. Verify the signature, then confirm your tarball’s hash appears in it. The signing key belongs to binaryFate; its fingerprint is 81AC 591F E9C4 B65C 5806 AFC3 F0AF 4D46 2A0B DF92. Compare that against what the Monero site and GitHub repository show rather than trusting this page.

cd /tmp
# linux64 for the x86 BVX plans, linuxarm8 for the Arm BVA plans.
case "$(uname -m)" in
  x86_64)  TARGET=linux64 ;;
  aarch64) TARGET=linuxarm8 ;;
esac
curl -L -o monero.tar.bz2 https://downloads.getmonero.org/cli/$TARGET
curl -LO https://www.getmonero.org/downloads/hashes.txt

curl -L -o binaryfate.asc https://raw.githubusercontent.com/monero-project/monero/master/utils/gpg_keys/binaryfate.asc
gpg --import binaryfate.asc
gpg --fingerprint binaryFate
gpg --verify hashes.txt          # expect "Good signature from binaryFate"

grep -q "$(sha256sum monero.tar.bz2 | cut -d' ' -f1)" hashes.txt && echo HASH OK || echo HASH MISMATCH
tar xjf monero.tar.bz2
install -m 0755 -o root -g root -t /usr/local/bin monero-*/monerod monero-*/monero-wallet-cli monero-*/monero-wallet-rpc
monerod --version

User, config file and systemd unit

monerod accepts the same options on the command line or in a config file (same names, no leading dashes). The file is easier to maintain than a long ExecStart line.

useradd --system --home-dir /var/lib/monero --shell /usr/sbin/nologin monero
install -d -m 0750 -o monero -g monero /var/lib/monero /var/log/monero
install -d -m 0750 -o monero -g monero /etc/monero

cat > /etc/monero/monerod.conf <<'EOF'
data-dir=/var/lib/monero
log-file=/var/log/monero/monerod.log
log-level=0
max-log-files=5

# Storage
prune-blockchain=1
sync-pruned-blocks=1

# P2P
p2p-bind-ip=0.0.0.0
p2p-bind-port=18080
no-igd=1
out-peers=32
in-peers=64
limit-rate-up=4096      # kB/s
limit-rate-down=16384   # kB/s

# Unrestricted RPC: localhost only, for you.
rpc-bind-ip=127.0.0.1
rpc-bind-port=18081

# Restricted RPC: safe to expose. Wallets connect here.
rpc-restricted-bind-ip=0.0.0.0
rpc-restricted-bind-port=18089
public-node=1

no-zmq=1
EOF
chown monero:monero /etc/monero/monerod.conf
# /etc/systemd/system/monerod.service
[Unit]
Description=Monero daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=monero
Group=monero
ExecStart=/usr/local/bin/monerod --config-file /etc/monero/monerod.conf --non-interactive
Restart=always
RestartSec=10
TimeoutStopSec=120

PrivateTmp=true
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
PrivateDevices=true

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now monerod
ufw allow 18080/tcp    # P2P
ufw allow 18089/tcp    # restricted RPC for wallets
tail -f /var/log/monero/monerod.log

The restricted RPC only answers the subset of calls a wallet needs; it cannot mine, stop the daemon or dump internal state. public-node=1 advertises that endpoint to peers so other users’ wallets can discover it. Drop that line and restrict 18089 in ufw to your own IPs if you want a private remote node only.

Broadcast transactions over Tor

Chain sync over clearnet is fine; what you want to hide is which node first announced your transaction. The --tx-proxy option sends your own transaction broadcasts through Tor (via Dandelion++ stems) while leaving block sync on the fast path. Optionally, an onion service lets other Tor users peer with you anonymously.

apt install -y tor
cat >> /etc/tor/torrc <<'EOF'
HiddenServiceDir /var/lib/tor/monero/
HiddenServiceVersion 3
HiddenServicePort 18084 127.0.0.1:18084
EOF
systemctl restart tor
cat /var/lib/tor/monero/hostname     # your onion address

cat >> /etc/monero/monerod.conf <<EOF

# Tor
tx-proxy=tor,127.0.0.1:9050,16
anonymous-inbound=$(cat /var/lib/tor/monero/hostname):18084,127.0.0.1:18084,25
EOF
systemctl restart monerod

Connect a wallet and watch the sync

# On the server: height vs target_height tells you how far along sync is.
curl -s http://127.0.0.1:18081/get_info | tr ',' '\n' | grep -E '"(height|target_height|synchronized|incoming_connections_count|outgoing_connections_count)"'

# From your laptop, once synced:
monero-wallet-cli --daemon-address YOUR.SERVER.IP:18089 --wallet-file mywallet

In the Monero GUI or Feather, set a custom remote node with your server’s IP and port 18089. For a bit more privacy on the wallet side, point the wallet at your node’s onion address over Tor instead of the clearnet IP, or tunnel 18089 through SSH. If other people are using your public node, keep an eye on bandwidth with vnstat or the limit-rate-* values and raise or lower them as the budget allows.

Upgrades: repeat the download and verification steps, install over the old binaries, and restart monerod. Monero hard forks are scheduled in advance and announced on getmonero.org; a node on an old version stops syncing at the fork height, so do not ignore release announcements.

Which plan to pick

A pruned monerod needs storage before anything else: choose a plan with at least 160 GB of NVMe and 4 GB of RAM; the smallest that fits is 4 vCPU, 8 GB RAM, 160 GB NVMe from about $59/mo. If you want to run a public node for others, favour an EU region (Falkenstein, Nuremberg or Helsinki) and keep the rate limits in place. Configure a server, pay in Bitcoin or another supported coin, and you will have root access from the emailed magic link in a few minutes.

Ready to run this yourself?

Linux KVM servers with NVMe storage in the EU, US and Singapore. Root access arrives by magic link; no account, no KYC.

Configure a server — pay with Bitcoin, no account needed