Dual-LND-Wireguard-VPS

Connect your lightning network nodes via wireguard VPN Tunnel through your VPS to allow fast and anonymous payments. When finished, you’ll be able to run one or more of your Lightning Nodes via Tor and obfuscate your Clearnet IP Adress via a paid VPS

Alter Elbtunnel (erbaut 1911) – Wikipedia

This is a fork of my own Guide provided here, but instead of OpenVPN, we’re using the somewhat smaller / simpler WireGuard Solution. The Problem statement remains the same, you may prefer one solution over the other. Have a read through both and see what fits better. But in either case, you’re coming here for the following reasons:

Table of Content

Pre-Amble

Objective

Your own, non-custodial Lightning-Network Node(s) running in Hybrid-Mode (Tor and Clearnet) via a cheap, anonymous Virtual Private Server (VPS). This guide outlines setup for two nodes (adjust steps for one or more).

Challenge

Fast, reliable, non-custodial Bitcoin payments should ideally be anonymous. Tor provides privacy but can be slow/unreliable.

Proposed Solution

This guide offers one approach to improve speed and anonymity using a VPS and WireGuard. Follow carefully, it may take about 1 hour depending on your skills.

Pre-Reads

To understand some concepts better, read these articles:

Pre-Requisites

DigitalOcean Referral Badge

Disclaimer: ref link, $100 credit over 60 days, cheapest option ~$5/month.

Preperations

The better we prepare, the more we can deal with blindspots and the unexpected.

Make notes

Document your steps! Imagine future you setting up a new node - will you remember everything?

Suggested checklist:

Visualize

Draw a diagram to understand the flow. High-lvl-Flowchart

Secure

Security is critical! This guide doesn’t cover all security steps in detail. Start with small funds, stay updated on security news, and ideally, do this with a peer for review. Use 2FA/YubiKeys!

Let’s get started (LFG!)

Well, let’s get into it, shall we?!

Lightning Node

We will consider you have your Lightning Node up and running, connected via Tor and some funds on it. You also have SSH access to it and administrative privileges.

VPS: Setup

If you don’t have a VPS, sign up via referral link or choose another provider with static IP and reasonable cost (maybe even Lightning payable!).

For DigitalOcean, create a Droplet (takes minutes):

After setup, you’ll get a public IPv4 address. Note it down as VPS Public IP: 207.154.241.101 (example).

VPS: Connect to your VPS and tighten it up

Connect via SSH: ssh root@207.154.241.101. Harden your VPS immediately:

VPS: Install Wireguard

Follow DigitalOcean guide for detailed context. Skipping IPv6 for simplicity.

VPS: Firewall

For packet forwarding, add rules to wg0.conf. This forwards packets from your node to the internet device.

PostUp = ufw route allow in on wg0 out on eth0
PostUp = iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
PreDown = ufw route delete allow in on wg0 out on eth0
PreDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

VPS: LND Port-Forwarding

Forward LND packets to your node.

Add these lines to the script:

#!/bin/bash
# Save current iptables rules
iptables-save > /etc/wireguard/iptables.rules
ip6tables-save > /etc/wireguard/ip6tables.rules

Make it executable:

sudo chmod +x /etc/wireguard/iptables-save.sh

Now create a service to restore rules at boot:

sudo nano /etc/systemd/system/iptables-restore.service

Add this content:

