These tutorials are written by Freedom Lab members in their free time. If you find them helpful, please consider supporting our work.

TutorialsSetup your Bitcoin node from source

Setup your Bitcoin node from source

Bitcoin Linux Self-hosting

This tutorial is for advanced users with good technical skills. For a more guided setup, consider using Umbrel OS instead.

In this tutorial we setup our own Bitcoin node from scratch! What is covered:

We assume the reader might not own their internet connection or have access to the router's admin interface. Therefore, this guide defaults to a Tor-only setup.

Credits

This tutorial would have not been possible without TheRoadToNode and Harry Bawsac.

Hardware List

If you don't want to use a Pi then just ssh into an old laptop or VPS and fast forward to Prepare the system.

This is the hardware I use in this tutorial:

You'll find that on Amazon or anywhere else.

Unlike the Umbrel method, this approach does not require a separate microSD card for the OS. Everything will be flashed and installed directly onto the portable SSD.

Flash Raspberry Pi OS

Download Pi Imager

To flash the OS onto the portable SSD we will use a software utility called Raspberry Pi Imager. You can download it here.

Choose OS image

Now connect the portable SSD to your computer and launch the Pi Imager. First you have to select 3 options:

Raspberry Pi OS Lite does not include a GUI or extra utilities, allowing us to conserve system resources.

Apply custom settings

Click on Next. The imager will now show a popup to ask you if you want to apply customisation settings. Click on Edit Settings.

General Tab

Services Tab

In the previous tab, we ensured the creation of a new user and automatic Wi-Fi connection at boot. In this tab, we will set up an SSH service to enable direct login to the Pi after it boots.

We won't use password authentication. It's better practice and safer to use public-key authentication.

First we must generate a pair of keys for our user:

ssh-keygen -t ed25519 -C "youremail@whatever.com"

Next we must copy the content of the public key (*.pub). Now in the Services tab of the Pi Imager:

Click Save, we are now done with the customizations.

Flash the OS

Back on the customisation popup, click Yes to apply the settings you just inputed. Click Yes again to flash the OS onto the SSD.

Once it's done, safely eject the SSD from your computer.

Make sure to safely backup your user credentials and your SSH private key.

Assemble the hardware

Plug the portable SSD into a USB 3.0 port on the Pi, then connect the Pi to power. Wait approximately 10 minutes for the installation process and the first boot to complete.

The Pi 4 and Pi 5 should automatically detect and boot from the portable SSD without requiring any manual configuration.

SSH into the Pi

You can now connect to your Pi via SSH using the private key you created previously:

ssh -i your_private_key username@hostname.local

or

ssh -i your_private_key username@IP

Prepare the system

Update the system

sudo apt update && sudo apt upgrade -y

Disable SSH Password Login

In the SSH configuration, make sure password login is disabled (PasswordAuthentication no)

sudo cat /etc/ssh/sshd_config | grep PasswordAuthentication

Setup a firewall

We need to setup a firewall to restrict inbound traffic for our node.

First we install it:

sudo apt install ufw

By default ufw denies all incoming traffic so we must allow inbound SSH traffic before we enable it:

sudo ufw allow 22/tcp

Now we can enable the firewall:

sudo ufw enable

We can check the status with those commands:

sudo ufw status
sudo ufw status verbose

Install Tor

Install Tor:

sudo apt install tor

Add your user:

sudo usermod -a -G debian-tor your-user

You must log out and log back in for the changes to take effect.

Finally we can enable Tor at boot and start it:

sudo systemctl enable tor
sudo systemctl start tor

Install Bitcoin Core dependencies

The following packages will be needed to install Bitcoin Core:

sudo apt install git automake autoconf autotools-dev build-essential cmake make pkg-config protobuf-compiler libminiupnpc-dev libprotobuf-dev libdb++-dev libzmq3-dev libsqlite3-dev libboost-thread-dev libboost-test-dev libboost-all-dev libevent-dev libtool libssl-dev libboost-system-dev libboost-filesystem-dev capnproto libcapnp-dev

If you get the error Error: Unable to locate package libdb++-dev then you must specify the version number. Run apt search 'libdb.*++-dev'and install the latest version displayed. Example: libdb5.3++-dev

