
HODLmeTight
Plebnet Private Node for >1M channels, online 24/7 cable at 1gig in Germany, UPS, balancing to the best of what profitability allows
Verified
OG
Opener
Passionate
Trustworthy
Honourable
Social
Generous
Setup LNbits on a VPS, connected to your Lightning Network Node through a secured tunnel
Posted about 1 month ago
VPS-LNbits
Here's my current setup shared with you, while your objective and intend can be manyfold, you may
- have a dynamic IP from your Internet Service Provider
- want to hide your home IP from the world, for whatever reason
- desire to decrease your Lightning Node HTLC Routing times, so instead of running Tor only, you want Clearnet availability, too
- want others to leverage the LN Services you want to offer, via LNBits, BTCPay or others
- get a domain-name or use a free-domain host such as DuckDNS to point to your LNBits instance
- are just curious and want to tinker around a bit, because it's good to have those skills when demand for experience continues to rise
This is a long post, so please follow this linked Post on Github with better code-formatting, TOC and some casual updates.
Lastly, if you want a simpler LND Hybrid VPS guide, without the LNBits piece, check out the following guide.
- Hybrid-Mode for LND
- TURN YOUR SELF HOSTED LIGHTNING NETWORK NODE TO PUBLIC IN 10 MINUTES
- OpenVPN for Docker
- How to configure Umbrel LNbits app without Tor
- running lnd-0.14.2-beta or later. This can either be Umbrel, Raspiblitz, MyNode or even a bare RaspiBolt
- Technical curiosity and not too shy to use the command-line
- A domain name or a subdomain registered at DuckDNS
- An SSH connection to your node, and to the VPS as well. On Windows, use something like putty and get putty-gen, too
- VPS Account at DigitalOcean or any alternative VPS Solution out there offering similar capabilities (it's critical they offer a public IP for you)
- IP-Adresses of VPS external, VPS Tunnel, Node Tunnel
- Ports which needs forwarding
- ToDos
- Questions / open items

- add a new Droplet on the left hand navigation
- chose an OS of your preference, I have Ubuntu 20.04 (LTS) x64
- take the Basic Plan with a shared CPU, that's enough power. You can upgrade anytime if necessary
- Switch the CPU option to "Regular Intel with SSD", which should get you down to $5/month
- You don't need an extra volume, but pick a datacenter region of your liking
- Authentication: Chose the SSH keys option and follow the next steps to add your public keys in here for secure access. For Windows, with putty and putty-gen referenced above, you should be relatively quick to use those keys instead of a password. For Linux users, you probably know your ways already.
- Add backups (costs), Monitoring or IPv6 if you wish to, however this guide won't use any of those items
- Lastly, chose a tacky hostname, something which resonates with you, eg myLNBits-VPS
- Update your packages: apt-get update and apt-get upgrade
- Install Docker: apt-get install docker.io tmux
- Enable Docker automated start: systemctl start docker.service
- Enable Uncomplicated Firewall (UFW) and add ports to be allowed to connected to:
$ apt install ufw $ ufw default deny incoming $ ufw default allow outgoing $ ufw allow OpenSSH $ ufw allow 80 comment 'Standard Webserver' $ ufw allow 443 comment 'SSL Webserver' $ ufw allow 9735 comment 'LND Main Node 1' $ ufw enable
- Follow further hardening steps, eg setting up non-root users for additional security enhancements.
- Install fail2ban to protect your SSH user, it runs automatically on it's own sudo apt install fail2ban
4) VPS: Install OpenVPN Server
- export OVPN_DATA="ovpn-data" which sets a global-name placeholder for your VPN to be used for all the following commands. You can make this permanent by adding this to survive any reboot via nano .bashrc, add it to the very bottom => CTRL-X => Yes.
- docker volume create --name $OVPN_DATA notice how the $ indicates picking up the placeholder you have defined above
- docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://207.154.241.101, whereby you need to adjust the 207.154.241.101 with your own VPS Public IP.
- docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki this generates the necessary VPN certificate password. Take your password manager and create a secure pwd, which you will store safely. It will be needed once we create client-configuration files for your node to connect later.
- docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/udp -p 9735:9735 -p 9735:9735/udp -p 8080:8080 -p 8080:8080/udp --cap-add=NET_ADMIN kylemanna/openvpn this works under two assumptions. If any of those aren't true, you need to adjust your settings, either on your node, or by starting the docker container with different ports:
- your current LND Node configuration is listening on port 9735, which you can verify by looking into your cat ~/.lnd/lnd.conf => [Application Options] => listen=0.0.0.0:9735
- your LND RestLNDWallet is listening on port 8080, same location under [Application Options] => restlisten=0.0.0.0:8080
- CONTAINER-ID: docker ps to list your docker container. In the first column, you will find the CONTAINER-ID, usually a cryptic 12-digit number/character combination. Copy into the clipboard and make a note of it.
- Docker Shell: Get into the container, with docker exec -it <CONTAINER-ID> sh.
- VPS Docker IP: Run ifconfig and you typically find 3 devices listed with IPs assigned. Make a note of the one with eth0, which is your own VPS Docker IP: 172.17.0.2. Type exit to get out of the docker-shell.
5) VPS: Install LNBits
$ sudo apt-get install git $ git clone https://github.com/lnbits/lnbits-legend $ sudo apt update $ sudo apt install pipenv $ cd lnbits-legend $ pipenv --python 3.9 shell $ pipenv run pip install -r requirements.txt $ pipenv run python -m uvicorn lnbits.__main__:app
- docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full NODE-NAME nopass whereby NODE-NAME should be changed to a unique identifier you chose. For example, if your LND Node is called "BringMeSomeSats", I suggest to use that - with all lowercase.
- docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient NODE-NAME > NODE-NAME.ovpn which will prompt you to provide the secure password you have generated earlier. Afterwards, it'll store bringmesomesats.ovpn in the directory you currently are.
Into the Tunnel
$ cd ~ $ mkdir VPNcert $ scp user@207.154.241.101:/home/user/bringmesomesats.ovpn /home/admin/VPNcert/ $ chmod 600 /home/admin/VPNcert/bringmesomesats.ovpn $ sudo cp -p /home/admin/VPNcert/bringmesomesats.ovpn /etc/openvpn/CERT.conf
$ sudo apt-get install openvpn $ sudo systemctl enable openvpn@CERT $ sudo systemctl start openvpn@CERT
* openvpn@CERT.service - OpenVPN connection to CERT Loaded: loaded (/lib/systemd/system/openvpn@.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2022-04-06 13:11:13 CEST; 4s ago Docs: man:openvpn(8) https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage https://community.openvpn.net/openvpn/wiki/HOWTO Main PID: 1514818 (openvpn) Status: "Initialization Sequence Completed" Tasks: 1 (limit: 18702) Memory: 1.0M CPU: 49ms CGroup: /system.slice/system-openvpn.slice/openvpn@CERT.service `-1514818 /usr/sbin/openvpn --daemon ovpn-CERT --status /run/openvpn/CERT.status 10 --cd /etc/openvpn --config /etc/openvpn/CERT.conf --writepid /run/openvpn/CERT.pid Apr 06 13:11:13 debian-nuc ovpn-CERT[1514818]: WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1541', remote='link-mtu 1542' Apr 06 13:11:13 debian-nuc ovpn-CERT[1514818]: WARNING: 'comp-lzo' is present in remote config but missing in local config, remote='comp-lzo' Apr 06 13:11:13 debian-nuc ovpn-CERT[1514818]: [207.154.241.101] Peer Connection Initiated with [AF_INET]207.154.241.101:1194 Apr 06 13:11:14 debian-nuc ovpn-CERT[1514818]: TUN/TAP device tun0 opened Apr 06 13:11:14 debian-nuc ovpn-CERT[1514818]: net_iface_mtu_set: mtu 1500 for tun0 Apr 06 13:11:14 debian-nuc ovpn-CERT[1514818]: net_iface_up: set tun0 up Apr 06 13:11:14 debian-nuc ovpn-CERT[1514818]: net_addr_ptp_v4_add: 192.168.255.6 peer 192.168.255.5 dev tun0
- Remember how to get into the container? Arrow-up on your keyboard, or do docker ps and docker exec -it <CONTAINER-ID> sh
- Doublecheck your VPN Client IP, and adjust it in the following IPtables commands you enter into the container and confirm with Enter
$ iptables -A PREROUTING -t nat -i eth0 -p tcp -m tcp --dport 9735 -j DNAT --to 192.168.255.6:9735 $ iptables -A PREROUTING -t nat -i eth0 -p udp -m udp --dport 9735 -j DNAT --to 192.168.255.6:9735 $ iptables -A PREROUTING -t nat -i eth0 -p tcp -m tcp --dport 18080 -j DNAT --to 192.168.255.6:8080 $ iptables -t nat -A POSTROUTING -d 192.168.255.0/24 -o tun0 -j MASQUERADE $ exit
Raspiblitz / Raspibolt settings
externalip=207.154.241.101:9735 | # to add your VPS Public-IP
nat=false | # deactivate NAT
tlsextraip=172.17.0.2 | # allow later LNbits-access to your rest-wallet API
tor.active=true | # ensure Tor is active
tor.v3=true | # with the latest version. v2 is going to be deprecated this summer
tor.streamisolation=false | # this needs to be false, otherwise hybrid mode doesn't work
tor.skip-proxy-for-clearnet-targets=true | # activate hybrid mode
publicIP='207.154.241.101' | # add your VPS Public-IP
lndPort='9735' | # define the LND port
lndAddress='207.154.241.101' | # define your LND public IP address
sudo nano /etc/systemd/system/lnd.service | edit the line 15 where it starts your LND binary, and add the following parameter: ExecStart=/usr/local/bin/lnd ${lndExtraParameter}
sudo systemctl restart lnd.service | apply changes and restart your lnd.service. It will ask you to reload the systemd services, copy the command, and run it with sudo. This can take a while, depends how long your last restart was. Be patient.
sudo tail -n 30 -f /mnt/hdd/lnd/logs/bitcoin/mainnet/lnd.log | to check whether LND is restarting properly
lncli getinfo | to validate that your node is now online with two uris, your pub-id@VPS-IP and pub-id@Tor-onion
"03502e39bb6ebfacf4457da9ef84cf727fbfa37efc7cd255b088de426aa7ccb004@207.154.241.101:9736", "03502e39bb6ebfacf4457da9ef84cf727fbfa37efc7cd255b088de426aa7ccb004@vsryyejeizfx4vylexg3qvbtwlecbbtdgh6cka72gnzv5tnvshypyvqd.onion:9735"
- Restart your LND Node with sudo reboot
Umbrel / Citadel settings
externalip=207.154.241.101:9735 | # to add your VPS Public-IP
nat=false | # deactivate NAT
tlsextraip=172.17.0.2 | # allow later LNbits-access to your rest-wallet API
tor.active=true | # ensure Tor is active
tor.v3=true | # with the latest version. v2 is going to be deprecated this summer
tor.streamisolation=false | # this needs to be false, otherwise hybrid mode doesn't work
tor.skip-proxy-for-clearnet-targets=true | # activate hybrid mode
cd umbrel && docker-compose restart lnd | this can take a while, depends how long your last restart was. Be patient.
tail -n 30 -f ~/umbrel/lnd/logs/bitcoin/mainnet/lnd.log | check whether LND is restarting properly
~/umbrel/bin/lncli getinfo | validate that your node is now online with two uris, your pub-id@VPS-IP and pub-id@Tor-onion
"03502e39bb6ebfacf4457da9ef84cf727fbfa37efc7cd255b088de426aa7ccb004@207.154.241.101:9736", "03502e39bb6ebfacf4457da9ef84cf727fbfa37efc7cd255b088de426aa7ccb004@vsryyejeizfx4vylexg3qvbtwlecbbtdgh6cka72gnzv5tnvshypyvqd.onion:9735"
- Restart your LND Node with sudo reboot
Warning: This guide did not verify yet, if and how the docker LND service on Umbrel & Citadel needs to be adjusted to channel clearnet packets via tunnel. We will add peer-reviewed adjustments here from Umbrel / Citadel devs. Until then, consider this highly experimental, it might fail.
Connect VPS LNBits to your LND Node
- your tls.cert. Only with access to this file, your VPS is going to be allowed to leverage your LND Wallet via Rest-API scp ~/.lnd/tls.cert root@207.154.241.101:/root/ sends your LND Node tls.cert to your VPS, where we will use it in the next section.
- your admin.macaroon. Only with that, your VPS can send and receive payments xxd -ps -u -c ~/.lnd/data/chain/bitcoin/mainnet/admin.macaroon will provide you with a long, hex-encoded string. Keep that terminal window open, since we need to copy that code and use it in our next step on the VPS.
$ cd lnbits-legend $ mkdir data $ pwd $ cp .env.example .env $ sudo nano .env
LNBITS_DATA_FOLDER="/user/lnbits-legend/data" | enter the absolute path to the data folder you created above
LNBITS_BACKEND_WALLET_CLASS=LndRestWallet | Specify that we want to use our LND Node Wallet Rest-API
LND_REST_ENDPOINT="https://172.17.0.2:8080" | Add your VPS Docker IP: 172.17.0.2 on port 8080
LND_REST_CERT="/root/tls.cert" | Add the link to the tls.cert file copied over earlier
LND_REST_MACAROON="HEXSTRING" | Copy the hex-encoded snippet from your LND Node Terminal output from Section 11.2 in here
LNBITS_SITE_TITLE="HODLmeTight LNbits" | Give your Website a tacky title
LNBITS_SITE_TAGLINE="free and open-source lightning wallet" | Define the sub-title in the body
LNBITS_SITE_DESCRIPTION="Offering free and easy Lightning Bitcoin Payment options for Friends & Family" | Outline your offering
LNBITS_THEME_OPTIONS="classic, bitcoin, flamingo, mint, autumn, monochrome, salvador" | Provide different color themes, or keep it simple
CTRL-X => Yes => Enter to save |
$ tmux new -s lnbits $ cd ~/lnbits-legend $ pipenv --python 3.9 shell $ pipenv run python -m uvicorn lnbits.__main__:app --host 0.0.0.0
- make an account on DuckDNS with GH or Email
- add 1 of 5 free subdomains, eg. paymeinsats
- point this domain to your VPS Public IP: 207.154.241.101
- Make a note of your Token
$ sudo apt update $ sudo apt install nginx certbot $ sudo certbot certonly --manual --preferred-challenges dns
- Open a text editor, and add this URL: https://www.duckdns.org/update?domains={YOURVALUE}&token={YOURVALUE}&txt={YOURVALUE}[&verbose=true]
- replace each variable2
- domains={YOURVALUE} with your subdomain only, in our case domains=paymeinsats
- token={YOURVALUE} with your token from your duckdns.org overview
- txt={YOURVALUE} with the random text-snippet certbot provided you to fill in
- optional: set verbose=true if you want 2 lines more info as a response
- Copy that whole string into a new Webbrowser window, and if verbose isn't set as true, it'll be as crisp as OK
- In a new Terminal window, install dig sudo apt-get install dnsutils to check if the world knows about you solved the challenge: dig -t txt _acme-challenge.paymeinsats.duckdns.org. Compare the TXT record entry with what Certbot provided you. If both are similar, confirm with Enter in the Certbot Terminal, so it can do it's own verification
- Once successful, you got your SSL certificates. Make a note in your calendar when the validation time is over, so you renew early enough. Also take note of the absolute paths of those two certificates you received.
VPS: Webserver NGINX
- sudo nano /etc/nginx/sites-available/paymeinsats.conf to create and edit your new configuration file nginx will use
server { # Binds the TCP port 80 listen 80; # Defines the domain or subdomain name server_name paymeinsats.duckdns.org; # Redirect the traffic to the corresponding # HTTPS server block with status code 301 return 301 https://$host$request_uri; } server { listen 443 ssl; # tell nginx to listen on port 443 for SSL connections server_name paymeinsats.duckdns.org; # tell nginx the expected domain for requests access_log /var/log/nginx/paymeinsats-access.log; # Your first go-to for troubleshooting error_log /var/log/nginx/paymeinsats-error.log; # Same as above location / { proxy_pass http://127.0.0.1:8000; # This is your uvicorn LNbits local host IP and port proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header X-Forwarded-Proto https; proxy_set_header Host $host; proxy_http_version 1.1; # headers to ensure replies are coming back and forth through your domain } ssl_certificate /etc/letsencrypt/live/paymeinsats.duckdns.org/fullchain.pem; # Point to the fullchain.pem from Certbot ssl_certificate_key /etc/letsencrypt/live/paymeinsats.duckdns.org/privkey.pem; # Point to the private key from Certbot }
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful $ sudo ln -s /etc/nginx/sites-available/paymeinsats.conf /etc/nginx/sites-enabled/ $ sudo systemctl restart nginx

Triangle Capacity: 5,000,000 SAT
View Swap ID: 7713Triangle Capacity: 4,000,000 SAT
View Swap ID: 5247Triangle Capacity: 5,000,000 SAT
View Swap ID: 5025Triangle Capacity: 4,900,000 SAT
View Swap ID: 5019Square Capacity: 4,000,000 SAT
View Swap ID: 3102This bitcoin lightning network node identified by the pubkey: 037f66e84e38fc2787d578599dfe1fcb7b71f9de4fb1e453c5ab85c05f5ce8c2e3 also known by the alias: HODLmeTight is accessible on the lightning network address: 037f66e84e38fc2787d578599dfe1fcb7b71f9de4fb1e453c5ab85c05f5ce8c2e3@207.154.241.207:9735 and 037f66e84e38fc2787d578599dfe1fcb7b71f9de4fb1e453c5ab85c05f5ce8c2e3@z5keqdwlv7mr5bjudwczzfok775d4xfxlxh3bbp7ug5nyjrjkxup3cyd.onion:9735 .
The node has 114 channels, and a total channel capacity of: 558,372,842 Satoshis, which is equivalent to ~5.584 BTC. The node's hex color is #76eec6. The information regarding this node and it channels has been updated last on 2022-05-27 11:00:58 UTC.
This node page has been claimed by user: HODLmeTight and has been verified through a digital signature as well. The user has created their account 11 months ago, and has been last seen 2 days ago.
The user has participated in 10 swaps on LightningNetwork+. The node operator has opened 10 channels to LN+ users through Swaps. The user has received 10 positive ratings from other users. The user has generously donated to LN+ to support the operation of the site.
To learn more about this node, including historical data visit the following lightning network node explorers.