Bitcoin Node + Lightning Network + Tor

Okay, so this is the post that kickstarted me to return to StackAttack… because I’ll probably forget all of this in a week, and I want a reference. In short, the goal is:

  • Setup a full Bitcoin core node
  • Setup the Lightning Network Daemon
  • Make it all work over Tor

Let’s dive in, shall we? 🙂

Disclaimer: None of the sensitive data in this write-up is actually from my system. Usernames, passwords, etc have all been modified. 🙂

Setting Up Ubuntu

First up, I’m building this on an Ubuntu Server 20.04 LTS system. That setup is nothing fancy, so if you need a reference for that install just check out the Ubuntu guide to installing it. You will need a system with at least 8 GB of RAM, and ideally about 1 TB of storage, but neither of those are high bars to meet at this point. Do the usual, but once you’ve finished the install there are a few more things you need to do. First up, I updated everything:

user@system:~$ sudo apt update
user@system:~$ sudo apt -y upgrade
user@system:~$ sudo apt -y auto-remove

Next we need to install a few extra packages. In no particular order we need the following:

  • golang
    • Used to install LND
  • git
    • Used to pull down LND from the repository
  • build-essential
    • Used to build LND
  • git-core
    • Used to build LND
  • tor
    • Used to anonymize traffic with Tor
  • libzmq3-dev
    • Used to support ZeroMQ RPC calls from Bitcoin daemon
  • jq
    • Used to support LND

So we use all of that in one whiz-bang command:

user@system:~$ sudo apt install git git-core tor build-essential libzmq3-dev jq golang

Then it’s time to start actually configuring everything. First up, let’s create a dedicated user for all of the things we’re going to run.

user@system:~$ sudo useradd -c /bin/bash -m BlockChainy
user@system:~$ sudo passwd BlockChainy
# The next part is to ensure that LND can eventually read the Ubuntu-specific cookie:
user@system:~$ sudo usermod -a -G debian-tor BlockChainy

And before we go too far, if you went with the default install options you may notice that your drive is only 200 GB, which won’t do for a 300+ GB sync that’s coming up. Assuming the default LVM approach you probably want to do this to resize to the maximum available size (use up all the free space that was reserved by the installer):

user@system:~$ sudo lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv

Setting Up Tor

Next let’s get Tor running. We need to setup how it’s going to function, which is done in the /etc/tor/torrc file.

# Add the following to the end of the default /etc/tor/torrc file
# (which should be fully commented out from the Ubuntu distribution)
#### Custom Additions for LND ####
SOCKSPort 9050
Log notice stdout
ControlPort 9051
CookieAuthentication 1

Then we need to set Tor to run at startup automatically, so a quick couple of steps there:

user@system:~$ sudo systemctl enable tor.service
user@system:~$ sudo systemctl start tor.service

And a quick check to see if it’s working (lifted from this article):

user@system:~$: curl --socks5 localhost:9050 --socks5-hostname localhost:9050 -s https://check.torproject.org/ | cat | grep -m 1 Congratulations | xargs

You should see the following: “Congratulations. This browser is configured to use Tor.” On to Bitcoin setup!

Setting Up Bitcoin Core

To start, we need to pull down the installer from the official Bitcoin Core image (this link is to the most recent as of the date of this posting), then verify the hash (against the official hashes) and extract it.

user@system:~$ curl https://bitcoin.org/bin/bitcoin-core-0.21.0/bitcoin-0.21.0-x86_64-linux-gnu.tar.gz --output bitcoin-0.21.0-x86_64-linux-gnu.tar.gz

user@system:~$ curl https://bitcoin.org/bin/bitcoin-core-0.21.0/SHA256SUMS.asc --output SHA256SUMS.asc

user@system:~$ sha256sum -c SHA256SUMS.asc

user@system:~$ tar -xvzf bitcoin-0.21.0-x86_64-linux-gnu.tar.gz

Fortunately this installation is a simple one. We’re using the install command to clone the binaries to /usr/local/bin with owner/group of root and standard permissions (rwxr-xr-x) on the files. This will place the binaries into the common path of all users.

