7 min read

Tor-Only Bitcoin & Lightning Guide

A detailed guide to improving your privacy as a Lightning Network user.
Tor-Only Bitcoin & Lightning Guide

When the average person hears the term "cryptocurrency," they may assume that every aspect of the protocol is encrypted and thus completely private, allowing users to safely remain anonymous. This is most certainly not the case, and privacy-conscious users will need to take additional steps to protect themselves. One particular threat vector that Bitcoin and Lightning users should consider is that of the network observer. By sending data in the clear via default IPV4 and IPV6 networks, sophisticated entities can look for patterns to correlate your financial activity and they can use the IP address of your machine to probe it for weaknesses and attempt to learn your location and identity.

How are we to protect ourselves?

  1. By sharing as little data with third parties as possible.
  2. By ensuring that all of the data our nodes send and receive is routed over a privacy preserving network.

Full nodes offer the best privacy model when it comes to preventing data leaks. With a full node, you download all the blockchain data and only query for addresses / transactions locally — network observers can’t see what you’re interested in.

But if we run our own nodes, we still have to share data (such as for sending transactions) with peers on the network - how do we protect ourselves from them? Enter Tor. Tor Project maintainers say that you can think of what Tor does as "using a twisty, hard-to-follow route in order to throw off somebody who is tailing you — and then periodically erasing your footprints." Your traffic gets intermingled with the traffic of other Tor users. As the global Tor userbase grows, the path gets twistier.

In order for you to make networked services (anything from a web server to a peer to peer node) work on Tor, you need to create a hidden service that acts as a bridge from the Tor network to the specific software running on your machine.

NOTE: after running a tor-only Lightning node for a year, I have come to believe that doing so results in significantly decreased routing performance and available inbound liquidity. Be aware that if your goal is to be a highly trafficked routing node, going tor-only makes it far more challenging.

Bitcoin Core

As of Bitcoin Core 0.12, a node will automatically run a hidden service if it is able to connect to a local Tor daemon. However, we have to make sure that a few things are configured correctly so that the node and daemon can talk to each other. As such, back in 2016 I first looked into how to get my Bitcoin nodes operating on the Tor network and I wrote this guide:

How to Run Bitcoin as a Tor Hidden Service on Ubuntu
Why should you run a Bitcoin hidden service on your node?* It increases the privacy of other Bitcoin users who are anonymizing their…

The above guide will get you most of the way there, though additional configuration needs to be made in order to disable communication via IPV4 and IPV6. When you set up Bitcoin Core to power a Lightning node you'll want to have the following lines in your bitcoin.conf file:

# [core]
# Maintain a full transaction index (improves lnd performance)
txindex=1
daemon=1
disablewallet=1
maxuploadtarget=1000

# [rpc]
# Accept command line and JSON-RPC commands.
server=1
rpcauth=[redacted]:[redacted]

# [zeromq]
# Enable publishing of transactions to [address]
zmqpubrawtx=tcp://127.0.0.1:28333
# Enable publishing of raw block hex to [address].
zmqpubrawblock=tcp://127.0.0.1:28332

# Privacy
bind=127.0.0.1:8333
# Allow DNS lookups for -addnode, -seednode and -connect values.
dns=0
# Query for peer addresses via DNS lookup, if low on addresses.
dnsseed=0
# Specify your own public IP address.
externalip=[redacted].onion
# Use separate SOCKS5 proxy to reach peers via Tor
onion=127.0.0.1:9050
proxy=127.0.0.1:9050
proxyrandomize=1
# Only connect to peers via Tor.
onlynet=onion
listenonion=1
listen=0
# helps bootstrap peers for initial sync
addnode=6u2hzskqwebn4ldjhobi73kch5us4cc6cssm7pnatnyumvci7btdmhqd.onion
addnode=jnuehir3ownmhnrceltatxz6vvznwgw5hlz3dgk6kjlrop5rq7tykeqd.onion
addnode=6nwabl7vks2jieb74akgjmariirzchzeionxdwthsgjsenbfr3qgqzad.onion
addnode=2hz64d5zd7f3vznpbnfpicbzsotp5bjr742qeyqkcgghxah4dck543qd.onion
addnode=fpmxqxvjhexojvyeqrr7oles6r6bztt2e2i5ltwtdorpwqw2zoeqi2qd.onion
addnode=e5l6pazznjdfozuen3763bkde4njorniffxq7xg35znm3344oitjwfad.onion
addnode=m4gtrhkde7abevhmt2cbdxw5eqcqnpoekjseaunq45p6ithquonl54qd.onion
addnode=mrlyeqavp5ufbsnk37tr6pmbnlr74e4v3xtlx4elmhrb3hfrfpuiz4yd.onion
addnode=t2ui2nl7hm63qqmwot5rwzegh42mhuzpmodxmxzb6dc7ckovkyiejiad.onion
addnode=52cawcafaswleiedcprfs4y7bp3vn4qaknjl3j64bcjunixryjxpozyd.onion
addnode=567ckf7gxoxoun5ympwwphcvzxtc2usqlvu2zggi3b5neznub77gwaid.onion
addnode=uwxxxv3alapmwijos7vtgv7ueuoffyu6ev62ttbpt5cvtkq7p56725ad.onion

Note that the two lines with [redacted] info need to be set dynamically by you.

rpcauth=[redacted]:[redacted]

The rpcauth value should be set by running this python script.

externalip=[redacted].onion

You can find your Bitcoin hidden service address that you should set as the externalip by running this command while your node is running: bitcoin-cli getnetworkinfo | grep \"address

Now you'll just have to wait for bitcoind to finish syncing. This will take at least a few days, depending upon a variety of factors.

LND

LND is similarly smart like Bitcoin Core in that it can talk to the Tor daemon; you just need to tell it to do so. I suggest the following lnd.conf parameters:

[Application Options]
minchansize=100000
listen=localhost
accept-keysend=1
allow-circular-route=1
watchtower.active=1

# Mark unpayable, unpaid invoices as deleted
gc-canceled-invoices-on-startup=1
gc-canceled-invoices-on-the-fly=1

# Avoid historical graph data sync
ignore-historical-gossip-filters=1

# gRPC socket binding
rpclisten=0.0.0.0:10009
restlisten=0.0.0.0:8080

# Avoid slow startup time
sync-freelist=1

# Avoid high startup overhead
stagger-initial-reconnect=1

# Auto regenerate RPC TLS certificate
tlsautorefresh=1

# Do not include IPs in the RPC TLS certificate
tlsdisableautofill=1

[Bitcoin]
bitcoin.active=true
bitcoin.mainnet=true
bitcoin.node=bitcoind
bitcoin.minhtlc=1000
bitcoin.basefee=1000
bitcoin.feerate=100

[Bitcoind]
bitcoind.rpcuser=[redacted]
bitcoind.rpcpass=[redacted]
bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332
bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333
bitcoind.estimatemode=ECONOMICAL

[routerrpc]
# Set default chance of a hop success
routerrpc.apriorihopprob=0.5

# Start to ignore nodes if they return many failures
routerrpc.aprioriweight=0.75

# Set minimum desired savings of trying a cheaper path
routerrpc.attemptcost=10
routerrpc.attemptcostppm=10

# Set the number of historical routing records
routerrpc.maxmchistory=10000

# Set the min confidence in a path worth trying
routerrpc.minrtprob=0.005

# Set the time to forget past routing failures
routerrpc.penaltyhalflife=6h0m0s

[tor]
tor.active=true
tor.v3=true
tor.streamisolation=true

Note that bitcoind.rpcuser and bitcoind.rpcpass should be the values that you fed into the rpcauth python script when configuring Bitcoin Core, not the output value of the script.

LND has a ton of config options; you may wish to browse the sample lnd.conf here. Alex Bosworth also has some fairly in-depth recommendations for configuring your machine.

Be sure to set automatic off-site channel backups for disaster recovery! Believe me, you'll want to avoid having to perform a wallet recovery on corrupted data. I've written extensively about some of the edge cases I've run into.

Lightning Wallet Recovery: Lessons Learned
Recovering funds from a crashed Lightning Network node can be technically challenging - here’s what we have learned from performing quite a few recoveries.

Here's a simple utility script that you can tweak to send channel backups to another machine via any bash command you can conjure up (such as scp.) Alternatively you can use this script that I found and modified to automatically back up your channels to Dropbox.

Mobile Node Control via Zeus

Getting your nodes set up is great, but what if you want to actually use them to make a payment when you're out on the town and not lugging a laptop around?

At time of writing it appears that Zeus is the only mobile app available on both iOS and Android that supports talking directly to remote LND, Eclair, and c-lightning nodes.

While it's possible for Zeus to talk to your node via IPV6, we might as well stick to Tor! You'll first want to create a separate Tor hidden service for lnd's REST interface.

sudo vim /etc/tor/torrc

Add these two lines:

HiddenServiceDir /var/lib/tor/lnd_rest/
HiddenServicePort 8080 127.0.0.1:8080

Restart tor and find your new onion service hostname that you'll paste into Zeus.

sudo service tor restart
sudo cat /var/lib/tor/lnd_rest/hostname

Create a macaroon for authentication.

/path/to/lncli bakemacaroon address:read address:write info:read info:write invoices:read invoices:write message:read message:write offchain:read offchain:write onchain:read onchain:write peers:read peers:write signer:generate signer:read

This command will output a bunch of hex that you'll need to paste into Zeus. You'll also want to make sure you have the "use Tor" option checked in the Zeus config.

Now you should be all set!

But one more thing...

Liquidity Management

We are still in the early days of understanding best practices for managing Lightning Network liquidity; I expect that entire books will be written on the subject. You should learn the basics, however. I'd suggest joining some of the discussion forums to stay up to date on best practices.

There are several tools available to help manage liquidity across your channels.

Managing Liquidity on the Lightning Network
Learn about the concept of liquidity in the context of the Lightning network and how to best open, manage, balance and close your channels.

There are plenty of liquidity management functions in the Balance of Satoshis tool; if you read through the documentation you'll find some automation examples under the "Linux Fu" section.

Just remember: a balanced channel is a useful channel!