This repository, features some forms of self-hosting of bitcoin nodes:
It makes usage of docker-compose environments to host and expose different node configurations.
The repository contains 3 branches, representing different hosting environments configurations:
- prune: minimalist bitcoind node pre-configured as a prune node.
- full: a full
bitcoind
node pre-configured to also index transactions (txindex=1). - electrs: a full
bitcoind
node withtxindex=1
along with an electrs electrum server.
In all configurations bitcoind
operates in conjunction with TOR
for optimal security and anonymity.
All configurations support 4 ways of exposing your bitcoind
(and electrs
when applicable) services:
local
- service API only available in the node (127.0.0.1
) where the docker-compose environment runs.tor
- service API exposed using a tor hidden service through an onion address.vpn
- using tailscale service becomes available only in your VPN.all
- all of the above.
Notice that the option number 1.
can be used in conjunction with ssh tunnel ports
for remote access.
For an even stronger configuration, you can
secure your sshd with FIDO2.
The default setup runs a prune version of the bitcoin node
The optimal runtime environment for this service is a small server where you have the possibility to ssh into.
the makefile should be your friend:
$ make
Usage:
dump_env requires user to insert mandatory environment variables and dumps them to a `.env` file.
.env checks if .env file exists and if not invoke dump_env.
generate_bitcoind_conf generates the bitcoin.conf file from the bitcoin.template.conf. It will prompt for a password to be configured for your bitcoind rpc user.
up_local starts the compose environment where bitcoind is exposed locally to the node.
down_local tears down the docker compose environment.
up_vpn starts the compose environment exposing the bitcoind node through tailscaled (VPN).
down_vpn tears down the docker compose vpn environment.
up_tor starts the compose environment exposing the bitcoind node through tor hidden services.
down_tor tears down the docker compose tor environment.
up_all starts the compose environment exposing the bitcoind node locally, through VPN, and through tor hidden services.
down_all tears down the docker compose all environment.
test_btc_rpc once the cluster is up, you can use this target to test RPC connectivity/authentication/authorization.
test_btc_rpc_over_tor once the cluster is up, you can use this target to test RPC connectivity/authentication/authorization.
recycle_svc recycle a service taking into account docker-compose.base.yaml configuration changes as well as service specific configuration changes (torrc, bitcoin.conf, etc).
restart_svc restarts a service. This will only refresh service-specific configurations (torrc, bitcoin.conf), and not docker-compose.base.yaml updates.
.env.host requires user to insert mandatory environment variables and dumps them to a `.env.host` file.
up_vpn_host starts VPN in the host system.
down_vpn_host tears down VPN in the host system.
rotate_btc_user_credentials rotates the credentials of the user configured to have access to bitcoind RPC APIs.
generate_service_spec generates the 'bitcoind.service' systemd specs replacing some environment parameters (project folder and user).
help prints this help message.
you would typically:
- Checkout the branch that contains the configuration you are most interested in out of (
prune
,full
,electrs
); - Modify your
bitcoin/bitcoin.template.conf
and run:
$ # This will prompt for some configurations and generate the bitcoind configuration file: `bitcoin/bitcoin.conf`
$ make generate_bitcoind_conf
- Start the servers by running:
$ # <remote_access_method> one of local, vpn, tor, all
$ make up_<remote_access_method>
NOTE:
vpn
andall
require you to have configured a tailscale account and will prompt for an emphemeral auth key during the first run
- If all goes well you can use
make generate_service_spec
to generate a systemd service spec - If you are satisfied with the systemd service specs you can create a linux systemd service
I have done some checks on the bitcoind docker image that I'm using, but that means that I inherently trust the image registry to run this image, this might not be your case. Don't trust, verify!
Start the compose environment: make up_local
.
You need to have ssh access to the node where your docker-compose local stack is running.
To access your node, you can ssh tunnel the port 8332 from
your local machine to the node (or VM) running the docker-compose environment, and then simply connect to the port
8332
.
$ ssh -L 8332:localhost:8332 <your_user_name>@<remote_host>
Test that your node is reachable by running the following command from your client machine (not within the prompt you used to create the tunnel).
$ curl --user <your_btc_user> --data-binary '{"jsonrpc":"1.0","id":"curltext","method":"getblockchaininfo","params":[]}' -H 'content-type:text/plain;' localhost:8332
or
$ make test_btc_rpc BTC_USER=<your_btc_user> BTC_RPC_SERVER_ADDR=127.0.0.1:8332
NOTE:
<your_btc_user>
is the bitcoind user configured to authenticate against your btc node;
Pros:
- fast access;
- can protect your access using hardware-level ssh authentication; Cons:
- If you are not in the same network as your node, you will have to port-forward your node to the public internet or enable VPN in your node running the docker-compose environment.
You can also Access your node through TOR network: make up_tor
Test that your node is reachable by running the following command:
curl --socks5-hostname <tor_proxy> --user <your_btc_user> --data-binary '{"jsonrpc":"1.0","id":"curltext","method":"getblockchaininfo","params":[]}' -H 'content-type:text/plain;' <your_hidden_service_onion_address>:8332
or
$ make test_btc_rpc_over_tor BTC_USER=<your_btc_user> BTC_RPC_SERVER_ONION_ADDR=<your_hidden_service_onion_address>:8332
NOTE:
<tor_proxy>
is typically127.0.0.1:9050
but you will have to know where it is running in your system; NOTE:<your_hidden_service_onion_address>
is the onion address of thebitcoind_hidden
service, which can be found undertor/bitcoin_hidden/hostname
;
PROS:
- No need to have access to a router to port-forward your node service;
- Accessible from anywhere as long as you have your onion address with you; CONS:
- Very slow;
Using vpn
mode (Tailscale)
You can also Access your node through VPN: make up_vpn
$ curl --user <your_btc_user> --data-binary '{"jsonrpc":"1.0","id":"curltext","method":"getblockchaininfo","params":[]}' -H 'content-type:text/plain;' tailscaled:8332
or
$ make test_btc_rpc BTC_USER=<your_btc_user> BTC_RPC_SERVER_ADDR=tailscaled:8332
PROS:
- No need to have access to a router to port-forward your node service;
- Accessible from anywhere as long as you are in one of the workstations that can access your VPN
- Fast access;
You can also start your service locally with make up_local
and separately start a VPN client in your
host with make up_vpn_host
. With this approach, you can ssh-tunnel into your node even when not within
the same network and use the same approach described in the local mode section
(for that, your host needs to be running sshd
, and you need admin privileges in the host).
PROS:
- No need to have access to a router to port-forward your node service;
- Accessible from anywhere as long as you are in one of the workstations that can access your VPN
- Fast access;
CONS:
- You need to have admin privileges on the host machine.
Linux mDNS for simplifying your local setup
When you only need to access your node from a client hosted in the same network, it is convenient
to start an mDNS
in your node. Checkout for example Avahi.
This allows you to refer to your host with a local DNS name without worrying about having a fixed IP
assigned to your node in your local network. As an alternative you could configure your home router to
assign a static IP to your node and edit your /etc/hosts
file in the client to configure your node with
an alias which is easier to remember than the local IP address.
You can than simplify your ssh client configuration for tunneling by including the following content into
your ~/.ssh/config
Host btcnode
HostName <your-configured-mDNS-or-static-IP>
User <your_user>
Port <your_server_sshd_port_usually_22>
IdentityFile <the_key_file_for_ssh_connection>
which allows you to login with simply:
ssh -L 8332:localhost:8332 btcnode
To access your node from the internet, you can configure port forwarding in your router
to forward your sshd port. This would allow you to ssh into your node and perform the tunneling technique
explained above using your public IP instead of your local mDNS
address or your local network address.
If you don't plan to access your node from workstations that do not belong to your VPN, I would suggest
you to use the VPN approach as it gives you remote access without the need of port-forwarding (which opens
a considerable attack vector).
Consider reading about best-practices whenever exposing your services to the internet.
If you configure properly your ssh daemon with a security key (e.g. Yubikey) your ssh authentication would be protected by a hardware-device.
In your server running the docker-compose spec, it's handy to alias the following for interacting with
the bitcoind
server running inside the docker-compose runtime:
alias bitcoin-cli='docker exec bitcoind bitcoin-cli
You can then check the status of your blockchain info:
$ bitcoin-cli getblockchaininfo
and if you have jq installed you can monitor your oldest block in a typical prune node:
$ bitcoin-cli getblockchaininfo | jq '.pruneheight'
and also configure some kind of alert if it approaches too much a block-height that you are not willing to prune:
$ echo $(( <<<here_goes_the_block_height_you_are_interested>>> - $(bitcoin-cli getblockchaininfo | jq '.pruneheight')))
For more bitcoin-cli
RPCs, refer to this.
bitcoin/
folder is mounted in thebitdoind
docker container, and it's where the blockchain is downloaded;tailscale/btc/
folder will be used to persist VPN data from thetailscaled
service. This will allow your container to maintain the same node identity in thetailscale
VPN;tailscale/host/
serves the same purpose as the one above but for thehost-vpn
service which is dettached from the main docker-compose environment;tor/bitcoin_hidden/
will contain information about hidden-service exposed by tor - you can find your onion address under this folder in a file calledhostname
.
If you want to consult some websites from your workstation hosted in the same network as the node above
you can leverage the tor proxy to mask your public IP address (at the price of having
a less performant browsing experience). Check the documentation of your browser for how to configure a SOCKS
proxy. The address of your proxy will be <your-node-ip>:9050
.
A legit reason/situation for doing that is when you want to check in mem.pool for a block that might contain a transaction that involves one of your wallets. You can consume the public service in a convenient way without having to disclose your IP.
You can also use it in conjunction with curl
:
$ curl --socks5-hostname <tor_proxy> ...
Since bitcoind
needs to explicit authorize traffic incoming from within the docker-compose environment
container, we need to keep consistency between the IP submask of the network container (defined in docker-compose.base.yaml
)
and the one configured in bitcoind.conf
.
You can query your system which submasks are already in use and pick one that does not exist:
$ docker network inspect $(docker network ls -q) | jq '.[].IPAM.Config[].Subnet'
"172.17.0.0/16" │
"172.31.0.0/24" │
"172.32.0.0/24"
For the response above you can pick 172.33.0.0/24
and replace the content of docker-compose.base.yaml
and of the
bitcoind.conf
.
- host your hidden service with onion addresses
- TOR controller commands
- Running TOR proxy in docker
- simple way of running tor in docker, initial step for me to configure my solution.
- Bitcoin core - running bitcoind and tor in Ubuntu VM.
- good details about how to configure systemd
- Tor authentication and commands over telnet
- bitcoin.conf generation tool
- ssh tunneling
- bitcoind RPC API Reference
- bitcoind API list
- enable debug log level in bitcoind
- Bitcoind configurations
- TOR arguments
- Electrum servers comparison
- systemctl useful commands