Install Node.js

This is only required if you plan to install BTC RPC Explorer.

The steps to install Node.js 23 are detailed here.

Install curl:

sudo apt install curl

Download the setup script:

curl -fsSL https://deb.nodesource.com/setup_23.x -o nodesource_setup.sh

Run it:

sudo -E bash nodesource_setup.sh

Install node:

sudo apt install nodejs

Verify the installation:

node -v

And also update npm to the latest version:

sudo npm install -g npm@latest

Install Rust and Cargo

This will be needed by the Electrum server if you plan on installing it.

Install dependencies:

sudo apt install -y clang cmake

Install Rust and Cargo:

curl https://sh.rustup.rs -sSf | sh

Install Bitcoin Core

Get latest stable version

First clone the repo:

cd ~
git clone https://github.com/bitcoin/bitcoin.git

Next we need to make sure to use the latest stable version. To find it, list the latest tags:

cd bitcoin/
git describe --tags `git rev-list --tags --max-count=20`

The output will look like this:

v28.1
v28.1rc2-6-g36314b8da2
v28.1rc2-5-g58910279dc
v28.1rc2-4-g6a68ef9bfb
v28.1rc2-3-g5b368f88a9
v28.1rc2-2-g05cd448e33
v28.1rc2-1-g621c634b7f
v28.1rc2
v28.1rc1-10-g5576618152
v28.1rc1-9-g01fe07a2ce
v28.1rc1-8-g7ddfcf32da
v28.1rc1-7-ge0b27b234c
v28.1rc1-6-gbdc6b3e531
v28.1rc1-5-ga0585b6087
v28.1rc1-4-gbbde830b97
v28.1rc1-3-g227642d5af
v28.1rc1-2-gb8112cf422
v28.1rc1-1-g2835158be0
v28.1rc1
v28.0-15-g8fef83a0a0

From top (newest) to bottom (oldest) tags, the latest stable version is v28.1.

Stable versions are easily recognizable by their clean format, vX.Y (e.g., v28.1), with no additional suffixes like rc or commit metadata.

Versions with rc in their names are called release candidates (preliminary versions).

Some versions simply represent intermediate development states, serving as milestones.

The tag v28.0-15-g8fef83a0a0 indicates version v28.0 with 15 additional commits, followed by the short commit hash 8fef83a0a0.

Alternatively you can find the latest stable version here and take note of the tag here.

Now we can switch to that version:

git checkout <version-tag> # Example: git checkout v28.1

Configure, Compile and Install

For version 29 and after

Since version 29, bitcoin switched to CMake to compile.

Create the configuration files:

cmake -B build -DBUILD_GUI=OFF # OPTION 1: Wallet functionalty enabled
cmake -B build -DBUILD_GUI=OFF -DENABLE_WALLET=OFF # OPTION 2: Wallet functionality disabled

The wallet functionality lets the node manage its own keys, addresses, and transactions. Disabling it removes these features but still allows connection and use of external wallets for validation and broadcasting.

If you change your mind, just delete the build/ directory and go again.

Now compile the source code:

cmake --build build -j $(nproc)

Finally, copy the binaries to system-wide directories:

sudo cmake --install build

For version 28 and before

Until version 28 included, bitcoin used autotools for compilation.

Create the configuration files:

./autogen.sh

Use one of the following two commands to apply the configuration files:

./configure --without-gui # OPTION 1: Wallet functionalty enabled
./configure --without-gui --disable-wallet # OPTION 2: Wallet functionality disabled

Now compile the source code:

make -j $(nproc)

Finally, copy the binaries to system-wide directories:

sudo make install

Verify Installation

Run the following to verify the installation:

bitcoin --version
bitcoind --version

Configure Bitcoin Core

Base Configuration

Let's create the needed files:

cd ~
mkdir ~/.bitcoin
touch ~/.bitcoin/bitcoin.conf

Add the following configuration to the bitcoin.conf file we just created:

With the configuration below the node will be accessible only on localhost and on the Tor network. Refer to the configuration file on this page if you wish to also expose your node via IPv4/IPv6.

