Fork me 🍴

Willian Antunes

Self-hosted wallet setup with Bitcoin Core using Docker

5 minute read

bitcoin, cryptocurrency

Table of contents
  1. Requirements
    1. Important notice about blockchain data
  2. Running the project
  3. Interacting with the wallet
  4. Using RegTest mode
  5. Important notice
  6. Conclusion.

This project is a proof of concept to demonstrate how to set up a self-hosted wallet using two Bitcoin Core nodes in pruned mode. One node***,*** bitcoin-core-middleware, acts as a regular node with no max peer connection limit, and the other node, bitcoin-core-wallet, acts with a max peer connection limit of 1, with no internet access. The middleware node will act as a peer to the wallet node. The wallet node is the key component for interacting with the wallet.dat in the self-hosted setup. It is the node you must use to access and manage the wallet. On the other hand, the middleware node serves as a peer to the wallet node, playing a supporting role in the setup.

Requirements

The JSON-RPC interface of both services will be exposed with a password. Let's generate them using rpcauth.py:

python rpcauth.py jaffar
python rpcauth.py jasmine

Sample output:

String to be appended to bitcoin.conf:
rpcauth=jafar:4fa794addec8e955123456ab93cf137c$279369610574dc4059ce1fd36b9232702ff8b8429fe6490dc856c0db02119795
Your password:
CYa-7c9-M_0_va3Qg_3vJHaimN-kiM

String to be appended to bitcoin.conf:
rpcauth=jasmine:3b821b7$17b114961abb15e83421856067a3843c15cb29fe259afaeda177b023
Your password:
Llc5yNHoZGrF4ctPPh_12dCg

Configure the generated rpcauth string in the bitcoin.conf file of both services. Store the password in a secure location.

Important notice about blockchain data

If possible, copy the entire blockchain data from someone else to avoid downloading it from scratch. Let's say you have it. Then you just copy the data and paste it somewhere, for example, in a folder named bitcoin-core-middleware. Now, you can create a volume to mount the folder to the container. Remember to copy the provided bitcoin.conf file to the folder. Example:

  bitcoin-core-middleware:
    build:
      context: .
    volumes:
      - "/tmp/bitcoin_core_middleware:/home/bitcoin/.bitcoin/"
    environment:
      - UID=$UID
      - GID=$GID
    networks:
      - web
      - no-internet

Run the service and wait for its full synchronization until it's fully pruned. Now, you can copy the entire folder and paste it with another name, for example, bitcoin-core-wallet. Again, remember to copy the provided bitcoin.conf file to the folder. Example:

  bitcoin-core-wallet:
    build:
      context: .
    volumes:
      - "/tmp/bitcoin_core_wallet:/home/bitcoin/.bitcoin/"
    environment:
      - UID=$UID
      - GID=$GID
    networks:
      - no-internet

Running the project

At the root folder of the project, just issue the following command:

UID=$UID GID=$GID docker compose up bitcoin-core-middleware

Now spin up the wallet container:

UID=$UID GID=$GID docker compose up bitcoin-core-wallet

It will add the middleware as peer to the wallet bitcoin-core node.

Interacting with the wallet

Given you have the wallet.dat file inside the /home/bitcoin/.bitcoin/ folder in bitcoin-core-wallet container, you can interact with the wallet using the bitcoin-cli command. Execute the following command to get the balance of the wallet:

UID=$UID GID=$GID docker compose exec bitcoin-core-wallet \
bitcoin-cli \
-rpcconnect=bitcoin-core-wallet \
-rpcuser=jasmine \
-stdinrpcpass \
getbalance

You'll have to enter the password generated earlier. 🔐

Using RegTest mode

Check out the blog Bitcoin Node with RegTest mode using Docker. You'll u how to create addresses, receive a blog reward of 50 bitcoins, and many more. You can easily adapt the provided Bitcoin configuration files with Bitcoin Core Config Generator.

Important notice

Try to keep your wallet.dat on a single computer. Don't keep it on multiple computers. For example, suppose you have your wallet.dat on device A and the very same file on device B. You create an address through device A, and then it receives money. If you try to check your balance through device B, it won't be able to retrieve the up-to-date value, even though your blockchain is fully synchronized. It happens because one wallet won't have addresses that are in the other. Don't lose your money. ⚠️

Another important point is that blockchain rescan capability on prune nodes is not possible at the time this article was written. Look at the issue regarding its implementation. This means you can't import your wallet.dat unless you repeat the initial synchronization of the blockchain, which takes a lot of time.

Conclusion.

Using two nodes is more secure. The middleware node has a connection to the internet. The wallet node does not have it. In case the middleware node is compromised, your wallet node is protected. The walled node serves only to sign transactions and the middleware to propagate them to the network. Of course, the attacker might access the wallet node through the middleware, though the chances of that happening are astronomically low. By the way, you can use an alternative approach of signing transactions offline and generating addresses with descriptors.

See everything we did here on GitHub.

Posted listening to Chitãozinho & Xororó, Majestado o Sabiá 🎶.


Have you found any mistakes 👀? Feel free to submit a PR editing this blog entry 😄.