#

docker

(13 articles)

Securely Exposing Your LND Node Using Tor, Socat, and a VPS

# Securely Exposing Your LND Node Using Tor, Socat, and a VPS *A Cloudflare-Free Clearnet Proxy Architecture* ## Introduction & Motivation Running a Lightning Network Daemon (LND) node with a publicly reachable TCP address is essential for channel opens, forwarding payments, and maintaining strong network connectivity. Many node operators expose LND through tunneling services such as Cloudflare Tunnel. However, reliance on a proprietary centralized service introduces a structural single point of failure. The recent global Cloudflare outage demonstrated that even the most robust commercial infrastructures can go dark—taking dependent LND nodes offline. To eliminate this dependency, this article presents a fully open, privacy-preserving alternative using: - A minimal **VPS** exposing a public TCP listener - **Tor** as an anonymizing transport - **socat** to forward clearnet connections through Tor into your LND onion service - **Health checks + autoheal** to keep the tunnel alive This design preserves all the security benefits of outbound-only connectivity while removing Cloudflare from the trust chain. **Original Cloudflare-based article:** https://habla.news/a/naddr1qvzqqqr4gupzq0l6cwnvsk0242xdmkevwqp2dcgtx0h7hyksykc5att03gkk2ejhqqxnzde58yun2wpjxyerwd33tr0ph4 --- # Architecture Overview ``` Clearnet → VPS:9735 → socat → Tor SOCKS Proxy → Onion:9735 → LND Node ``` The system uses three containers: - **tor** – Runs Tor and exposes a SOCKS5 proxy - **socat** – Listens on clearnet and forwards streams to the onion service - **autoheal** – Restarts containers when health checks fail Result: a **public TCP endpoint** with **zero exposure** of your LND node’s real IP. --- # Why This Architecture? ### Key Properties | Feature | Tor + socat + VPS | Cloudflare Tunnel | |--------|--------------------|-------------------| | Keeps LND host inbound-closed | ✅ | ✅ | | VPS cannot discover LND IP | ✅ | ❌ | | No proprietary dependency | ✅ | ❌ | | Fully decentralized | ✅ | ❌ | | Built-in access control | ❌ | ✅ | | Reliant on a third party | ❌ | ✅ | | Resists Cloudflare outages | ✅ | ❌ | | Tor-level privacy | ✅ | ❌ | ### Summary - **Tor-based:** privacy, independence, censorship-resistance - **Cloudflare-based:** convenience, integrated access control, centralized trust The Tor solution sacrifices some convenience in exchange for decentralization and resilience. --- # Implementation Overview ## Components ### 1. Tor Container - Boots Tor - Provides SOCKS5 on port `9050` - Considered healthy after bootstrap reaches 100% ### 2. Socat Container - Waits for Tor readiness - Listens on clearnet port (default: 9735) - Forwards streams through the Tor SOCKS proxy ### 3. Autoheal - Monitors health status - Restarts unhealthy containers automatically - Ensures continuous operation --- # Deployment Guide ## 1. Start the Containers ```bash cd /path/to/tor-tunnel-lnd docker compose build docker compose up -d ``` ## 2. Check Runtime Status ```bash docker compose ps docker logs -f lnd-tor docker logs -f lnd-socat docker logs -f lnd-autoheal ``` ## 3. Check Container Health ```bash docker inspect --format='{{.State.Health.Status}}' lnd-tor docker inspect --format='{{.State.Health.Status}}' lnd-socat ``` ## 4. Configure Firewall ```bash sudo ufw allow 9735/tcp sudo ufw reload ``` --- # Configuration Options ### Environment Variables for `socat` | Variable | Description | Default | |----------|-------------|---------| | `ONION_HOST` | Onion address of LND | b3pje4v…onion | | `ONION_PORT` | LND port | 9735 | | `TOR_HOST` | Tor container hostname | tor | | `TOR_PORT` | SOCKS port | 9050 | | `TIMEOUT` | Seconds to wait for Tor readiness | 180 | ### Changing the External Port ```yaml ports: - "19735:9735" ``` --- # Testing ### From an external host ```bash nc -v <VPS_IP> 9735 ``` ### From another LND node ```bash lncli connect <pubkey>@<VPS_IP>:9735 ``` ### From inside the containers ```bash docker exec lnd-socat nc -z tor 9050 docker exec lnd-socat netstat -tlnp | grep 9735 ``` --- # LND Configuration Advertise both the clearnet and onion endpoints: ```ini externalip=<VPS_IP>:9735 externalip=b3pje4vztlrbilix7wp6fisyrdflbrx232v75xl4eyx4hjn2756avkyd.onion:9735 ``` Restart LND and check: ```bash lncli getinfo ``` Expected: - `03abc...@<VPS_IP>:9735` - `03abc...@b3pje4vztlr...onion:9735` --- # Health Checks & Autoheal ## Tor Health Check Verifies: - Tor bootstrap completion - Tor exit IP is recognized as a Tor exit - SOCKS proxy remains reachable Interval: 30s Timeout: 30s Start period: 60s ## Socat Health Check Verifies: 1. Socat is listening 2. Forwarding works end-to-end 3. LND responds with a Lightning handshake This ensures the tunnel isn't just running but fully functional. ## Autoheal Behavior - Monitors container health - Restarts unhealthy containers - Logs all restart actions --- # Advantages of the Tor-Based Architecture ### ✔ Fully Open-Source No central provider; no API tokens; no dashboards. ### ✔ Strong Privacy Guarantees The VPS cannot identify your LND node or its network location. ### ✔ Resilient to Cloudflare and CDN Outages No reliance on commercial infrastructure. ### ✔ Outbound-Only Connectivity The LND node exposes **zero** inbound ports. ### ✔ Minimal Attack Surface Only the VPS port is exposed; LND remains unreachable. --- # Disadvantages Compared to Cloudflare Tunnel ### ❌ No Integrated Access Control Cloudflare’s Service Tokens provide elegant authorization. Tor + socat relies on LND’s inherent authentication, which is strong but not policy-based. ### ❌ Higher Latency Tor paths increase latency slightly, although this is irrelevant for Lightning gossip and peer maintenance. ### ❌ More Operational Complexity Requires Docker, health checks, and Tor maintenance. Cloudflare’s solution is plug-and-play. ### ❌ VPS Sees Connection Metadata It cannot identify your LND, but it sees: - number of incoming connections - timing patterns - clearnet origin IPs Mitigations require additional layers if desired. --- # Final Evaluation Both the Cloudflare and the Tor-based approaches achieve the same goal: providing a stable clearnet endpoint for your Lightning node without exposing the node itself to the internet. The **Cloudflare solution** favors convenience, centralized control, and access management. The **Tor solution** favors privacy, sovereignty, decentralization, and resilience to third-party outages. For operators who value independence and censorship resistance, the Tor + socat architecture is a strong upgrade, fully eliminating proprietary dependencies while maintaining robust Lightning connectivity. --- # References 1. Original Cloudflare-based article (Habla.news): https://habla.news/a/naddr1qvzqqqr4gupzq0l6cwnvsk0242xdmkevwqp2dcgtx0h7hyksykc5att03gkk2ejhqqxnzde58yun2wpjxyerwd33tr0ph4 2. Tor Project – Tor Documentation https://community.torproject.org/ 3. Socat manual (Linux man pages) https://linux.die.net/man/1/socat 4. Lightning Network Specification https://github.com/lightning/bolts 5. LND Documentation https://docs.lightning.engineering/ 6. Autoheal Docker Project https://github.com/willfarrell/docker-autoheal

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.