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 enableDownload 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 MISMATCHtar 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 --versionUser, 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.targetsystemctl 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.logThe 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 monerodConnect 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 mywalletIn 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.