# Enable JSON-RPC API on port 8332
server=1
# Restrict JSON-RPC API to localhost only
rpcbind=127.0.0.1
rpcallowip=127.0.0.1
# Run Bitcoin Core as a background daemon
daemon=1
# Accept incoming P2P traffic (port 8333) to be a full participant in the network 
# If set to 0, other nodes can't sync from us, but we can still sync from them
listen=1
# Keep full index of all transactions, not just those of the node's wallet.
# Uses more space but allows querying any transaction by its txid
# We need it if we want to run an Electrum Server or a blockchain explorer
txindex=1
# Cache size in MBs. Lower it to 500 after the first blockchain sync is complete. 
dbcache=3000
# Run the node **only** on the Tor network
onlynet=onion
proxy=127.0.0.1:9050
bind=127.0.0.1
# Use native segwit addresses by default
addresstype=bech32
changetype=bech32

JSON-RPC API

Bitcoin provides a control interface via a JSON-RPC API on port 8332. We enabled with server=1 in the bitcoin.conf file.

Other locally running applications that need to interact with Bitcoin's JSON-RPC API will use the cookie located at ~/.bitcoin/.cookie.

If you ever want to connect remotely running applications to the JSON-RPC API, you can create a set of credentials with the command below:

python3 ~/bitcoin/share/rpcauth/rpcauth.py <username-of-your-choice>

Verify the output and append the mentioned line to the bottom of the bitcoin.conf file.

Save the plain text password securely because the line added to bitcoin.conf contains only the hash.

Configure Tor

Bitcoin Core and other applications you install will heavily rely on Tor to connect with peers and ensure our wallets remain accessible. Proper configuration is critical.

Tor-default Configuration

Edit the default tor configuration file:

sudo vim /etc/tor/torrc

Add the following lines:

SocksPort 9050
ControlPort 9051
CookieAuthentication 1
CookieAuthFileGroupReadable 1

This configuration restricts Tor's control port to only local programs launched by our user.

Now restart tor:

sudo systemctl restart tor@default

Tor-Instance Configuration

If you're using a different tor instance,the config above won't work because bitcoin won't be able to find the cookie auth file for the instance. So instead we will use password authentication to access the control port.

Choose a strong password, then generate a hash with tor:

tor --hash-password "YourStrongPasswordHere"

This will output a hash for the password specified, example:

16:DCC57869A5B8899B60F099CCF421641762DDD9DEFBB385F28A2031CE3C

Now edit your tor instance config like /etc/tor/instances/tor4bitcoin/torrc to add the following:

SocksPort 9060
ControlPort 9061
HashedControlPassword
16:DCC57869A5B8899B60F099CCF421641762DDD9DEFBB385F28A2031CE3C

Replace ports 9060/9061 by whatever free port you want.

Now enable and start the tor instance:

sudo systemctl enable --now tor@tor4bitcoin

Next edit ~/.bitcoin/bitcoin.conf and edit this line with the right tor socks port:

proxy=127.0.0.1:9060

Next add these lines. Make sure to add the right tor control port and the password you chose before.

torcontrol=127.0.0.1:9061
torpassword=YourStrongPasswordHere

Hidden Onion Service for the JSON-RPC API

Exposing the RPC API is not recommended unless you fully understand the risks. It is a prime target for brute-force attacks and zero-day exploits. If compromised, an attacker could steal your Bitcoin IF you enabled the node's wallet and had funds in it.

As configured, the JSON-RPC API is accessible only from localhost. To expose this port externally, you can create a Tor service for it.

Configure systemd service

Bitcoin Core's main program is bitcoind (short for Bitcoin Daemon). We will configure it as a systemd service to simplify management:

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

Add the following:

[Unit]
Description=Bitcoin Daemon
After=network.target

[Service]
User=your_user
PIDFile=/home/your_user/.bitcoin/bitcoind.pid
ExecStart=/usr/local/bin/bitcoind
Restart=always
TimeoutSec=120
RestartSec=30

[Install]
WantedBy=multi-user.target

Finally, reload systemd:

sudo systemctl daemon-reload

Start Bitcoin Core

Startup

Configure bitcoind to automatically start at boot:

sudo systemctl enable bitcoind.service

Start bitcoind:

