Turn your self hosted Lightning Network node to public in 10 minutes

If you run personal self hosted Lightning Network node at home – probably it is a private node. Your node can open channels to other (public) nodes, but other nodes cannot open channel to your node, because the node is not advertised in the LN network as a public node. Why? There are many factors why your node is not public but some main are:

  • Your self hosted LN node is not configured to be public. Is it a big problem? NO – LN node configuration to be public can be easily changed, so it’s not a problem (it can use Tor however it is not a scope of this article, what we mean here by public is to advertise with standard IPV4 IP)
  • Your network configuration is not properly configured. Is it a big problem? NO – your router is probably not forwarding ports for LN node (9735) or firewall blocks traffic but most likely it can be configured.
  • You don’t have static IP. Is it a big problem? YES – if you have dynamic IP (most likely answer is yes) you won’t be able to easily make your node public.

In this article I will explain how can you setup self hosted Lightning Network (at home or anywhere) to get public (not changing) IP for 5$/month what will make your node public – other nodes will be able to open channels to your node. This is not TOR based solution. This is not DDNS based solution.

Our LN node is built on Raspiblitz (https://github.com/rootzoll/raspiblitz) and this article will show steps to turn your self hosted Raspiblitz node public. What is Raspiblitz? It’s open source project which allow to build own, self hosted Bitcoin full node + Lightning Network Node + many fancy Bitcoin tools on Raspberry PI 4. I recommend these tools since it’s solid and good work (and you have cool LCD display on your Raspberry PI), however you can use any other self hosted LN node setup (e.g. Umbrel or even bare LND simply setup by yourself). Since our node implementation is LND (on Raspiblitz) – the configuration will be for LND – but the general public node solution concept can be applied to other LN node implementations (you will have to just tweak node settings in different way).

How it works?

Your node will get a public IP address of cloud provider – in our case Digital Ocean which offers the smallest droplets (vps) for 5$/month. The droplet will run OpenVPN server. Your personal, home hosted Lightning Network node will connect to the OpenVPN server. With proper configuration this setup will allow to route LN node traffic through the VPN connection between your node and droplet, what will allow to advertise your LN node with public IP.

The best part of this VPN based solution is that your personal (home) IP will not be advertised to the network and will become private.

The diagram presents the high level solution overview.

Overview of public Lightning Network node setup exposed to the network via static IP (by Digital Ocean droplet) based on OpenVPN connection.

The tutorial is based on this Reddit thread (good job) – it’s just step-by-step explanation, little bit simpler because of Docker based OpenVPN setup.

Step 1: Setup VPS with static IP

You can use any VPS/Cloud provider you want. I use Digital Ocean for most of my projects. They offer 1GB RAM,  1CPU, 25 GB SSD, 1000 GB monthly transfer VPS (droplet) for 5$. It’s enough for the setup we need however feel free to use any other VPS provided if needed. What is important – they must offer you exclusive public IP for your VPS (what Digital Ocean does for every droplet).

If you decide to use Digital Ocean here is my referral link: https://m.do.co/c/1dec60f1b63f (you get 100$ credit to use for 60 days).

The picture below shows the droplet to choose if you decide to use Digital Ocean droplet. During the process choose the datacenter region you prefer. The datacenter you choose affects your public IP (your LN node will have show the location of your public IP) so choose according to your needs/preferences. Your can add SSH keys for easier SSH login. Don’t take any additional features, all we need is a basic droplet.

The smallest droplet offered by Digital Ocean is enough for need of OpenVPN server.
The datacenter affects your public IP and the visibility of your node – your IP address based location will show your node is for example in Germany.

Droplet creation takes ~1 minute. It should get public IP immediately.

The IP of your droplet, will become IP of your LN node (in this case 192.241.154.55).

We have droplet IP: 192.241.154.55. In the steps below always replace this value with your VPS/droplet IP.

Step 2: Configure VPS (on VPS/droplet)

  1. Connect via SSH to your VPS (in case of our droplet you can configure it in Access tab in droplet settings then ssh root@192.241.154.55).
  2. (OPTIONAL, do it on Digital Ocean for new Droplet) Update apt-get package manager:
    1. sudo apt-get update
    2. sudo apt-get upgrade
  3. Install dependencies and setup:
    1. sudo apt-get install docker.io screen
    2. sudo systemctl start docker.service

Step 3: Setup OpenVPN server (on VPS/droplet)

We will use dockerized OpenVPN server: https://hub.docker.com/r/kylemanna/openvpn/. You can setup OpenVPN server by yourself if you want (but then you must manually configure). Dockerized version is easy to setup and gains the additional security/featuers of containers (Docker). On VPS/droplet run:

  1. export OVPN_DATA="ovpn-data" – if you want it to be exported permanently add it to .bashrc file but it’s optional
  2. docker volume create --name $OVPN_DATA
  3. docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://192.241.154.55– remember to replace with your IP
  4. docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki– define required CA password (do not lose it), you can skip defining any name.
  5. docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/udp -p 9735:9735 -p 9735:9735/udp --cap-add=NET_ADMIN kylemanna/openvpn

At this point your OpenVPN docker container is running and has already exposed ports required for further LN node configuration.

Step 4: Obtain client VPN certificate (on VPS/droplet)

Client certificate will be used for client in order to connect to your VPN server (in our case Linux on Raspiblitz which runs LND will connect to VPN server running on the droplet). On VPS/droplet run:

  1. docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full CLIENTNAME nopass
  2. docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient CLIENTNAME > CERT.ovpn– it will ask you for password generated in point 3.4. It will generate file named CERT.ovpn in the folder you currently are

Step 5: Download VPN client cert to local machine and upload to Raspiblitz Linux (on your PC/localhost)

Our Raspiblitz is visible in local network under 192.168.1.6 (it may be different IP for you, obtain the correct IP). On your local PC/localhost run:

  1. scp -r root@165.227.155.159:/root/CERT.ovpn CERT.ovpn– download CERT.ovpn certificate file to your local machine via scp
  2. scp CERT.ovpn  admin@192.168.1.6:/home/admin– upload CERT.ovpn certificate file to the system which hosts your LN node (Raspiblitz Linux)

Step 5: Connect to VPN server (on Raspiblitz Linux)

Now we must connect from Raspiblitz Linux to droplet via VPN. On Raspiblitz Linux run:

  1. screen – it will open new terminal window which can be easily closed without killing session (it means it’s long lived terminal). We will use screen to connect open VPN connection which will not be closed after disconnecting via SSH from Raspiblitz Linux, however you can achieve similar effect using different ways/tools.
  2. sudo openvpn --config CERT.ovpn – it should establish connection to your VPN server.

Successful connection should present log similar to this:

➜  ~ sudo openvpn --config CERT.ovpn
Wed Jun 23 17:34:50 2021 OpenVPN 2.4.7 aarch64-unknown-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Feb 20 2019
Wed Jun 23 17:34:50 2021 library versions: OpenSSL 1.1.1d  10 Sep 2019, LZO 2.10
Wed Jun 23 17:34:50 2021 TCP/UDP: Preserving recently used remote address: [AF_INET]165.227.155.159:1194
Wed Jun 23 17:34:50 2021 UDP link local: (not bound)
Wed Jun 23 17:34:50 2021 UDP link remote: [AF_INET]192.241.154.55:1194
Wed Jun 23 17:34:51 2021 WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1541', remote='link-mtu 1542'
Wed Jun 23 17:34:51 2021 WARNING: 'comp-lzo' is present in remote config but missing in local config, remote='comp-lzo'
Wed Jun 23 17:34:51 2021 [165.227.155.159] Peer Connection Initiated with [AF_INET]192.241.154.55:1194
Wed Jun 23 17:34:52 2021 Options error: Unrecognized option or missing or extra parameter(s) in [PUSH-OPTIONS]:1: block-outside-dns (2.4.7)
Wed Jun 23 17:34:52 2021 TUN/TAP device tun0 opened
Wed Jun 23 17:34:52 2021 /sbin/ip link set dev tun0 up mtu 1500
Wed Jun 23 17:34:52 2021 /sbin/ip addr add dev tun0 local 192.168.255.6 peer 192.168.255.5
Wed Jun 23 17:34:52 2021 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this
Wed Jun 23 17:34:52 2021 Initialization Sequence Completed

The line in logs: Wed Jun 23 17:34:52 2021 /sbin/ip addr add dev tun0 local 192.168.255.6 peer 192.168.255.5 informs that your client VPN IP is 192.168.255.6. It will be important for further configuration.

4. click CTRL+A CTRL+D – it will quit your screen terminal without killing the session and will take you back to your host terminal (and you are still connected to VPN server)
5. (OPTIONAL) run screen -R– to verify your screen terminal is running then again quit using CTRL+A CTRL+D

Step 6: Configure VPN server to route traffic to your LN node (on VPS/droplet)

Go back to your VPS/droplet. We must now properly configure OpenVPN docker container to filter/foward the LN traffic. Your container has already exposed 9735 port so requests on 192.241.154.55 reach your OpenVPN server running container. We must now configure IPTABLES  to allow/forward traffic in Docker container in order to reach your LN node connected via VPN. On your VPS/droplet run:

  1. docker ps– it should show your OpenVPN server container running. Copy the CONTAINER ID value, in our case 56f1a07e2239
  2. docker exec -it 56f1a07e2239 sh– open shell inside the container
  3. iptables -A PREROUTING -t nat -i eth0 -p tcp -m tcp --dport 9735 -j DNAT --to 192.168.255.6:9735– assuming that your client connected to VPN server is like in our case: 192.168.255.6
  4. iptables -A PREROUTING -t nat -i eth0 -p udp -m udp --dport 9735 -j DNAT --to 192.168.255.6:9735
  5. iptables -t nat -A POSTROUTING -d 192.168.255.0/24 -o tun0 -j MASQUERADE– notice that 192.168.255.0 is based by our client IP which is 192.168.255.x.

Tweak these commands to your needs if you have different VPN client IP.  Type exit in order to quit Docker container.

Step 7: Configure LN node and make it public (on Raspiblitz Linux)

On your Raspiblitz run:

  1. sudo vim /mnt/hdd/lnd/lnd.conf – edit the file and add/replace these sections (do not edit/delete other entries). Use your VPS/droplet IP.

    [Application Options]
    externalip=192.241.154.55:9735
    tlsexteraip=192.241.154.55
  2. sudo vim /mnt/hdd/raspiblitz/conf– edit the file and add/replace these sections (do not edit/delete other entries). Use your VPS/droplet IP.

    # RASPIBLITZ CONFIG FILE
    publicIP='192.241.154.55'
    lndPort='9735'
    lndAddress='192.241.154.55'
  3. sudo vim /etc/systemd/system/lnd.service– edit the file and add/replace this line only ExecStart=/usr/local/bin/lnd ${lndExtraParameter. It does not require implicit externalip definition since it will be taken from lnd.conf.
  4. sudo systemctl restart lnd.service– restart your lnd.service . If systemd asks you to reload services, run the command it shows.
  5. Restart your Raspiblitz.

Step 7B: If you don’t use Raspiblitz…

If you don’t use Raspiblitz then assure that you run your LND with proper configuration in means:

  • it has externalip=set with proper IP of your VPS
  • it has tlsextraip= has the same IP like externalip

Step 8: Connect it all together (on Raspiblitz Linux)

If you restarted your Raspiblitz (or your custom-LND setup) after applying changes from step 7 we are almost ready. Now we have:

  • restarted, running LND which is configured to be exposed public to the network on IP 192.241.154.55
  • running VPS/droplet with static IP 192.241.154.55 with running OpenVPN server Docker container which is configured to accept/route LND (port 9735) traffic via VPN to VPN client

What we must do now is only to connect from Raspiblitz to OpenVPN server. If you just restarted your Raspiblitz connect to it via SSH and run:

  1. screen
  2. sudo openvpn --config CERT.name
  3. CTRL+A CTRL+D
  4. sudo systemctl restart lnd.service – it can take a while.

If everything works well your restarted LND node should be already public with 192.241.154.54.

You can verify it simply checking your Raspiblitz info screen. It should show your LN node URI in orange color with correct IP.

Bittery.io node with public IP – Raspiblitz info screen (also LCD display)

F.A.Q.

1. Is it safe? Is my node still private/self hosted?

Yes it is safe. Your node is still self hosted and access to other Raspiblitz services is not exposed to the public. VPS server running on cloud provider is just exposing 9735 port so it’s kind of equivalent of having 9735 port exposed on your Raspiblitz by yourself. However you can secure your droplet/VPS  by some custom configuration (e.g. create non-root user).

2. What if someone hacks droplet/VPS? Can he hack also my LND?

The simplified answer is no, but access to VPS is not secure by definition and you don’t want it. The VPS does simple job of forwarding traffic to/from your node connected by VPN. From that perspective there is not any serious security risk involved with having additional component between LND and network (VPN connection). Remember that your LND is still self hosted – all sensitive data, including private keys are never exposed in any part of the connection between your LND and network using VPN and tutorial which we described. Your LND data is on your devices and even access to the VPS is not access to your device. However hacked VPS can always be vulnerable (or even is by definition) so you can try to hardering it.

3. I restarted my Raspiblitz. What should I do?

Follow these steps when you restart your Raspiblitz. Connect via SSH to your Raspiblitz and run:

  1. screen
  2. sudo openvpn --config CERT.name
  3. CTRL+A CTRL+D
  4. sudo systemctl restart lnd.service

Of course there are ways to make VPN connection more automated (via some script or systemd service).

4. I restarted my droplet/VPS. What should I do?

Follow these steps when you restart your droplet/VPS or by any other reason it will restart. SSH to droplet/VPS then:

  1. docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/udp -p 9735:9735 -p 9735:9735/udp --cap-add=NET_ADMIN kylemanna/openvpn
  2. Execute all the commands from step 6
  3. Execute all the commands from FAQ section, point 3. I restarted my Raspiblitz. What should I do?

5. I’ve changed tlsextraip in lnd.conf – was it required? Did it affect anything?

Your tls.cert certificate used to secure connection via GRPC/HTTP to LND node was configured to localhost. If you want to use external connections via GRPC/HTTP to LND (which are not configured for you if you configured Raspiblitz using this tutorial) then you should regenerate tls.cert to include your new public IP. You can do it from Raspiblitz settings (for safety do backup before).

6. What if I would like to connect via HTTP/GRPC to my node using public IP?

So you want to reach your GRPC/HTTP API of your self hosted node via Internet. Yes it’s possible using this VPN configuration. All you need is to start OpenVPN docker container with exposed ports 10009 (default for GRPC) or 8080 (default for HTTP) and do the same IPTABLES configuration like for port 9735. Example for GRPC: iptables -A PREROUTING -t nat -i eth0 -p tcp -m tcp --dport 10009 -j DNAT --to 192.168.255.6:10009. For using the API you will need reconfigured tls.cert (look point above). Also be aware that exposing your API/GRPC is risky from security point of view. Do it at your own risk.

Summary

This tutorial presents steps for relatively cheap, secure, stable and private way to expose your private, self hosted Lightning Network node (Raspiblitz) as public node. It is alternative to DDNS based solution which also can achieve similar effect however it exposes your private IP address.

I develop Bittery.io – better Bitcoin payments which aims to allow accepting Bitcoin payments (especially via Lightning Network). This is the place where right now you can get your personal, free Lightning Network node on Bitcoin testnetIt is great way to learn by doing and touch Lightning before you decide to setup your personal node (what I recommend, in Bitcoin we trust). Very soon Bittery.io will go mainnet and will offer hosted LN nodes solutions (unfortunately not free anymore).

Follow me on Twitter to be part of my Bitcoin, Lightning Network, Bittery.io, blockchain and other crypto-anarchy tasted adventures.

Have any question, feedback or you want to add/clarify something? Write in the comments.