a sovereign bitcoin stack
sovereign stack dependency graph
sovereign stack dependency graph

Contents

The Sovereign Stack

This guide will show you how to setup a bitcoin stack, so you can use bitcoin in a sovereign, private and secure manner.

The stack consists of five different software: Tor, Bitcoin Core, Electrs, Mempool and Sparrow Wallet.

To run this stack, provision a linux box. This guide assumes basic Unix knowledge, and a debian-based distro (I'm running Ubuntu Server 22.04). If you're running another distro branch, adjust accordingly. Ideally, you want at least 8GB of RAM and 2TB of storage to run everything comfortably for a few years.

Let's dive in and setup each one:


Tor

Tor is an network multi-layer encryption protocol, used in the Tor Network. It routs a packet across multiple nodes on the network, adding another layer of encryption on each one. That way, only the first node knows the source of the packet, and only the last node knows the destiantion of the packet. Middle nodes are completely blind to both source and destination. They merely receive an encrypted blob, add another encryption layer to it, and pass it on to the next hop.

Although Tor is a very good system, it is not perfect, since government actors are know to run exit nodes, which provide information they can use to perform correlation attacks. Also, the network is vulnerable to DDoS attacks, having been rendered pratically unusable in 2022 due to this.

More info can be found at torproject.org.

Install tor:

$ sudo apt install tor

Add this to /etc/tor/torrc:

ControlPort 9051
CookieAuthentication 1
CookieAuthFileGroupReadable 1

Add $USER to the debian-tor group:

$ sudo usermod -a -G debian-tor $USER

Restart tor:

$ sudo systemctl restart tor

That's it, tor is now running.


Bitcoin Core

Bitcoin Core is the reference implementation of the bitcoin consensus protocol, written in C++. It is responsible for building your own copy of the blockchain, connecting to other nodes, broadcasting transactions and deciding, based on it's own rules, if a received transaction block is valid or not. Your API to the network, in short.

It is actively developed by hundreds of people around the world, and follows a strict proposal-implementation-review process before any changes are merged to the master branch. Because of this, mistakes that pose a threat to the network are extremely rare.

More info can be found on github and bitcoincore.org.

Create a folder:

$ mkdir bitcoin && cd bitcoin

Import the maintainers PGP keys, so we can assure the integrity of the binary:

$ git clone https://github.com/bitcoin-core/guix.sigs
$ gpg --import guix.sigs/builder-keys/*

Download Bitcoin Core. At time of writing (827000), we are on release v26.0:

$ wget https://bitcoincore.org/bin/bitcoin-core-26.0/bitcoin-26.0-x86_64-linux-gnu.tar.gz

Download the list of SHA256 checksums and signatures of these checksums:

$ wget https://bitcoincore.org/bin/bitcoin-core-26.0/SHA256SUMS
$ wget https://bitcoincore.org/bin/bitcoin-core-26.0/SHA256SUMS.asc

Verify the checksum of the release file:

$ sha256sum --ignore-missing --check SHA256SUMS

Verify that the SHA256SUMS file was signed by the PGP keys imported earlier:

$ gpg --verify SHA256SUMS.asc

Extract the binary and install it:

$ tar xzf bitcoin-26.0-x86_64-linux-gnu.tar.gz
$ sudo install -m 0755 -o root -g root -t /usr/local/bin bitcoin-26.0/bin/*

Bitcoin Core is installed. Now start the daemon:

$ bitcoind

Let's configure it. Stop the process and navigate to ~/.bitcoin. Create a file named bitcoin.conf, and add the following to it (adjust it to your own environment):

# accept RPCs
server=1

# auth params for external calls
rpcuser=foo
rpcpassword=bar

# listen for RPCs on all interfaces
rpcbind=0.0.0.0

# allow RPCs from these addresses
rpcallowip=192.168.1.0/24

# index transactions
txindex=1

# only peer over Tor:
#proxy=127.0.0.1:9050
#listen=1
#bind=127.0.0.1

Let's create a systemd service for bitcoind, so it starts on boot and restarts on failure automatically. Go to /etc/systemd/system/ and create a file named bitcoind.service:

[Unit]
Description=Bitcoin Core Daemon
After=network-online.target

[Service]
User=<user>
Type=simple
Restart=on-failure
ExecStart=/usr/local/bin/bitcoind

[Install]
WantedBy=multi-user.target

Then, activate and start it:

$ sudo systemctl enable bitcoind.service
$ sudo systemctl start bitcoind.service

Now, let it sync. This may take a while, from hours to days, depending on your CPU.

Once it is synched to 100%, move to the next step.


Electrs


Electrs is a Rust implementation of the Electrum Server. It indexes all adresses and transactions on the blockchain, whereas Bitcoin Core only indexes those that concern the user's wallet. This allows quick queries for any address.

Wallets may come with a predefined, public (read: someone else's computer) electrum server. This implicates that this someone else has knowledge of all your transactions, balances and used addresses, along with your IP address. Not very private. If you run your own, that won't happen.

More info can be found on github.

Electrs will be built from source. Let's install the required dependencies:

$ sudo apt update
$ sudo apt install clang cmake build-essential
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source ~/.bashrc
$ cargo install cfg_me

Electrs can be both statically or dynamically linked. We'll link it statically.

Download the electrs repo:

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

Now build it (takes a while):

$ cargo build --locked --release

Let's create a systemd service for electrs. Go to /etc/systemd/system/ and create a file named electrs.service:

[Unit]
Description=Electrum Rust Server
After=bitcoind.service

[Service]
WorkingDirectory=/home/<user>/electrs
ExecStart=/home/<user>/electrs/target/release/electrs --log-filters INFO --db-dir ./db --electrum-rpc-addr="0.0.0.0:50001"
User=<user>
Group=<user>
Type=simple
KillMode=process
TimeoutSec=60
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

Add this line to ~/electrs/electrs.toml:

auth="foo:bar"

Then, activate and start it:

$ sudo systemctl enable electrs.service
$ sudo systemctl start electrs.service

Sync took about 5 hours on my box.

That's it. Onto the enxt.


Mempool

Mempool is a block and mempool explorer and visualizer. With it, you can query addresses, transactions (confirmed and unconfirmed) with a nice interface. The instance run by the developers can be found at mempool.space.

If you use a public explorer (mempool.space, blockstream.info, blockchain.com, ...), they can collect an address/transaction and IP pair. This enables some off-chain survaillance. By running your own instance, you are querying your own server.

It connects to both Bitcoin Core and Electrum on the backend.

More info can be found on github.

Download the mempool repo and checkout the latest release:

$ git clone https://github.com/mempool/mempool
$ cd mempool
$ latestrelease=$(curl -s https://api.github.com/repos/mempool/mempool/releases/latest|grep tag_name|head -1|cut -d '"' -f4)
$ git checkout $latestrelease

Now, let's setup MariaDB:

$ sudo apt install mariadb-server mariadb-client

Create a DB and grant privileges:

$ sudo mariadb

MariaDB [(none)]> drop database mempool;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> create database mempool;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> grant all privileges on mempool.* to 'mempool'@'%' identified by 'mempool';
Query OK, 0 rows affected (0.00 sec)

Install dependencies:

# install nvm
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
$ source ~/.bashrc

# install node.js v16.10
$ nvm install 16.10
$ nvm use 16.10

# install npm v7
$ npm install -g npm@7

Let's build the backend:

cd backend
npm install --no-install-links
npm run build

Now configure it:

$ cp mempool-config.sample.json mempool-config.json

On "CORE_RPC", change USERNAME and PASSWORD to match those on bitcoin.conf.

On "ELECTRUM", change "PORT" from 50002 to 50001.

I ran into a problem where mempool attempts to connect to a DB socket that does not exist (note that this will vary depending on your OS). On mempool-config.json, on "DATABASE", change "SOCKET" from:
/var/run/mysql/mysql.sock
to:
/run/mysqld/mysqld.sock

Let's make a systemd service for the mempool backend. Create a file named /etc/systemd/system/mempool-backend.service:

[Unit]
Description=Mempool Backend
After=electrs.service

[Service]
WorkingDirectory=/home/<user>/mempool/backend
ExecStart=/home/<user>/.nvm/versions/node/v16.10.0/bin/npm run start
Environment=PATH=/home/<user>/.nvm/versions/node/v16.10.0/bin/:/usr/local/bin:/usr/bin:/bin
User=<user>
Group=<user>
Type=simple
KillMode=control-group
TimeoutSec=60
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

Then enable it and start it:

$ sudo systemctl enable mempool-backend.service
$ sudo systemctl start mempool-backend.service

The mempool backend sync can take a while. You can move on to the frontend while you wait.

Now, let's build and run the frontend:

$ cd ~/mempool/frontend
$ npm install
$ npm run build
$ npm run serve

As is, you can only access it via localhost, since you probably should have a reverse proxy in front of it. But if you're just using it on your local network, that's hardly necessary. To access it on your LAN, modify the serve script in package.json to this:

"serve": "npm run generate-config && npm run ng -- serve --host 0.0.0.0 --disable-host-check",

What this does is bind the process mempool is running to all interfaces, not just localhost.

Now let's make a systemd service for the frontend. Create a file named /etc/systemd/system/mempool-frontend.service:

[Unit]
Description=Mempool Frontend
After=mempool-backend.service

[Service]
WorkingDirectory=/home/<user>/mempool/frontend
ExecStart=/home/<user>/.nvm/versions/node/v16.10.0/bin/npm run serve
Environment=PATH=/home/<user>/.nvm/versions/node/v16.10.0/bin/:/usr/local/bin:/usr/bin:/bin
User=<user>
Group=<user>
Type=simple
KillMode=control-group
TimeoutSec=60
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

Then enable it:

$ sudo systemctl enable mempool-frontend.service

Now, open the mempool frontent at <server_ip>:4200. Once the backend is done synching, you'll have a private block/address/transaction explorer running on your own infra.

You can use my instance at mempool.luisschwab.net.


Sparrow Wallet

Sparrow Wallet is a FOSS bitcoin-only wallet that enables easy UTXO management, supports offline signing (PSBT), native Tor support, PayNym support, and has a very nice UI.

This is where you make transactions, generate new addresses and the works.

It can connect to either Bitcoin Core or an Electrum Server.

More info can be found on sparrowwallet.com.

You'll install Sparrow on your personal machine. There is a TUI-based implementation (Sparrow Server), but it doesn't offer nearly as much functionality as the GUI version.

Begin by importing the developer's PGP key:

$ curl https://keybase.io/craigraw/pgp_keys.asc | gpg --import

Download the binary, the manifest and the manifest signature:

$ wget https://github.com/sparrowwallet/sparrow/releases/download/1.8.2/sparrow_1.8.2-1_amd64.deb
$ wget https://github.com/sparrowwallet/sparrow/releases/download/1.8.2/sparrow-1.8.2-manifest.txt
$ wget https://github.com/sparrowwallet/sparrow/releases/download/1.8.2/sparrow-1.8.2-manifest.txt.asc

Verify the release:

$ gpg --verify sparrow-1.8.2-manifest.txt.asc

You should see something like this:

gpg: assuming signed data in 'sparrow-1.8.2-manifest.txt'
gpg: Signature made Thu Jan 18 12:35:34 2024 SAST
gpg:                using RSA key D4D0D3202FC06849A257B38DE94618334C674B40
gpg: Good signature from "Craig Raw <[email protected]>" [unknown]

Check that the SHA256 hash of the binary matches the manifest:

$ sha256sum --check sparrow-1.8.2-manifest.txt --ignore-missing

sparrow_1.8.2-1_amd64.deb: OK

Install it:

$ sudo dpkg -i sparrow_1.8.2-1_amd64.deb

Once installed, open the wallet and press CTRL+P, and go to the server menu. Then, choose Private Electrum, and put your servers IP address and the port electrs is running at (50001). If you click Test Connection, you should see something like this:

Connected to electrs/0.10.2 on protocol version 1.4
Batched RPC enabled.
Server Banner: Welcome to electrs 0.10.2 (Electrum Rust Server)!

That's it. You're now running the sovereign stack.



follow the white rabbit