sudo systemctl start bitcoind.service

Initial Synchronization

Your node will now connect to other peers to download and verify the entire blockchain, block by block, starting from the genesis block on January 3, 2009.

Sync is in progress. This operation may take 3 to 7 days to complete.

Monitoring

Logs

To view the Bitcoin Core logs:

tail -f ~/.bitcoin/debug.log

You can monitor progress live by checking for height= or progress=.

bitcoin-cli

bitcoin-cli is part of Bitcoin Core and serves as a command-line interface for the JSON-RPC API.

Node Status

You can use it to monitor the status of your node and the synchronization progress:

bitcoin-cli -getinfo

Network Info

You can use it to check your integration with the P2P network:

bitcoin-cli getnetworkinfo

If you're using Tor, note in the output how Bitcoin used the Tor control port to create an onion service for P2P on port 8333.

[...]
"localaddresses": [
    {
        "address": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion",
        "port": 8333,
        "score": 4
    }
[...]

You can find the full list of bitcoin-cli commands here.

Blockchain Data

Get the current block height:

bitcoin-cli getblockcount

Get some blockchain statstics:

bitcoin-cli getblockchaininfo

Post Synchronization

Once fully synchronized, edit Bitcoin's config file located at ~/.bitcoin/bitcoin.conf, and lower the value of dbcache to 500. Then, restart Bitcoin:

sudo systemctl restart bitcoind.service

Setup Electrs

An Electrum server is an indexing layer built on top of Bitcoin Core. It enables more efficient blockchain queries and easier wallet connections. Most wallets support Electrum.

We're going to use Electrs, a Rust implementation of an Electrum Server.

Make sure your node is 100% synchronized before proceeding.

Install Electrs

Clone the repo:

cd ~
git clone https://github.com/romanz/electrs.git

Source the env file to update your $PATH with Rust & Cargo binaries:

. "$HOME/.cargo/env"

The binaries might already be in your PATH if Rust automatically added ."$HOME/.cargo/env" to your .profile, .bashrc, or .zshrc.

You can verify this with the command:

grep -H '.cargo/env' ~/.bashrc ~/.zshrc ~/.profile

Now you can compile electrs:

cd electrs
cargo build --locked --release

Once it's done, test the compilation was successful by checking the version:

~/electrs/target/release/electrs --version

Configure Electrs

Create the configuration file:

mkdir ~/.electrs && mkdir ~/.electrs/db && touch ~/.electrs/config.toml

Add the following configuration to the config.toml file we just created:

With the configuration below the Electrum server will be accessible only on localhost and on the Tor network. Refer to the configuration file on this page if you wish to also expose your node via IPv4/IPv6.

cookie_file = "/home/alex/.bitcoin/.cookie"
daemon_rpc_addr = "127.0.0.1:8332"
daemon_p2p_addr = "127.0.0.1:8333"
db_dir = "/home/alex/.electrs/db"
network = "bitcoin"
electrum_rpc_addr = "127.0.0.1:50001"
log_filters = "INFO"

Using 127.0.0.1 ensures that only locally running applications and Tor traffic can access our Electrum server.

Create Tor hidden service

We need to create a Tor hidden service to connect our wallets to the Electrum server. Edit the conf file:

sudo vim /etc/tor/torrc

Add the following:

HiddenServiceDir /var/lib/tor/electrs_hidden_service/
HiddenServicePort 50001 127.0.0.1:50001

Save it then restart tor:

sudo systemctl restart tor

Configure systemd service

Create the service file:

sudo vim /etc/systemd/system/electrs.service

Add the following:

[Unit]
Description=electrs
Requires=bitcoind.service
After=bitcoind.service
[Service]
WorkingDirectory=/home/your_user/electrs
ExecStart=/home/your_user/electrs/target/release/electrs
User=your_user
Group=your_user
Type=simple
Restart=on-failure
TimeoutSec=120
RestartSec=30

[Install]
WantedBy=multi-user.target

Line 6,7,8 and 9 make sure to replace your_user by your own user. Finally, reload systemd:

sudo systemctl daemon-reload

Startup

Configure Electrs to automatically start at boot:

sudo systemctl enable electrs.service

Start Electrs:

sudo systemctl start electrs.service

Electrum will now connect to Bitcoin Core to build its own index of the blockchain.

Indexing is in progress. This operation may take 12 to 24 hours to complete.

Monitoring

Check the logs and monitor progress in real time:

journalctl -u electrs.service -f

Setup BTC RPC Explorer

BTC RPC Explorer is essentially a web GUI for the Bitcoin JSON-RPC API. It is highly useful for node monitoring, management, and as a blockchain explorer.

Before you start make sure you've installed Node.js.

Install BTC RPC Explorer

Get the latest stable release

Clone the repo:

cd ~
git clone https://github.com/janoside/btc-rpc-explorer.git
cd btc-rpc-explorer/

Show the latest version tags:

git describe --tags `git rev-list --tags --max-count=20`

Switch to the latest stable version:

git checkout -f <version-tag>

Install

Update local dependencies within version ranges specified in package.json:

npm update

Install:

npm install

If you get an error try updating the following packages to their latest version instead:

npm install zeromq@latest
npm install nan@latest

Then try installing again:

npm install

Configure

Create the config file:

touch .env

Add the following:

BTCEXP_HOST=192.168.1.52
BTCEXP_PORT=3002
BTCEXP_BITCOIND_HOST=127.0.0.1
BTCEXP_BITCOIND_PORT=8332
BTCEXP_BITCOIND_COOKIE=/home/your_user/.bitcoin/.cookie
BTCEXP_BITCOIND_RPC_TIMEOUT=5000
BTCEXP_PRIVACY_MODE=true
BTCEXP_BASIC_AUTH_PASSWORD=your_secure_password
BTCEXP_ADDRESS_API=electrum
BTCEXP_ELECTRUM_SERVERS=tcp://127.0.0.1:50001

With this setup, BTC RPC Explorer is accessible from any machine on our LAN, is password-protected, and also connected to our Electrum server.

Configure systemd service

Create the service file:

sudo cat /etc/systemd/system/btc-rpc-explorer.service

Add the following:

[Unit]
Description=BTC-RPC-Explorer
Requires=electrs.service
After=electrs.service
[Service]
WorkingDirectory=/home/your_user/btc-rpc-explorer
ExecStart=npm run start
User=your_user
Group=your_user
Type=simple
Restart=on-failure
TimeoutSec=120
RestartSec=30
[Install]
WantedBy=multi-user.target

Line 6,8 and 9 make sure to replace your_user by your own user.

See .env-sample to discover more options.

Finally, reload systemd:

sudo systemctl daemon-reload

Startup

Configure BTC-RPC Explorer to automatically start at boot:

sudo systemctl enable btc-rpc-explorer.service

Start BTC-RPC Explorer:

sudo systemctl start btc-rpc-explorer.service

Access BTC RPC Explorer at http://NODE-IP:3002 from any device on your LAN.

You'll see a popup asking you to enter a username and password. The username doesn't matter; just use the password you set up in the .env file.

Issue with Node Details page

The page /node-details of BTC RPC Explorer throws an error. I suck at coding but I was able to fix it with ChatGPT.

Edit the below file:

vim views/node-details.pug

At line 29, replace this block of code:

if (getblockchaininfo.warnings && getblockchaininfo.warnings.trim().length > 0)
	+contentSection("Active Warnings")
		if (getblockchaininfo.warnings && getblockchaininfo.warnings.trim().length > 0)
			span.text-danger #{getblockchaininfo.warnings}
		else
			span.text-success None

By this one:

if (getblockchaininfo.warnings)
	+contentSection("Active Warnings")
		if (getblockchaininfo.warnings)
			span.text-danger #{getblockchaininfo.warnings}
		else
			span.text-success None

(Basically I removed getblockchaininfo.warnings.trim().length > 0 in both if statements).

This is a dirty DIY way of patching it, but it does the job lol.

Make sure to restart BTC RPC Explorer and the page should be working:

sudo systemctl restart btc-rpc-explorer.service

Tor

I personally wouldn't risk exposing this app to the outside world. It has some bugs, is vulnerable to brute-force attacks, and stores the password in a plain text .env file.

If I ever do, I will ensure that the features enabling manual Bitcoin JSON-RPC API calls are disabled.

Connect wallets

To connect your wallet to your node, simply add your Electrum server's address and port in the wallet's network settings.

You will find your Electrum server's address here:

sudo cat /var/lib/tor/electrs_hidden_service/hostname

The port is 50001 unless you specified otherwise.

When connecting your wallet, ensure Tor is enabled (or bundled with your wallet); otherwise, you won't be able to access your node.

Update Process

Keep your node software up to date:

Update the OS

Do this frequently:

sudo apt update && sudo apt upgrade -y

Update Bitcoin Core

For more details and context on this process, refer to the installation step.

Verify what your current version is:

bitcoind --version

Fetch the latest changes:

cd ~/bitcoin
git fetch --all

Show the latest version tags:

git describe --tags `git rev-list --tags --max-count=20`

Switch to the latest stable version:

git checkout -f <version-tag>

Configure, Compile and Install

For version 29 and after

Since version 29, bitcoin switched to CMake to compile.

Clear files and outputs from the previous build process:

rm -rf build

Create the configuration files:

cmake -B build -DBUILD_GUI=OFF # OPTION 1: Wallet functionalty enabled
cmake -B build -DBUILD_GUI=OFF -DENABLE_WALLET=OFF # OPTION 2: Wallet functionality disabled

Compile the source code:

cmake --build build -j $(nproc)

For version 28 and before

Until version 28 included, bitcoin used autotools for compilation.

Clear files and outputs from the previous build process:

make clean

Create the configuration files:

./autogen.sh

Use one of the following two commands to apply the configuration files:

./configure --without-gui # OPTION 1: Wallet functionalty enabled
./configure --without-gui --disable-wallet # OPTION 2: Wallet functionality disabled

Compile the source code:

make -j $(nproc)

Stop, Install and Restart

Once the compilation is done, we stop Electrs and bitcoind:

sudo systemctl stop electrs.service
sudo systemctl stop bitcoind.service

Wait until both programs have exited cleanly. You can monitor the logs for confirmation.

Now we can update the binaries system-wide:

sudo cmake --install build # For version 29 and after
sudo make install # For version 28 and before

Finally we can restart bitcoind and Electrs:

sudo systemctl start bitcoind.service
sudo systemctl start electrs.service

You can check your new version with:

bitcoind --version

Update Rust

If Rust and Cargo binaries aren't in your path, run:

. "$HOME/.cargo/env"

Update Rust and Cargo:

rustup update

Update rustup:

rustup self update

Check the new versions:

rustc --version
cargo --version
rustup --version

Now, update all packages installed with Cargo by running:

cargo install-update -a

If you encounter an error because cargo-update is not installed, install it using:

cargo install cargo-update

Update Electrs

For more details and context on this process, refer to the installation step.

Make sure to update Rust first before proceeding.

Fetch the latest changes:

cd ~/electrs
git fetch --all

Show the latest version tags:

git describe --tags `git rev-list --tags --max-count=20`

Switch to the latest stable version:

git checkout -f <version-tag>

Stop Electrs:

sudo systemctl stop electrs.service

Source the env file and compile

. "$HOME/.cargo/env"
cargo build --locked --release

Start electrs:

sudo systemctl start electrs.service

Verify the new version:

~/electrs/target/release/electrs --version

Update Node.js

Update Node.js to the latest version:

sudo apt update && sudo apt upgrade -y nodejs

Update npm to the latest version globally:

sudo npm install -g npm@latest

Update all globally installed npm packages:

sudo npm update -g

Update BTC RPC Explorer

For more details and context on this process, refer to the installation step.

Make sure to update Node.js first before proceeding.

Fetch the latest changes:

cd ~/btc-rpc-explorer
git fetch --all

Show the latest version tags:

git describe --tags `git rev-list --tags --max-count=20`

Switch to the latest stable version:

git checkout -f <version-tag>

Stop BTC RPC Explorer:

sudo systemctl stop btc-rpc-explorer.service

Update the dependencies:

npm update

Install the updates:

npm install

Once it's done, you can start BTC RPC Explorer again:

sudo systemctl start btc-rpc-explorer.service