Bitcoin Full Node on RBP3 (revised)

Damian Mee
17 min readNov 29, 2017

This is a revised version of the previous guide, that covers the upgraded Raspbian Stretch & Bitcoin v0.16.3.

This guide assumes you’re on MacOS, comfortable with terminal and want to run a headless Bitcoin Full Node on a Raspberry Pi 3, setting it up w/o attaching any peripherals to RBP3.

Things you need:

  • Raspberry Pi 3;
  • MicroSD card—as of June 2018 Bitcoin blockchain is 200GB in size, so you need at least 256GB+ for a full non-pruned node (recommended) or 8GB++ for a pruned node (the more free space is left on the card the longer it will last);
  • a way to plug the microSD card into your Mac;
  • around 5 weeks of time for the initial sync (as of mid-2018);
  • (optionally) HDD/SSD to store blockchain on it instead;
  • (optionally) USB stick to use as SWAP memory;

Get Raspbian Lite image

Either via torrent or by abusing Raspberry Pi Foundation servers.

Download latest version directly:

wget --content-disposition

Verify (hash below is for

# NOTE: 2 spaces are needed between hash and filename
echo "5a0747b2bfb8c8664192831b7dc5b22847718a1cb77639a1f3db3683b242dc96" | shasum -a 256 -c -
# the output should be something like: OK

If the downloaded filename is different, go to the raspbian download page and get the correct SHA-256 checksum from there.

Put image on the SD card

# Extract .img file from .zip archive

Plug the SD card into your computer and run this to identify the disk of your SD card:

diskutil list | grep external

Assuming it’s /dev/disk2:

# Unmount it
diskutil unmountDisk /dev/disk2
# Copy image to the SD card
sudo dd bs=1m if=2018-04-18-raspbian-stretch-lite.img of=/dev/disk2

For OSs other than MacOS, see here.

The above step should leave you with /Volumes/boot already mounted.

Enable ssh

Starting with Raspbian 2016–11–25 SSH is disabled by default. To enable it, a file named ssh needs to be created in the root of the SD card.

touch /Volumes/boot/ssh

More about it here.

Add WiFi credentials

To avoid using ethernet cable & simply speed things up, you can add your first WiFi credentials already (as per this SE post):

nano /Volumes/boot/wpa_supplicant.conf

And put there this:

ctrl_interface=/var/run/wpa_supplicant GROUP=netdev

Note: Starting with Raspbian 2018-03-13 specifying country is required.

Replace XX with country code of the country where RBP will be located, fill-in network details, and use ctrl+x, y, enter to exit nano 😉.


diskutil unmountDisk /dev/disk2

Connect & secure Raspberry

Once above is done, put the card into your Raspberry & power it up.

After a few minutes, it should boot up. Now it’s time to find its IP address.

There are multiple ways to do that, the easiest one would probably be logging into your router interface (most commonly: or and trying to find it there.

If that doesn’t work you can also try:

# MAC prefix 'b8:27:eb:' is reserved for RBP Foundation
# see more:
arp -a | grep 'b8:27:eb'

Or, if that doesn’t work, you can try nmapping your local network for open 22/tcp ports:

nmap -A '192.168.0-1.*' -p T:22 --open

Assuming the IP of your RBP is, ssh to it (default password is raspberry):

ssh pi@

Note: You might be greeted with a bunch of locale warnings. Feel free to ignore them for now.


To decrease chances of your RBP joining some IoT botnet, change/set passwords for default users (you can use the same password for both pi and root):

## On RBP# for pi
# for root
sudo passwd root

We also need to create user bitcoin and a password for it:

## On RBPsudo adduser bitcoin
Adding user `bitcoin' ...
Adding new group `bitcoin' (1001) ...
Adding new user `bitcoin' (1001) with group `bitcoin' ...
Creating home directory `/home/bitcoin' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for bitcoin
Enter the new value, or press ENTER for the default
Full Name []:
Satoshi Nakamoto
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Lost since 2011. Definitely not Craig Wright.
Is the information correct? [Y/n] y

Note: Make sure to use difficult passwords and store both of them securely in a password manager.

Once you do that, close your current session:

## On RBPexit

Use keys to auth with ssh

Now that we’ve located the RBP and changed its password, let’s make ssh access more secure.

I use Ed25519 keys and I strongly encourage you to do the same. Here’s an easy why & how to switch guide. That being said, you can pass a path to any key in the command below:

## on Mac:ssh-copy-id -i ~/.ssh/ pi@

Next we need to disable password authentication. Either manually:

## On Mac:
ssh pi@
## On RBP:# edit ssh daemon config file
sudo nano /etc/ssh/sshd_config
# Find `#PasswordAuthentication yes` & below it add:
PasswordAuthentication no

Use ctrl+x, y, enter to exit nano 😉😉.

Or using a oneliner:

## On RBP:sudo sed -i '/#PasswordAuthentication yes/a PasswordAuthentication no' /etc/ssh/sshd_config

Listen to

It’s a good tool that offers good advice. If you want to see recommendations it gives, run:

## on Mac:git clone ssh-audit./

I won’t go into details here, but to follow its recommendations put this into /etc/ssh/sshd_config file on RBP3:

# make sure these are in the file and NOT commented out:
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# make sure these are either gone or commented out:
#HostKey /etc/ssh/ssh_host_dsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
# add the below lines

For Termius to work on mobile, you need to add diffie-hellman-group-exchange-sha256 to KexAlgorithms and hmac-sha-256 to MACs 😭.

For ConnectBot to work on mobile you only need to add hmac-sha2-512 to MACs 😢, as it supports Ed25519 curves.

Save the file and reload config of the ssh daemon:

## On RBP:sudo service ssh reload

Note: If you disconnect now you will need to remove line containing from ~/.ssh/known_hosts on your Mac before connecting again.

Permanent IP

To make things a bit more reliable for the future you might want to set a permanent IP for your Pi.

The easiest way to do it is to head over to your router admin page (likely or and find a “permanent IP” / ”DHCP Address Reservation section — each router is different, so you’re on your own here, but it will look something like:

Protip: If you set it up & restart your router before reconnecting, you will not have to fiddle with known_host file.

Public IP

To have your node as an active and contributing participant in the network, you might want to make sure you have a public (and static) IP. If not, most ISPs can usually provide it for a small fee.

Configure the Raspberry

All following commands are run on RBP, unless specified otherwise.

Localization, Time Zone, etc…

Run the below and feel free to play with the wizard there. You might want to change time zone and WiFi country. Also, “expanding the filesystem” is no longer necessary, as it happens automatically on the first boot (ref: scroll this to 2016–05–10).

sudo raspi-config# And if it didn't ask you to, run:
sudo reboot

Note: If you’ve set-up the localisation correctly, all the locale warnings should be gone now.

Get all the shiny updates

sudo apt update
sudo apt -y upgrade

External Hard Drive (optional)

External hard drive is one of the most sustainable and inexpensive ways to store the blockchain. If you have a spare and empty drive of the sufficient size, here’s how to set it up.

First, plug it in and see what’s its name with either:

sda 931.5G BUP Slim SL
├─sda1 200M EFI
├─sda2 931.2G SILVER
└─sda3 128M
sdb 14.3G Ultra Fit
└─sdb1 14.3G
mmcblk0 59.5G
├─mmcblk0p1 41.8M boot
└─mmcblk0p2 59.4G

Or (UUIDs & PARTUUIDs removed from output for brevity):

sudo blkid
/dev/mmcblk0p1: LABEL="boot" TYPE="vfat"
/dev/mmcblk0p2: TYPE="ext4"
/dev/sda1: LABEL="EFI" TYPE="vfat" PARTLABEL="EFI System Partition"
/dev/sda2: LABEL="SILVER" TYPE="exfat" PARTLABEL="Seagate Backup Plus Drive"
/dev/mmcblk0: PTTYPE="dos"
/dev/sda3: PARTLABEL="Booter"
/dev/sdb1: TYPE="swap"

In my case it’s a 1TB “Seagate Backup Plus Drive” labeled “SILVER”, so the device I’m looking for is: /dev/sda (last number is irrelevant for now).


Once the name is known, proceed to format the drive to a more linux-friendly file system:

Warning: this deletes all data and partitions on the drive.

sudo mkfs.ext4 /dev/sda -L BLOCK-STORAGE
mke2fs 1.43.4 (31-Jan-2017)
Found a gpt partition table in /dev/sda
Proceed anyway? (y,N)
Creating filesystem with 244190645 4k blocks and 61054976 inodes
Filesystem UUID:
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000, 214990848
Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done

You can verify if the disk got formatted correctly with:



Create the directory into which the disk will be mounted:

sudo mkdir /mnt/hdd

Determine UUID of the partition to be mounted:

sudo blkid | grep /dev/sda

Next, open fstab file with:

sudo nano /etc/fstab

And there, append (replacing XXXXXXXX with your UUID):

UUID=XXXXXXXX /mnt/hdd ext4 defaults 0 0

Save the file, and mount everything with:

sudo mount -a

Verify that it’s mounted:

ls -hal /mnt/hdd
total 24K
drwxr-xr-x 3 root root 4.0K Mar 6 15:51 .
drwxr-xr-x 3 root root 4.0K Mar 6 15:57 ..
drwx------ 2 root root 16K Mar 6 15:51 lost+found

And finally, let’s grant the entire drive to user bitcoin:

sudo chown -R bitcoin:bitcoin /mnt/hdd

Now, user bitcoin has full read/write rights, and user pi can only read, but not write (without sudo).

Note: If you encounter issues this or this can help.


For the ease of access (and to have instructions below consistent), let’s create a symlink for .bitcoin folder.

Switch to bitcoin user with:

sudo su - bitcoin

Now, create bitcoin datadir:

mkdir /mnt/hdd/bitcoin

And link it to the standard location:

ln -s /mnt/hdd/bitcoin /home/bitcoin/.bitcoin

After that exit bitcoin user, with:


Note: To unmount and detach the drive, follow the instructions from the “Unmounting an HDD“ section here.


SWAP on an SD card is bad, in fact, it can kill it in 30 days (according to the internet), to minimize writes let’s disable SWAPping to the card:

sudo swapoff --all

SWAP to HDD (optional)

If you chose to use HDD, as described above, you can also use it for SWAP (source). But do note, that SWAPping to HDD is really, really slow.

To do that anyway, open /etc/dphys-swapfile:

sudo nano /etc/dphys-swapfile

Find line:


Uncomment it and change the path to a file on the external hdd, ex:


Comment out:


And uncomment:


Save the file, and reboot your Pi with sudo reboot.

SWAP to USB (optional)

If you chose a path without HDD, you can put SWAP on a spare USB stick, if you have one laying around (source).

Let’s start with some cleanup:

sudo apt-get remove dphys-swapfile
sudo apt-get autoremove

Next, plug-in the USB stick, and find its name:

sudo blkid

/dev/sda1: UUID="D1AC-C562" TYPE="vfat" PARTUUID="c3072e18-01"

Knowing your device (ex. /dev/sda), run:

sudo mkswap /dev/sda

Once it completes, find UUID with TYPE="swap", ex:

sudo blkid

/dev/sda1: UUID="133a2665-f89b-4dc4-9a05-f2acb232b4e9" TYPE="swap"

Having it, open fstab file:

sudo nano /etc/fstab

And append it with a line similar to this (replace UUID with your own):

UUID=133a2665-f89b-4dc4-9a05-f2acb232b4e9 none swap sw,pri= 5 0 0

Save the file, and enable SWAP with:

sudo swapon -a

Reboot your RBP with sudo reboot.

Finally, the good stuff

The below steps are mostly, but loosely, based on the official UNIX BUILD NOTES.


Before we start, we need to install all required dependencies.

sudo apt install git build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libminiupnpc-dev libzmq3-dev jq

Get Bitcoin client

Go to and see what’s the newest stable release. As of September 2018 it’s v0.16.3:

Latest Bitcoin Core release as of September 2018 is v0.16.3

Knowing that:

cd ~git clone -b v0.16.3 bitcoin

Note: As gruesome as “detached HEAD” sounds, it’s exactly as it should be and there’s no reason to panic.

Protip: If you install Tor first, you’ll be able to clone Bitcoin source code anonymously from Wladimir-hosted repository at: http://nxshomzlgqmwfwhcnyvbznyrybh3gotlfgis7wkv7iur2yj2rarlhiad.onion/git/bitcoin.git. More about it in this Twitter thread.


At this point you need to decide whether you want your node with wallet or not. You can change it later, but it will require recompilation.

  • If you intend to run this node on testnet only, there are no real drawbacks to having it compiled with a wallet.
  • If you intend to run this node on mainnet and want to use it to store funds/sign transactions, I recommend you make sure your RBP is well secured. It is also not recommended to store non-insignificant funds on an internet-connected device.

Berkeley DB (optional)

If you chose the path with wallet you need a very specific version (4.8) of Berkeley db. Luckily, there’s now a convenient script in the Bitcoin repo that does it for you — send love for that to James O’Beirne :), just run:

./contrib/ $(pwd)

Bitcoin Client


If you want it with wallet, run:

export BDB_PREFIX=$(pwd)/db4./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" --enable-cxx --without-gui --disable-shared --with-pic --enable-upnp-default

If you want it without wallet, run:

./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" --enable-cxx --without-gui --disable-shared --with-pic --disable-tests --disable-bench --enable-upnp-default --disable-wallet

Regardless of the choice above continue:

# this might take a few hours
sudo make install

Note: While make will run for many hours, your ssh session must be kept open. To avoid that consider using tools like screen or, my choice, tmux.

Note_2: during make you might see a lot of warnings, fixing them might be a low-hanging-fruit way of becoming a Core contributor ;).


Probably the best way to get a well optimised ~/.bitcoin/bitcoin.conf file is to use the generator created by Jameson Lopp.

That being said, we first need to switch to the bitcoin user:

sudo su - bitcoin

Now, let’s create the required app data directory:

mkdir ~/.bitcoin

And put the minimal configuration to ~/.bitcoin/bitcoin.conf (note the dot in front of .bitcoin):

# makes client run in background
# is required by Fail2Ban described below
# magic RBP optimisations

If you chose to run without SWAP, also include:


Other optional, but useful:

  • upnp=1 — will try to automagically open a port on your router;
  • txindex=1 — will allow you to call getrawtransaction <tx> on all transactions (as opposed to only ones in the mempool and/or not fully spent). It’s a good idea to decide on this before the initial sync, changing it later will require a lengthy full -reindex;
  • testnet=1 — runs your node on a testnet, as opposed to mainnet;
  • rest=1 — enables REST interface on;
  • server=1 — enables JSON-RPC interface;
  • walletrbf=1 — ensure any transaction you send can be replaced with one paying a higher fee;
  • prune=X — Discards past validated state beyond last X MB. I recommend against node pruning, unless you neither have an SD card nor a hard drive that’s big enough. As an example a reasonable value for a 64GB storage medium would be prune=42000 (42GB);

Once the configuration is done, return the the pi user with:


Create bitcoind service

Inspiration taken from bitcoind.service, provided in the Bitcoin repository.

First, create relevant file:

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

And then paste all of the below there:

Description=Bitcoin daemon
ExecStart=/usr/local/bin/bitcoind -conf=/home/bitcoin/.bitcoin/bitcoin.conf -pid=/home/bitcoin/.bitcoin/
# Creates /run/bitcoind owned by bitcoin
# Hardening measures
# Provide a private /tmp and /var/tmp.
# Mount /usr, /boot/ and /etc read-only for the process.
# Disallow the process and all of its children to gain
# new privileges through execve().
# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
# Deny the creation of writable and executable memory mappings.

Once that’s done, make sure that the service starts on system start/reboot with:

sudo systemctl enable bitcoind


Now, just before we put things in motion, let’s spend a little bit of time following the, rather important, security recommendations from Raspbian.

Uncomplicated Firewall

Let’s install it first:

sudo apt install ufw

Note: ufw default rules allow for all outgoing connections, but block all incoming connections.

Let’s make sure that ssh access is allowed (but limited), with:

sudo ufw limit ssh 

That should be more than enough for a testnet node, however for a mainnet one, you might want to add a few more limitations on ssh. For example if you’re planning on accessing your node from local network only:

sudo ufw allow from to any port 22

Or/and if you have a dedicated static IP (through ex. your ISP or VPN):

sudo ufw allow from to any port 22

To allow for Bitcoin traffic, do:

# for mainnet …
sudo ufw allow 8333 comment "Bitcoin mainnet"
# … or, for testnet
sudo ufw allow 18333 comment "Bitcoin testnet"

Enable Firewall with:

sudo ufw enable

You can preview enforced rules with:

sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp LIMIT IN Anywhere
8333 ALLOW IN Anywhere
22/tcp (v6) LIMIT IN Anywhere (v6)
8333 (v6) ALLOW IN Anywhere (v6)


To install it, run:

sudo apt install fail2ban

To see active jails, run:

sudo fail2ban-client status
|- Number of jail: 1
`- Jail list: sshd

Unfortunately, I wasn’t able to find or come up with any useful Bitcoin filters yet (even though I tried), so we’ll have to stick with sshd only for now.

Note: If you have a filter that works, or you know that Bitcoin doesn’t need it, please do leave a comment.


sudo systemctl start bitcoind

Note: Rebooting your Pi to ensure Bitcoin starts on reboot is a good idea now.

Make sure it works

It might take a few minutes to start. You can watch progress by switching to bitcoin user and running:

tail -n 100 -f ~/.bitcoin/debug.log# or (for testnet)
tail -n 100 -f ~/.bitcoin/testnet3/debug.log

And here’s a few of handy commands that you can later use:

bitcoin-cli -getinfo

Make sure it’s accessible from outside

If you have public IP & chose upnp=1 your node should be accessible for the outside world. You can check it with:

curl -sL | jq# or for testnet:
curl -sL | jq

If the response is {"success":true}, just skip to the next step.

Otherwise, there are still some things that can be done, but since they’re all very setup-specific, I will just list some ideas that might be worth pursuing:

  • Wait a bit (UPnP is currently renewed every 20 minutes),
  • Restart node and wait until it boots up completely,
  • Make sure UPnP is supported and enabled on your router,
  • Assign a permanent local IP to Raspberry Pi, and
  • Manually set up port forwarding (for port 8333 or 18333),
  • Make sure your ISP provides you with a public IP (see above).
This is how a successful UPnP might look like

Note: If neither of the above worked, your node will still connect to 8 peers and, from your perspective, will still be fully functional. The only difference being it will not be able to relay blocks and serve SPV wallets.

Backup your wallet

If you chose to run a node with a wallet, now’s a good time to create a backup of your wallet.dat file, that should be located: /home/bitcoin/.bitcoin/wallet.dat. The wallet is deterministic, so making one backup now should be good forever.

Now wait, and wait, and wait…

Now, that the node is running it will download and process the entire Bitcoin blockchain. This process will take between one or two months. Just leave it running and it will get there eventually.

Protip: If you’re impatient, you can install Bitcoin Core on your computer, sync the chain there and then just copy it to your Raspberry Pi. Taking this path will be much, much faster. More about it here.

Trusted Node

Once the sync completes your node is ready for the grand cooperation with the excellent Samourai Wallet ❤️. To set it up follow the guide here:

Other thingies


If something goes wrong, or you just want to see your node working, you can peak in here:

tail -f -n 100 ~/.bitcoin/debug.log# or for testnet
tail -f -n 100 ~/.bitcoin/testnet3/debug.log

Note: Each restart generates a bunch of empty lines, so it’s really easy to spot it.

Make ssh welcome message pretty

There’s no reason to see that awful block of text every time you log in. Making it prettier was inspired with stuff from here.


wget -qO- | sudo sh

Note: This script has to run as sudo, consider reading what it does before running.


Save this as /etc/update-motd.d/20-raspberry-bitcoin, and:

chmod +x /etc/update-motd.d/20-raspberry-bitcoin

After either, just log in again, and you should be greeted with:

RBP greeting

You can summon the view above at any time with:

sudo run-parts --lsbsysinit /etc/update-motd.d

Note: If you configured SWAP on an external device as instructed above, you might want to also run sudo chmod -x /etc/update-motd.d/30-swap-warning to disable SWAP warning on ssh login.

Update Bitcoin Node

Check exactly what version you’re updating to, on the Releases page. Assuming it’s v0.17.0:

sudo systemctl stop bitcoindcd bitcoin
git fetch --tags
git checkout v0.17.0
# with wallet
export BDB_PREFIX=$(pwd)/db4
./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" --enable-cxx --without-gui --disable-shared --with-pic --enable-upnp-default
# without wallet
./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" --enable-cxx --without-gui --disable-shared --with-pic --disable-tests --disable-bench --enable-upnp-default --disable-wallet
# for both
sudo make install
# start Bitcoin
sudo systemctl start bitcoind

Note: The steps are identical to the initial ones (except, in most cases, you can skip BerkleyDB).

Mistakes? Improvements? Tips?

If you’ve found anything incorrect in this guide, or have an idea on how to improve it, feel free to either leave a comment, btc AT meedamian DOT com or @meeDamian me.

If you liked the guide, it helped you or you just want to contribute to my ticket to 🚀 Mars, you can do it either through my PayNym: +quietmath379, or more traditionally: bc1qm2rhkaj9s45p8dfkcjulqrusex6avyvhrfm9l4.


A whole lot of things changed. Updated guide to newest Raspbian version and Bitcoin v0.16.1. Added external HDD section. Added SWAP sections. Added running Bitcoin as a bitcoin user. Added bitcoind systemd service. Added ufw and fail2ban. And probably more 😬.

Added --disable-tests --disable-bench to config, and changed make check to make. And updated Bitcoin Core version to v0.16.3, which fixes a critical vuln.

Other Guides…

This is a third guide in a series of planned:

  1. Litecoin Full Node on RBP3,
  2. (obsolete) Bitcoin Full Node (with or w/o BIP148 UASF 🙊) on RBP3,
  3. Bitcoin Full Node on RBP3 (revised),
  4. Bitcoin through Tor on RBP3,
  5. Lightning Network (c-lightning) on RBP3,
  6. Lightning Network (lnd) on RBP3.



Damian Mee

Bitcoin. Lightning. Golang. Applied cryptography, not Blockchain. . PGP: D8CA 1776 EB92 6549 1D07 CE67 F546 ECBE A809 CB18