Securely Expose Your LND Node via Cloudflared and a VPS

Securely Expose Your LND Node via Cloudflared and a VPS

Securely Expose Your LND Node via Cloudflared and a VPS

Introduction & Motivation

Exposing your Lightning Network Daemon (LND) node to the public internet is essential for full participation in the Lightning Network. However, doing so introduces critical challenges in terms of security, privacy, and resilience against attacks.

This guide presents a solution using Cloudflare Tunnel and Cloudflare Access—a modern, secure method to expose services to the internet while maintaining strict control and minimizing exposure. We also compare this approach with more traditional methods such as SSH tunnels and VPNs (WireGuard/OpenVPN + socat/iptables) to highlight the trade-offs.


Traditional Exposure Methods: Risks and Limitations

SSH Reverse Tunnels (ssh -R, sshtunnel)

  • Outbound-only: The connection is initiated from the LND host. The VPS cannot reach the internal network on its own.
  • ⚠️ Metadata exposure: The LND host's IP address, SSH key, and connection metadata are visible to the VPS.
  • ⚠️ Access control is coarse: Without extra measures, any process on the VPS can access the forwarded service.
  • ⚠️ No service-layer authentication: Anyone reaching the exposed port can interact with LND, assuming the protocol is known.

VPNs (WireGuard/OpenVPN + iptables or socat)

  • ⚠️ Blurs the security boundary: VPNs extend the network perimeter to remote clients. Misconfigured rules can inadvertently expose internal services.
  • Allows lateral movement: If the VPS is compromised, it may gain full access to the LND host’s network.
  • Traffic is encrypted, but requires correct firewalling and routing to be safe.
  • ⚠️ Complexity: These setups often involve manual iptables, port forwarding, and tight coupling of services.

Cloudflare Tunnel + Access (This Guide)

This solution uses Cloudflared on the LND host to initiate an outbound connection to Cloudflare, which then routes traffic through a secured, authenticated TCP tunnel via a VPS.

  • No exposed ports on the LND host.
  • VPS cannot discover or access the LND IP—only forwards TCP packets to Cloudflare.
  • Service Token authentication ensures only authorized clients can connect.
  • ⚠️ Trust in Cloudflare is required. While your LND host is protected from the internet, Cloudflare can see metadata, and potentially, inspect unencrypted traffic.
  • Cloudflare is proprietary infrastructure. You’re protected from attackers, but not necessarily from Cloudflare or governments.

Security & Privacy Comparison

Feature SSH Tunnel VPN + socat/iptables Cloudflare Tunnel + Access
Encrypts traffic
Initiated from LND host
Prevents VPS from accessing LAN
Hides LND IP from VPS
Hides LND IP from tunnel provider
Proprietary infrastructure ⚠️ (Cloudflare)
Fine-grained access control ⚠️ (manual) ⚠️ (manual) ✅ (Service Token)
Susceptible to VPS compromise ⚠️ (metadata only) ❌ (full access) ✅ (isolated forwarding)

Tutorial: Step-by-Step Setup


1. Set Up the Cloudflare Tunnel

  1. In your Cloudflare Zero Trust dashboard, navigate to Access → Tunnels.

  2. Create a new tunnel (e.g., lnd-tunnel).

  3. Choose Use Token Authentication and copy the token.

  4. Add a Public Hostname:

    • Hostname: lnd-external-access.mydomain.com
    • Service Type: TCP
    • URL: tcp://lnd:9735
      (This is the internal Docker hostname and port for LND.)

2. Run Cloudflared on the LND Host

Assuming your LND node runs in Docker inside the bitcoin-net network:

.env

TOKEN=your-cloudflare-tunnel-token

docker-compose.yml

version: "3.8"

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run --token ${TOKEN}
    restart: unless-stopped
    env_file:
      - .env
    networks:
      - bitcoin-net

networks:
  bitcoin-net:
    external: true
    name: bitcoin-net

3. Create the Cloudflare Service Token

  1. Go to Access → Service Auth.
  2. Click Create Service Token.
  3. Name it (e.g., lnd-access-client) and store both the Token ID and Token Secret—you’ll need these on the VPS and to configure access.

4. Define the Cloudflare Access Application

  1. Navigate to Access → Applications → Add an Application.

  2. Choose Self-hosted.

  3. Set:

    • Application Name: lnd-external-access
    • Domain: lnd-external-access.mydomain.com
  4. In Policies:

    • Add a policy:

      • Name: Allow via Service Token
      • Action: Service Auth
      • Include → Service Token: select the token you just created

5. Deploy the Forwarding VPS

a. Configure firewall:

sudo ufw allow ssh
sudo ufw allow 9735/tcp
sudo ufw enable

b. Set environment variables:

.env

TOKEN_ID=your-service-token-id
TOKEN_SECRET=your-service-token-secret
HOSTNAME=lnd-external-access.mydomain.com
LISTEN=tcp://0.0.0.0:9735

c. Run Cloudflared:

docker-compose.yml

version: "3.8"

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    ports:
      - 9735:9735
    command: >
      access tcp
      --service-token-id ${TOKEN_ID}
      --service-token-secret ${TOKEN_SECRET}
      --hostname ${HOSTNAME}
      --url ${LISTEN}
      --loglevel debug
    env_file:
      - .env
    restart: unless-stopped

6. Configure DNS

In Cloudflare DNS:

  • Create an A record:

    • Name: lnd
    • Type: A
    • Value: VPS_IP
    • Proxy status: DNS only

7. Configure LND

Edit lnd.conf to include:

externalip=lnd.mydomain.com

Restart LND to apply changes.


8. Test the Connection

From another LND node or client:

lncli connect <pubkey>@lnd.mydomain.com:9735

Check logs in LND and Cloudflared to confirm successful connection.


Final Notes

  • This method preserves your network perimeter, even if the VPS is compromised.
  • All traffic is authenticated with service tokens, and no direct access is possible to your LND host.
  • You do trust Cloudflare, so weigh that risk in high-privacy environments.
This post and comments are published on Nostr.