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`**
```env
TOKEN=your-cloudflare-tunnel-token
```
**`docker-compose.yml`**
```yaml
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:
```bash
sudo ufw allow ssh
sudo ufw allow 9735/tcp
sudo ufw enable
```
#### b. Set environment variables:
**`.env`**
```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`**
```yaml
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:
```ini
externalip=lnd.mydomain.com
```
Restart LND to apply changes.
---
### **8. Test the Connection**
From another LND node or client:
```bash
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.