# How to run a pruned Bitcoin Core node on a VPS

> Run a pruned Bitcoin Core node on Ubuntu 24.04. Verify the download, set prune and dbcache, start bitcoind with systemd and follow the initial sync.

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](https://datapasa.com/en/crypto-node-vps) lists plan recommendations for other networks too.
- **Ubuntu 24.04** and SSH access as root. See [how to connect via SSH](https://datapasa.com/wiki/server-management/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](https://datapasa.com/en/crypto-vps).

> **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](https://bitcoincore.org/en/download/) 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:

| Field | Meaning |
|---|---|
| `blocks` / `headers` | Validated blocks versus known headers. Headers sync first, then blocks catch up. |
| `verificationprogress` | Progress from 0 to 1. It is not linear, recent blocks are heavier. |
| `initialblockdownload` | `true` until the node has caught up with the network. |
| `pruned` | Should be `true`. |
| `size_on_disk` | Stays 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](https://datapasa.com/wiki/guides/run-lightning-node-lnd) shows a lighter setup that does not need a local `bitcoind` at all.
