Skip to content

How to run a pruned Bitcoin Core node on a VPS

A Bitcoin Core full node checks every block and transaction against the consensus rules itself, so you do not have to trust anyone else's view of the chain. A pruned node does the same validation but keeps only the most recent blocks on disk. This guide installs Bitcoin Core on Ubuntu 24.04, verifies the download, configures pruning and runs bitcoind as a systemd service.

What you need

  • A VPS with 2 vCPU, 4 GB RAM and 64 GB of disk. On DataPasa that is the VPS-3 plan. Our crypto node VPS page lists plan recommendations for other networks too.
  • Ubuntu 24.04 and SSH access as root. See how to connect via SSH.
  • Enough traffic for the first sync. More on that below.

You can pay for the server with BTC or other coins, see crypto VPS hosting.

Pruning does not save traffic

A pruned node still downloads and verifies the whole blockchain once, from the first block to today. That is well over 700 GB of download, plus upload to other peers. VPS-1 includes only 1 TB of traffic per month, so it is not a good fit. VPS-2 and larger plans include 32 TB.

Step 1. Download Bitcoin Core

Open the official download page and note the latest version number. Set it in a variable, for example if the page shows 31.1:

bash
VERSION=31.1
cd /tmp
wget https://bitcoincore.org/bin/bitcoin-core-${VERSION}/bitcoin-${VERSION}-x86_64-linux-gnu.tar.gz
wget https://bitcoincore.org/bin/bitcoin-core-${VERSION}/SHA256SUMS
wget https://bitcoincore.org/bin/bitcoin-core-${VERSION}/SHA256SUMS.asc

Step 2. Verify the checksum and signatures

First check that the archive matches the list of checksums:

bash
sha256sum --ignore-missing --check SHA256SUMS

The output must end with bitcoin-VERSION-x86_64-linux-gnu.tar.gz: OK.

The checksum file itself is signed by several Bitcoin Core builders. Import their public keys from the guix.sigs repository and check the signatures:

bash
apt install -y git gnupg
git clone https://github.com/bitcoin-core/guix.sigs
gpg --import guix.sigs/builder-keys/*
gpg --verify SHA256SUMS.asc SHA256SUMS

You should see several lines starting with gpg: Good signature. Warnings that a key is "not certified with a trusted signature" are normal unless you have built a web of trust. Warnings about missing public keys can be ignored as long as the signers you trust are present.

Stop if verification fails

If a checksum does not match or no good signatures appear, delete the files and download them again. Never run a binary that failed verification.

Step 3. Install the binaries

Unpack the archive and copy the daemon and the command line client:

bash
tar -xzf bitcoin-${VERSION}-x86_64-linux-gnu.tar.gz
install -m 0755 -o root -g root -t /usr/local/bin bitcoin-${VERSION}/bin/bitcoind bitcoin-${VERSION}/bin/bitcoin-cli
bitcoind -version

Create a system user that will run the node:

bash
useradd --system --no-create-home --shell /usr/sbin/nologin bitcoin

Step 4. Write bitcoin.conf

The service below keeps its configuration in /etc/bitcoin and its data in /var/lib/bitcoind, the same layout as the official systemd unit from the Bitcoin Core repository.

bash
mkdir -p /etc/bitcoin
nano /etc/bitcoin/bitcoin.conf

Paste this configuration:

ini
server=1
prune=10000
dbcache=2048
maxconnections=40
  • prune=10000 keeps about 10,000 MiB (roughly 10 GB) of recent blocks. The minimum allowed value is 550. A larger value leaves more history for rescans.
  • dbcache=2048 gives the UTXO cache 2 GB of RAM, which speeds up the initial sync a lot. On a 4 GB server lower it to 1024 or remove the line after the sync is done.
  • server=1 enables the local RPC interface for bitcoin-cli. RPC listens only on localhost by default, keep it that way.

The chain state database is stored in addition to the pruned blocks and grows over time, so a 64 GB disk leaves comfortable room.

Set the permissions so the service user can read the file:

bash
chown -R root:bitcoin /etc/bitcoin
chmod 0710 /etc/bitcoin
chmod 0640 /etc/bitcoin/bitcoin.conf

Step 5. Create the systemd service

Create /etc/systemd/system/bitcoind.service:

bash
nano /etc/systemd/system/bitcoind.service

This unit is based on contrib/init/bitcoind.service from the Bitcoin Core repository, with the binary path changed to /usr/local/bin:

ini
[Unit]
Description=Bitcoin daemon
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/bitcoind -pid=/run/bitcoind/bitcoind.pid \
                                  -conf=/etc/bitcoin/bitcoin.conf \
                                  -datadir=/var/lib/bitcoind \
                                  -startupnotify='systemd-notify --ready' \
                                  -shutdownnotify='systemd-notify --stopping'
Type=notify
NotifyAccess=all
PIDFile=/run/bitcoind/bitcoind.pid
Restart=on-failure
TimeoutStartSec=infinity
TimeoutStopSec=600
User=bitcoin
Group=bitcoin
RuntimeDirectory=bitcoind
RuntimeDirectoryMode=0710
StateDirectory=bitcoind
StateDirectoryMode=0710
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
PrivateDevices=true
MemoryDenyWriteExecute=true

[Install]
WantedBy=multi-user.target

The long TimeoutStopSec matters: on shutdown bitcoind flushes its cache to disk, and killing it early can force a slow reindex.

Start the node and enable it at boot:

bash
systemctl daemon-reload
systemctl enable --now bitcoind
systemctl status bitcoind

Step 6. Follow the initial block download

Run bitcoin-cli as the bitcoin user so it can read the RPC cookie in the data directory:

bash
sudo -u bitcoin bitcoin-cli -datadir=/var/lib/bitcoind getblockchaininfo

Watch these fields:

FieldMeaning
blocks / headersValidated blocks versus known headers. Headers sync first, then blocks catch up.
verificationprogressProgress from 0 to 1. It is not linear, recent blocks are heavier.
initialblockdownloadtrue until the node has caught up with the network.
prunedShould be true.
size_on_diskStays near your prune target plus a small buffer.

Other useful checks:

bash
sudo -u bitcoin bitcoin-cli -datadir=/var/lib/bitcoind getnetworkinfo
sudo -u bitcoin bitcoin-cli -datadir=/var/lib/bitcoind getconnectioncount
journalctl -u bitcoind -f

On a 2 vCPU server the initial sync usually takes from one to several days. CPU and disk speed matter more than bandwidth here. You can close the SSH session, the service keeps running.

Accept incoming peers

Outgoing connections are enough for your own node. If you want to help the network, allow port 8333: ufw allow 8333/tcp. A pruned node can relay new blocks and transactions but cannot serve old blocks.

Limit traffic after the sync

Once initialblockdownload is false, daily traffic drops a lot. If you want to cap upload, add a daily target in MiB to bitcoin.conf, for example maxuploadtarget=5000, and restart with systemctl restart bitcoind. Bitcoin.org recommends not going below 144 MiB per day.

What pruning cannot do

  • The node cannot serve historical blocks to other peers.
  • txindex=1 is not compatible with pruning, so you cannot look up arbitrary old transactions.
  • Rescanning a wallet older than the kept blocks requires a full resync.

If you need these features, you need an unpruned node with over 1 TB of disk.

Summary

You downloaded and verified Bitcoin Core, set prune and dbcache, and run bitcoind as a hardened systemd service. After the first sync the node validates new blocks on its own. If you are interested in Lightning payments, the LND with Neutrino guide shows a lighter setup that does not need a local bitcoind at all.