user@system:~$ sudo install -m 0755 -o root -g root -t /usr/local/bin bitcoin-0.21.0/bin/*

Okay, time to configure our system to pull down and act as a node. Because we want to keep all of this contained to that single user, we need to become that user first:

user@system:~$ su - BlockChainy

First up, just run the Bitcoin daemon to create the default locations and files. Once that’s done (just give it about 15 seconds) kill it with CTRL+C and create the bitcoin.conf file to handle configuration going forward.

BlockChainy@system:~$ bitcoind
# Was about 15 seconds, then CTRL+C

#### Edit ~/.bitcoin/bitcoin.conf to use below   ####
#### This file may not exist.  If not, create it ####
listen=1
port=8333
server=1
zmqpubrawblock=tcp://127.0.0.1:28332
zmqpubrawtx=tcp://127.0.0.1:28333
rpcuser=SuperSecretRPCName
rpcpassword=SuperSecretRPCPassword
rpcport=8332
prune=0
[main]
[test]
[signet]
[regtest]

For all of those options…

  • listen tells the server to accept incoming communications
  • port tells the server what port to listen on
  • server tells the server to start a server
  • zmqpubrawblock specifies how to publish block hashes (this will be used by LND)
  • zmqpubrawtx specifies how to publish transaction hashes (this will be used by LND)
  • rpcuser is the username that RPC calls can authenticate with
  • rpcpassword is the password that RPC calls can authenticate with
  • rpcport is the port that RPC calls will use
  • prune specifies not to prune the database (e.g. maintain the full block set)
  • The remainder are chain-specific overrides (none here)

Start up the client again as a daemon, then check to see if you are (1) connecting to systems and (2) beginning to synchronize.

BlockChainy@system:~$ bitcoind -daemon
Bitcoin Core starting

BlockChainy@system:~$ bitcoin-cli getconnectioncount
8

BlockChainy@system:~$ bitcoin-cli getblockchaininfo

#### If you want to easily monitor the sync you can just use the following script ####
BlockChainy@system:~$ cat btc-sync-mon.sh
#!/bin/bash
echo "Current Stats"
echo "-------------"
bitcoin-cli getblockchaininfo | grep -e 'headers' -e 'blocks' -e 'verification' | sed -e 's/\"//g' -e 's/\,//g' | cut -d " " -f 3,4
echo "Connections: " `bitcoin-cli getconnectioncount`

#### End Script ####

BlockChainy@system:~$ chmod +x btc-sync-mon.sh

BlockChainy@system:~$ watch --interval=1.0 btc-sync-mon.sh

#### You should see something like the following ####
Current Stats
-------------
blocks: 245128
headers: 683387
verificationprogress: 0.999997988042878
Connections:  10

Congratulations! If you’re seeing something like the above you are now synchronizing the 300+ GB blockchain of Bitcoin. The headers value is how many blocks your node is aware of. The blocks value is how many blocks your node has. The verification progress would in theory be 1.000000 when you’re complete, but you’ll never be complete… so if you’re seeing five nines or so you’re pretty much done with that. Background or kill that process while you wait, then move on to automating bitcoind being started.

Let’s set up Bitcoin to run on startup so we don’t have to do that every time. First up we need to create a .service file that specifies how to run it. To do so just create the below configuration (updating user information as appropriate):

root@system:~# cd /lib/systemd/system
root@system:/lib/systemd/system# cat bitcoind.service 
[Unit]
Description=Bitcoin Daemon
After=network-online.target

[Service]
User=BlockChainy
Group=BlockChainy
Type=simple
ExecStart=/usr/local/bin/bitcoind -daemon
Restart=always
RestartSec=15s
KillMode=process

[Install]
WantedBy=multi-user.target

Once that’s been created we need to test it and enable it… both of which are quick single commands:

root@system:~# systemctl start bitcoind.service
root@system:~# systemctl enable bitcoind.service

Once that’s all set just wait until the headers and blocks values match with five nines (e.g. 0.99999_____) on the verification progress before going on to the next step.

Setting Up LND

Now we need to download, configure, and install the Lightning Network Daemon (LND). Just like with Bitcoin we’ll run the agent for a few seconds to let it setup the default directories, then configure a file to make that easier going forward. Remember those values that were setup for the Bitcoin configuration… you’ll need them for this file as well. Let’s get to it.

BlockChainy@system:~$ go get -d github.com/lightningnetwork/lnd

BlockChainy@system:~$ ~/go/bin/lnd
# Wait about 15 seconds, then CTRL+C

#### Again, the file ~/.lnd/lnd.conf may or may not exist at this point ####
#### If it doesn't, just create it. :) ####

BlockChainy@system:~$ cat ~/.lnd/lnd.conf
alias=SOME_SUPER_AWESOME_NAME
logdir=/var/log/lnd
maxlogfiles=5
maxlogfilesize=10
bitcoin.active=true
bitcoin.mainnet=true
debuglevel=debug
bitcoin.node=bitcoind
bitcoind.rpcuser=SuperSecretRPCName
bitcoind.rpcpass=SuperSecretRPCPassword
bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332
bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333
tor.active=true
tor.v3=true
tor.streamisolation=true
listen=localhost
accept-keysend=true
restlisten=0.0.0.0:80

# Due to this opening ports you need to run it as a privileged user, so...
# Drop back to your regular user (because you didn't setup this account with privileged access, RIGHT?)
BlockChainy@system:~$ exit
user@system:~$ sudo install -m 4775 -o root -g root -t /usr/local/bin go/bin/*
user@system:~$ su - BlockChainy

# You also need to create the folder that will be used to write the log files:
user@system:~$ sudo mkdir /var/log/lnd

BlockChainy@system:~$ lnd &

You’ll see a bunch of scrolling until a message appears about waiting for a wallet to be unlocked. We don’t have one yet, so let’s create one. Pressing ENTER will bring up a clean prompt again (thanks to that ampersand we ran with), and it’s time to create and unlock the wallet.

BlockChainy@system:~$ lncli create
# Follow the prompts
# Remember your password selections
# Write down your backups
# Print your backups
# Put encrypted copies of your backups in other backups you backup
# DON'T LOSE YOUR BACKUPS

# We still need to unlock the wallet, however, for the LND to see it:
BlockChainy@system:~$ lncli unlock
# Put in your password
# You should see the LND process start receiving data at a pretty decent rate, and quickly

At this point we probably want to make sure that lnd runs automatically all the time and can open the wallet itself. First kill lnd with CTRL+C, then we have to add one more line to the configuration file… add the following to the very end of the file:

BlockChainy@system:~$ cat ~/.lnd/lnd.conf
# ... all the stuff from above ...
restlisten=0.0.0.0:80
# Add the line below for automatic unlocks of the associated wallet
wallet-unlock-password-file=/home/BlockChainy/.sosecret


# To keep things safe(r), create that file and set the permissions appropriately
BlockChainy@system:~$ touch ~/.sosecret
BlockChainy@system:~$ echo "YourSuperSecretLNDWalletPassword" > ~/.sosecret
BlockChainy@system:~$ chmod 400 ~/.sosecret

Following that we can test just by running lnd and you should see a status message indicating that the wallet was successfully opened, followed by the return of lots of scrolling updates. Assuming that worked it’s time to get this starting automatically like we did with bitcoin.

root@system:~# cd /lib/systemd/system
root@system:/lib/systemd/system# cat lightning-network.service 
[Unit]
Description=Lightning Network Daemon
After=network-online.target

[Service]
User=BlockChainy
Group=BlockChainy
Type=simple
ExecStart=/usr/local/bin/lnd
Restart=always
RestartSec=15s
KillMode=process

[Install]
WantedBy=multi-user.target

Okay, close to done. Let’s make sure that we’re properly using Tor for all these communications. As lifted from this article we can quickly identify our own node and check the public address to confirm this.

BlockChainy@system:~$ lncli getinfo | grep identity_pubkey
# Copy the value of this...

BlockChainy@system:~$ lncli getnodeinfo VALUE_YOU_COPIED
# You should see something like this:
...
"addresses": [
    {
       "network": "tcp",
       "addr": "wholebunchoflettersandnumbers.onion:9735"
    }
],
...

The “.onion” part is the important one. Assuming you see that, you’re up and running on Tor.

Update 2021-03-25: Added update on automatic start for bitcoind and lnd and fixed install method for lnd.

At this point you have a fully-synchronized Bitcoin node running LND over Tor. Good hunting!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Website Powered by WordPress.com.

Up ↑

%d bloggers like this: