This is a copy of the article we published freely available on Github & LN+.
If this is helping you, we appreciate a small gift via LNURL in the footer below - it’s 50:50 shared between Osito and myself.
We’ve also added Y’all links in case this is more for you
- Y’all Standard Guide (LN Pay wall)
- Y’all Advanced Guide + VPN (LN Pay wall)
Now, let’s get into it
Prelude and Objective
The lightning network functions in rapid growing speed as infrastructure for payments across the globe between merchants, creators, consumers, institutions and investors alike. Hence the key pillars of sustained growth are their nodes, by providing reliable, liquid, discoverable and trustless connection points between those parties.
While a growing number of nodes come online every day, a significant share of those are using Tor, which allows them to remain anonymous in a sense that they don’t need to reveal their real IP address (aka Clearnet IP). However, this methodology paired with the increased demand for Bitcoin payments will continue to stretch Tor’s capacity to cater for continued need of supply. It also hampers existing and new node’s metric of success being a reliable and fast peering partner.
To mitigate some of ongoing Tor capacity constraints, a node runner may choose to reconsider (see Chapter Caution: Clearnet! offering both, a Tor as well as a Clearnet IP connection option. Next to the drawbacks outlined in the first section below, it has three main net benefits
- allows for alternative discovery, routing and peering in case your own Tor cluster is affected by capacity constraints. Even though mostly temporarily, it cuts into your reliability
- provides quicker routing of HTLCs, both for payment and probing. Quite nervous waiting 8 seconds for your transfer confirmation at the supermarket or bar, isn’t it?
- offers other clearnet-only nodes to connect directly to you. Otherwise it would be required for you as Tor-only to peer-connect to them first, before they can open a channel
With those considerations in mind, have a careful read through the words of caution below, make an educated decision by yourself, and then use our guide below on how to enable a hybrid Tor & Clearnet Node.
Table of Content
- Prelude and Objective
- Caution clearnet!
- Preconditions
- Configuring hybrid-mode
- Static IP
- Dynamic IP: Solution 1 - NAT/UPnP
- Dynamic IP: Solution 2 - Dynamic DNS (DDNS)
- Wrap-Up
- Bonus Special Case: Clearnet through VPN
Caution: Clearnet!
A word of caution: Running a node behind the Tor network offers many advantages (anonymity, security and usability) and therefore it is currently the most recommended way. For nodes maintaining a high number of connected channels and/or have high availability requirements, Tor can be a hindrance. Tor’s organic network is prone to censorship of a country’s law regulation and internal failures of circuits and relays. LND also allows running clearnet nodes that do not make use of the Tor network but directly connect to peers. This requires node administrators to take care of the underlying system’s security policies. At least one port (default: 9735) needs to be forwarded and exposed for remote peers to connect to. Setting up a firewall is highly recommended. Not only security is a topic to be thought about, also the risk of being localized by clearnet IP. Only use hybrid-mode if privacy is not of concern!
Preconditions:
For this guide the following is required:
- You are tech-savvy and know what you do
- A fully installed and synchronized node (Umbrel / custom)
- For RaspiBlitz these features will be implemented and available in Release v1.8.
lnd-0.14.1-beta
or latertor.streamisolation=false
must be turned off when using hybrid-mode
Hybrid-mode was brought to life in LND by Lightning Labs in version lnd-0.14.0-beta
. A new option was introduced to split connectivity and to separately address Tor-only peers via Tor and clearnet peers via clearnet:
[tor]
; Allow the node to connect to non-onion services directly via clearnet. This
; allows the node operator to use direct connections to peers not running behind
; Tor, thus allowing lower latency and better connection stability.
; WARNING: This option will reveal the source IP address of the node, and should
; be used only if privacy is not a concern.
tor.skip-proxy-for-clearnet-targets=true
Configuring hybrid-mode:
Advertising clearnet connectivity LND needs to know the external IP of a node. There are two different cases to investigate: static and dynamic IP connections.
A static IP is rather easy to set in LND. An obvious pre-requisite is, your ISP provides an IPv4, alternatively an IPv6 address to your connection. This external IP address has to be applied to LND’s option externalip
. That’s almost it. But most internet providers change IPs on a regular basis or at least on reconnection. Therefore externalip
in lnd.conf
would have to be changed accordingly each time a new IP was assigned, followed by a restart of lnd.service
to reload lnd.conf
. This is unsustainable for continuous node running. Two possible solutions to prevent re-editing and restarting LND:
- Solution 1: NAT/UPnP
- Solution 2: Dynamic DNS (DDNS)
Static IP:
Static IPs are rarely provided for home use internet connections. It is a feature mostly offered to cable or business connections. Having a static IP makes configuring of lnd.conf
much easier. In this case option externalip
needs a closer look.
; Adding an external IP will advertise your node to the network. This signals
; that your node is available to accept incoming channels. If you don't wish to
; advertise your node, this value doesn't need to be set. Unless specified
; (with host:port notation), the default port (9735) will be added to the
; address.
; externalip=
Dynamic IP: Solution 1 - NAT/UPnP:
Dealing with dynamic IPs tends to be a bit more complex. LND provides an integrated approach to this: NAT. NAT tries to resolve dynamic IPs utilising built-in techniques in order to fetch a node’s external IP address. Notable that LND doesn’t handle the setting of externalip
and nat
at the same time well. Choose only one of them, based on your router’s UPnP capabilities (nat traversal).
; Instead of explicitly stating your external IP address, you can also enable
; UPnP or NAT-PMP support on the daemon. Both techniques will be tried and
; require proper hardware support. In order to detect this hardware support,
; `lnd` uses a dependency that retrieves the router's gateway address by using
; different built-in binaries in each platform. Therefore, it is possible that
; we are unable to detect the hardware and `lnd` will exit with an error
; indicating this. This option will automatically retrieve your external IP
; address, even after it has changed in the case of dynamic IPs, and advertise
; it to the network using the ports the daemon is listening on. This does not
; support devices behind multiple NATs.
; nat=true
Dynamic IP: Solution 2 - Dynamic DNS (DDNS):
Dynamic DNS (DDNS) is a method of automatically updating a name server in the Domain Name System (DNS), often in real time, with the active DDNS configuration of its configured hostnames, addresses or other information. (src)
A script or an app regularly fetches the client’s current IP address which is saved for later requests. LND is able to resolve a given domain / DDNS to the actual IP address as well. Log output of HostAnnouncer
listed below:
[DBG] NANN: HostAnnouncer checking for any IP changes...
[DBG] NANN: No IP changes detected for hosts: [ln.example.com]
...
[DBG] NANN: HostAnnouncer checking for any IP changes...
[DBG] NANN: IP change detected! ln.example.com:9735: 111.11.11.11:9735 -> 222.22.22.22:9735
In this case lnd.conf
needs to know a reserved DNS domain instead of an external IP. Option externalhosts
has to be set:
[Application Options]
# specify DDNS domain (port optional)
externalhosts=ln.example.com:9735
Lightning explorers like 1ml.com and amboss.space show and use IP addresses only. The node itself also only makes use of the resolved IP addresses (see lncli getinfo
). Domains can be some fancy giveaway for peering invitations on chat groups or printed on business cards … who knows what it might be good for in the future.
Wrap-Up:
Summing up the introduced LND options in this article, here are some examples of complete configurations:
Static IP:
[Application Options]
# specify an external IP address e.g. 222.22.22.22:9735 / [2002::de16:1616]:9736
externalip=222.22.22.22:9735
# externalip=[2002::de16:1616]:9736
# specify an interface (IPv4/IPv6) and port (default 9735) to listen on
# listen on IPv4 interface or listen=[::1]:9736 on IPv6 interface
listen=0.0.0.0:9735
# listen=[::1]:9736
[tor]
tor.active=true
tor.v3=true
# deactivate streamisolation for hybrid-mode
tor.streamisolation=false
# activate split connectivity
tor.skip-proxy-for-clearnet-targets=true
Dynamic IP - NAT:
[Application Options]
# specify an interface (IPv4/IPv6) and port (default 9735) to listen on
# listen on IPv4 interface or listen=[::1]:9736 on IPv6 interface
listen=0.0.0.0:9735
# listen=[::1]:9736
nat=true
[tor]
tor.active=true
tor.v3=true
# deactivate streamisolation for hybrid-mode
tor.streamisolation=false
# activate split connectivity
tor.skip-proxy-for-clearnet-targets=true
Dynamic IP - DDNS:
[Application Options]
# specify an interface (IPv4/IPv6) and port (default 9735) to listen on
# listen on IPv4 interface or listen=[::1]:9736 on IPv6 interface
listen=0.0.0.0:9735
# listen=[::1]:9736
externalhosts=ln.example.com:9735
[tor]
tor.active=true
tor.v3=true
# deactivate streamisolation for hybrid-mode
tor.streamisolation=false
# activate split connectivity
tor.skip-proxy-for-clearnet-targets=true
After restarting LND, it is now offering two (or three with IPv6) addresses (URIs). These can be verified by typing lncli getinfo
:
"uris": [
"<pubkey>@<onion-address>.onion:9735",
"<pubkey>@222.22.22.22:9735",
"<pubkey>@[2002::de16:1616]:9736"
],
Special Case: VPN Setup
Clearnet over VPN
To prevent exposure of a node’s real IP address connecting through VPN is an approach if anonymity is crucial. To achieve this, some preconditions must be checked and met:
- VPN server or provider is able to forward ports.
- VPN setup is able to split-tunnel processes (killswitch).
- Home setup is able to forward specific ports (router/modem).
- Home setup is able to allow incoming traffic (firewall).
Check? Let’s go!
- Declarations
internal_port = Internal LND listening port (for easy setup: internal_port = port-forwarded-VPN_port, but does not necessarily have to be)
port_forwarded_VPN_port = VPN assigned forwarding port
static_VPN_IP = IP of your VPN service/provider
ddns_domain = DDNS (DNS domain) for IP resolution
- Firewall: allowing incoming port
sudo ufw allow <internal_port> comment 'lnd-vpn-port'
sudo ufw reload
- Router/Modem: forwarding / mapping internal port to VPN assigned port (check first if it is necessary)
This step is managed very individually due to high amount of routers and modems out there. Usually GUI-based webinterfaces let define ports to be forwarded to specific devices within a local network.
- LND: configuring
lnd.conf
for VPN setup:
- If VPN provides a static IP:
...
[Application Options]
externalip=<static_VPN_IP>[:<port_forwarded_VPN_port>]
# listen on IPv4 interface
listen=0.0.0.0:<internal_port>
# listen on IPv6 interface, if used
# listen=[::1]:<internal_port2>
[tor]
tor.streamisolation=false
tor.skip-proxy-for-clearnet-targets=true
...
- If VPN provides dynamic IPs and a DDNS was claimed:
...
[Application Options]
externalhosts=<ddns_domain>[:<port_forwarded_VPN_port>]
# listen on IPv4 interface
listen=0.0.0.0:<internal_port>
# listen on IPv6 interface, if used
#listen=[::1]:<internal_port2>
[tor]
tor.streamisolation=false
tor.skip-proxy-for-clearnet-targets=true
...
Note: Internal port and assigned VPN port are not necessarily the same. A router/modem may be configured to map any internal to any external port.
- VPN: Configure VPN connection and check port reachability
Set up a VPN connection with whatever your VPN provider recommends (individual step). Check if the opened port is reachable from the outside by running nc
(on Linux) and ping from the internet e.g. with dnstools.ch.
1. run: nc -l -p 9999 (9999 is port_forwarded_VPN_port)
2. ping port 9999 from the internet
- Killswitch (depends on VPN client): Exclude Tor process from VPN traffic by VPN client or UFW
Most VPNs route all traffic through their network to protect against data leakage. In this case Tor traffic should be excluded from the VPN network because it is anonymized per se plus we want to add redundancy of connectivity and make use of lower clearnet responding times for faster htlc processing. Killswitch can be applied using UFW as well. To do so, please follow this guide.If your VPN client supports command line input, excluding the Tor process could be handled like this:
pgrep -x tor // returns pid of tor process
<vpn cli split-tunnel command> pid add $(pgrep -x tor) // optional step: if VPN provider supports CLI this step can be automated in a script, e.g. after Tor or node restart
- Restart LND and watch logs for errors (adjust to your setup)
tail -f ~/.lnd/logs/bitcoin/mainnet/lnd.log
- Lookup node addresses:
If everything is set, two URI addresses will be displayed.
$ lncli getinfo
"uris": [
"<pubkey>@<onion-address>.onion:9735",
"<pubkey>@222.22.22.22:9999"
],
Alternatively check listening ports with netstat
:
netstat -tulpen | grep lnd
Result:
tcp6 0 0 :::9999 :::* LISTEN 1000 11111111 1111111/lnd
- Check connectivity with clearnet peers
To test clearnet connectivity find and ask other clearnet peers to connect to your node, e.g.: lncli connect <pubkey>@222.22.22.22:9999
Successful connection:
lncli connect <pubkey>@222.22.22.22:9999
{
}
Written by osito, Co-Authored & Reviewed by Hakuna.
If this guide was of help and you want to share some and contribution, please feel free to send a tip to our addresses: 0x382f9cf667447bb8@ln.tips (osito) | hakuna@btcadresse.de (Hakuna / HODLmeTight) or send some sats via LNURL
Also we are always grateful for incoming channels to our nodes: osito: HodL⚡NodL & Hakuna: HODLmeTight