[Unit]
Description=Restore iptables rules
After=network.target
Before=wg-quick@wg0.service
[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/wireguard/iptables.rules
ExecStart=/sbin/ip6tables-restore /etc/wireguard/ip6tables.rules
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

Now save your current rules and enable the service:

sudo /etc/wireguard/iptables-save.sh
sudo systemctl enable iptables-restore.service

This approach preserves your UFW configuration while ensuring your custom iptables rules for WireGuard are applied after a reboot.

VPS: Start your WireGuard Server

Your WireGuard server is running! Internet can connect to VPS on ports 9735 and 22 (SSH from home), tunnel on port 51820.

Check your notes for:

Into the Tunnel

We have installed the tunnel through the mountain, but need to get our LND Node to use it.

LND Node: Install and test the VPN Tunnel

Switch to your Lightning Node terminal. Replicate VPS WireGuard setup to connect to the VPS tunnel.

$ sudo apt update
$ sudo apt install wireguard -y
$ sudo apt install resolvconf -y # for DNS via tunnel
$ wg genkey | sudo tee /etc/wireguard/private.key
$ sudo chmod go= /etc/wireguard/private.key
$ sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
# Note down private key (secret!) and public key (for server config).

Create wg0.conf on your node: sudo nano /etc/wireguard/wg0.conf

[Interface]
PrivateKey = ***base64_encoded_peer_private_key_goes_here***
Address = 10.8.0.2/24

[Peer]
PublicKey = U9uE2kb/nrrzsEU58GD3pKFU3TLYDMCbetIsnV8eeFE=
AllowedIPs = 0.0.0.0/0
Endpoint = 207.154.241.101:51820
PersistentKeepalive = 25

Important: Route all node traffic through the tunnel, but keep local LAN access.

PostUp = ip rule add table 200 from 203.0.113.5
PostUp = ip route add table 200 default via 203.0.113.1
PreDown = ip rule delete table 200 from 203.0.113.5
PreDown = ip route delete table 200 default via 203.0.113.1

DNS = 67.207.67.2 67.207.67.3

Now, switch to VPS terminal to allow node connection.

Warning: Next step reroutes node traffic through tunnel, potential downtime for LND. Be patient!

Tunnel established! Troubleshoot with sudo wg show or sudo systemctl journal -u wg-quick@wg0.service.

LND Node: LND adjustments to listen and channel via VPS VPN Tunnel

We switch Terminal windows again, going back to your LND Node. A quick disclaimer again, since we are fortunate enough to have plenty of good LND node solutions out there, we cannot cater for every configuration out there. Feel free to leave comments or log issues if you get stuck for your node, we’ll be looking at the two most different setups here. But this should work very similar on MyNode, Raspibolt or Citadel.

Be very cautious with your lnd.conf. Make a backup before with cp ~/.lnd/lnd.conf ~/.lnd/lnd.bak so you can revert back when things don’t work out. The brackets below indicate the section where each line needs to be added to. Don’t place anything anywhere else, as it will cause your LND constrain from starting properly.

Adjust ports and IPs accordingly!

Click here to expand Raspibolt settings

LND.conf adjustments, open with `sudo nano /mnt/hdd/lnd/lnd.conf` [**Application Options**] | Command | Description | | --- | --- | | `externalip=207.154.241.101:9735` | # to add your VPS Public-IP | | `nat=false` | # deactivate NAT | [**tor**] | Command | Description | | --- | --- | | `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 | `CTRL-X` => `Yes` => `Enter` to save LND Systemd Startup adjustment | Command | Description | | --- | --- | | `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" ```

Click here to expand Raspiblitz 1.7.x settings

LND.conf adjustments, open with `sudo nano /mnt/hdd/lnd/lnd.conf` [**Application Options**] | Command | Description | | --- | --- | | `externalip=207.154.241.101:9735` | # to add your VPS Public-IP | | `nat=false` | # deactivate NAT | [**tor**] | Command | Description | | --- | --- | | `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 | `CTRL-X` => `Yes` => `Enter` to save RASPIBLITZ CONFIG FILE `sudo nano /mnt/hdd/raspiblitz.conf` since Raspiblitz has some LND pre-check scripts which otherwise overwrite your settings. | Command | Description | | --- | --- | | `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 | `CTRL-X` => `Yes` => `Enter` to save LND Systemd Startup adjustment | Command | Description | | --- | --- | | `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" ```

Click here to expand Raspiblitz 1.8.x settings

LND.conf adjustments, open with `sudo nano /mnt/hdd/lnd/lnd.conf` [**Application Options**] | Command | Description | | --- | --- | | `externalip=207.154.241.101:9735` | # to add your VPS Public-IP | | `nat=false` | # deactivate NAT | [**tor**] | Command | Description | | --- | --- | | `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 | `CTRL-X` => `Yes` => `Enter` to save RASPIBLITZ LND-checkup FILE `sudo nano /home/admin/config.scripts/lnd.check.sh` since Raspiblitz has some LND pre-check scripts which otherwise overwrite your settings. Go to line 184 or search for `enforce PublicIP if (if not running Tor)`. Uncomment those 5 lines indicated here: ``` # if [ "${runBehindTor}" != "on" ]; then # setting ${lndConfFile} ${insertLine} "externalip" "${publicIP}:${lndPort}" # else # when running Tor a public ip can make startup problems - so remove # sed -i '/^externalip=*/d' ${lndConfFile} # fi ``` `CTRL-X` => `Yes` => `Enter` to save LND Systemd Startup adjustment | Command | Description | | --- | --- | | `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" ```

Click here to expand Umbrel Pre-0.5 & Citadel settings

LND.conf adjustments, open with `sudo nano /home/umbrel/umbrel/lnd/lnd.conf` [**Application Options**] | Command | Description | | --- | --- | | `externalip=207.154.241.101:9735` | # to add your VPS Public-IP | | `nat=false` | # deactivate NAT | [**tor**] | Command | Description | | --- | --- | | `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 | `CTRL-X` => `Yes` => `Enter` to save LND Restart to incorporate changes to `lnd.conf` | Command | Description | | --- | --- | | `cd umbrel && docker-compose restart lnd` | This can take a while. 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" ```

Click here to expand Umbrel Version 0.5.x settings

LND.conf adjustments, open with `sudo nano /home/umbrel/umbrel/lnd/lnd.conf` [**Application Options**] | Command | Description | | --- | --- | | `externalip=207.154.241.101:9735` | # to add your VPS Public-IP | | `nat=false` | # deactivate NAT | [**tor**] | Command | Description | | --- | --- | | `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 | `CTRL-X` => `Yes` => `Enter` to save LND Restart to incorporate changes to `lnd.conf` | Command | Description | | --- | --- | | `~/umbrel/scripts/app stop lightning && ~/umbrel/scripts/app start lightning` | same applies here: Be patient. | | `tail -f ~/umbrel/app-data/lightning/data/lnd/logs/bitcoin/mainnet/lnd.log` | Check the logs | | `~/umbrel/scripts/app compose lightning exec lnd lncli getinfo` | Check the two Uris looking like below | ``` "03502e39bb6ebfacf4457da9ef84cf727fbfa37efc7cd255b088de426aa7ccb004@207.154.241.101:9736", "03502e39bb6ebfacf4457da9ef84cf727fbfa37efc7cd255b088de426aa7ccb004@vsryyejeizfx4vylexg3qvbtwlecbbtdgh6cka72gnzv5tnvshypyvqd.onion:9735" ```

Celebrate and wrapper

Now the moment of truth: once you tested the reboot, checked the LND log, and lncli getinfo shows you both the Tor and the VPS Clearnet IP as uris, you’re done. curl https://api.ipify.org responds with your VPS Clearnet-IP, too. LN gossip will soon populate your IP offering, and aggregator sites like Amboss or 1ml will pick it up. Time to celebrate 🍻 or troubleshoot where things could have gone wrong. If the former: Congratulations - you made it!

Hope you enjoyed this article. Please do share feedback and suggestions for improvement. If this guide was of any help, I’d appreciate if you share the article with others, give me a follow on X Twitter URL or nostr, perhaps even donating some sats to hakuna@hodlmetight.com

I’m also always grateful for incoming Hybrid channels to my node: HODLmeTight

Appendix & FAQ

I’m stuck and have no idea why it’s not working. Who can help?

Please add an issue on Github with your question and provide as much detail as possible. Keep it safe though, no macaroon or user-ids! Before that, use a port-checker tool or Tunnel⚡Sats Pingbot to check your connection

Why DigitalOcean - can’t we pick a VPS where we can pay with Lightning, and anonymously

Consider this guide a work-in-progress. I’ve picked DigitalOcean since I know what I’m doing there. Heard good things about Luna Node, it’s cheaper and you can pay with sats, so will test this out next. Also happy to add further alternatives, leave comments if you think these can accomplish the same results. Fee free to provide suggestions here.

Can I add more nodes connecting to the tunnel? If so, how?

In fact, I have more than one node connected to the tunnel. You need to handle your port-forwarding appropriately, since every node needs their unique LND listen port. Eg Node 1 has 9735, Node 2 9736 and so on. IPtable rules and UFW needs to be adjusted. But once you got this guide internalised, the principle should be clear. Otherwise, let me know.