# Cloudflare Tunnel Setup for RPC Endpoints

**Last Updated:** 2025-12-21  
**Status:** Configuration Guide

---

## Overview

This guide explains how to set up Cloudflare Tunnel for the RPC endpoints with Nginx SSL termination. This provides additional security, DDoS protection, and hides your origin server IPs.

---

## Architecture Options

### Option 1: Direct Tunnel to Nginx (Recommended)

```
Internet → Cloudflare → Tunnel → cloudflared → Nginx (443) → Besu RPC (8545/8546)
```

**Benefits:**
- Direct connection to Nginx on each RPC container
- SSL termination at Nginx level
- Simpler architecture
- Better performance (fewer hops)

### Option 2: Tunnel via nginx-proxy-manager

```
Internet → Cloudflare → Tunnel → cloudflared → nginx-proxy-manager → Nginx → Besu RPC
```

**Benefits:**
- Centralized management
- Additional routing layer
- Useful if you have many services

**This guide focuses on Option 1 (Direct Tunnel to Nginx).**

---

## Prerequisites

1. ✅ **Nginx installed** on RPC containers (2501, 2502) - Already done
2. ✅ **SSL certificates** configured - Already done
3. **Cloudflare account** with Zero Trust enabled
4. **Domain** `d-bis.org` managed by Cloudflare
5. **cloudflared container** (VMID 102 or create new one)

---

## Step 1: Create Cloudflare Tunnel

### 1.1 Create Tunnel in Cloudflare Dashboard

1. **Access Cloudflare Zero Trust:**
   - Navigate to: https://one.dash.cloudflare.com
   - Sign in with your Cloudflare account

2. **Create Tunnel:**
   - Go to **Zero Trust** → **Networks** → **Tunnels**
   - Click **Create a tunnel**
   - Select **Cloudflared**
   - Enter tunnel name: `rpc-tunnel` (or `proxmox-rpc`)
   - Click **Save tunnel**

3. **Copy Tunnel Token:**
   - After creation, you'll see installation instructions
   - Copy the tunnel token (starts with `eyJ...`)
   - Save it securely - you'll need it in Step 2

---

## Step 2: Deploy/Configure cloudflared

### 2.1 Check Existing cloudflared Container

```bash
# Check if cloudflared container exists (VMID 102)
ssh root@192.168.11.10 "pct status 102"
ssh root@192.168.11.10 "pct exec 102 -- which cloudflared"
```

### 2.2 Install cloudflared (if needed)

If cloudflared is not installed:

```bash
# Install cloudflared on VMID 102
ssh root@192.168.11.10 "pct exec 102 -- bash -c '
  wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
  dpkg -i cloudflared-linux-amd64.deb || apt-get install -f -y
  cloudflared --version
'"
```

### 2.3 Configure Tunnel

**Option A: Using Tunnel Token (Easiest)**

```bash
# Install tunnel with token
ssh root@192.168.11.10 "pct exec 102 -- cloudflared service install <YOUR_TUNNEL_TOKEN>"

# Start service
ssh root@192.168.11.10 "pct exec 102 -- systemctl enable cloudflared"
ssh root@192.168.11.10 "pct exec 102 -- systemctl start cloudflared"
```

**Option B: Using Config File (More Control)**

Create tunnel configuration file:

```bash
ssh root@192.168.11.10 "pct exec 102 -- bash" <<'EOF'
cat > /etc/cloudflared/config.yml <<'CONFIG'
tunnel: <YOUR_TUNNEL_ID>
credentials-file: /etc/cloudflared/credentials.json

ingress:
  # Public HTTP RPC
  - hostname: rpc-http-pub.d-bis.org
    service: https://192.168.11.251:443
    originRequest:
      noHappyEyeballs: true
      connectTimeout: 30s
      tcpKeepAlive: 30s
      keepAliveConnections: 100
      keepAliveTimeout: 90s

  # Public WebSocket RPC
  - hostname: rpc-ws-pub.d-bis.org
    service: https://192.168.11.251:443
    originRequest:
      noHappyEyeballs: true
      connectTimeout: 30s
      tcpKeepAlive: 30s
      keepAliveConnections: 100
      keepAliveTimeout: 90s

  # Private HTTP RPC
  - hostname: rpc-http-prv.d-bis.org
    service: https://192.168.11.252:443
    originRequest:
      noHappyEyeballs: true
      connectTimeout: 30s
      tcpKeepAlive: 30s
      keepAliveConnections: 100
      keepAliveTimeout: 90s

  # Private WebSocket RPC
  - hostname: rpc-ws-prv.d-bis.org
    service: https://192.168.11.252:443
    originRequest:
      noHappyEyeballs: true
      connectTimeout: 30s
      tcpKeepAlive: 30s
      keepAliveConnections: 100
      keepAliveTimeout: 90s

  # Catch-all (must be last)
  - service: http_status:404
CONFIG

# Set permissions
chmod 600 /etc/cloudflared/config.yml
EOF
```

**Important Notes:**
- Use `https://` (not `http://`) because Nginx is listening on port 443 with SSL
- The tunnel will handle SSL termination at Cloudflare edge
- Nginx will still receive HTTPS traffic (or you can configure it to accept HTTP from tunnel)

---

## Step 3: Configure Tunnel in Cloudflare Dashboard

### 3.1 Add Public Hostnames

In Cloudflare Zero Trust → Networks → Tunnels → Your Tunnel → Configure:

**Add each hostname:**

1. **rpc-http-pub.d-bis.org**
   - **Subdomain:** `rpc-http-pub`
   - **Domain:** `d-bis.org`
   - **Service:** `https://192.168.11.251:443`
   - **Type:** HTTP
   - Click **Save hostname**

2. **rpc-ws-pub.d-bis.org**
   - **Subdomain:** `rpc-ws-pub`
   - **Domain:** `d-bis.org`
   - **Service:** `https://192.168.11.251:443`
   - **Type:** HTTP
   - **WebSocket:** Enable (if available)
   - Click **Save hostname**

3. **rpc-http-prv.d-bis.org**
   - **Subdomain:** `rpc-http-prv`
   - **Domain:** `d-bis.org`
   - **Service:** `https://192.168.11.252:443`
   - **Type:** HTTP
   - Click **Save hostname**

4. **rpc-ws-prv.d-bis.org**
   - **Subdomain:** `rpc-ws-prv`
   - **Domain:** `d-bis.org`
   - **Service:** `https://192.168.11.252:443`
   - **Type:** HTTP
   - **WebSocket:** Enable (if available)
   - Click **Save hostname**

---

## Step 4: Configure DNS Records

### 4.1 Update DNS Records to Use Tunnel

**Change from A records to CNAME records pointing to tunnel:**

In Cloudflare DNS Dashboard:

1. **Delete existing A records** (if any):
   - `rpc-http-pub.d-bis.org` → A → 192.168.11.251
   - `rpc-ws-pub.d-bis.org` → A → 192.168.11.251
   - `rpc-http-prv.d-bis.org` → A → 192.168.11.252
   - `rpc-ws-prv.d-bis.org` → A → 192.168.11.252

2. **Create CNAME records:**

| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | `rpc-http-pub` | `<tunnel-id>.cfargotunnel.com` | 🟠 Proxied | Auto |
| CNAME | `rpc-ws-pub` | `<tunnel-id>.cfargotunnel.com` | 🟠 Proxied | Auto |
| CNAME | `rpc-http-prv` | `<tunnel-id>.cfargotunnel.com` | 🟠 Proxied | Auto |
| CNAME | `rpc-ws-prv` | `<tunnel-id>.cfargotunnel.com` | 🟠 Proxied | Auto |

**Where `<tunnel-id>` is your tunnel ID (e.g., `abc123def456`).**

**Example:**
```
Type: CNAME
Name: rpc-http-pub
Target: abc123def456.cfargotunnel.com
Proxy: 🟠 Proxied (orange cloud)
TTL: Auto
```

**Important:**
- ✅ **Proxy must be enabled** (orange cloud) for tunnel to work
- ✅ Use CNAME records (not A records) when using tunnels
- ✅ Target format: `<tunnel-id>.cfargotunnel.com`

---

## Step 5: Update Nginx Configuration (Optional)

### 5.1 Option A: Keep HTTPS (Recommended)

Nginx continues to use HTTPS. The tunnel will:
- Terminate SSL at Cloudflare edge
- Forward HTTPS to Nginx
- Nginx handles SSL again (double SSL - acceptable but not optimal)

### 5.2 Option B: Use HTTP from Tunnel (More Efficient)

If you want to avoid double SSL, configure Nginx to accept HTTP from the tunnel:

**Update Nginx config on each container:**

```bash
# On VMID 2501 and 2502
ssh root@192.168.11.10 "pct exec 2501 -- bash" <<'EOF'
# Add HTTP server block for tunnel traffic
cat >> /etc/nginx/sites-available/rpc <<'NGINX_HTTP'
# HTTP server for Cloudflare Tunnel (no SSL needed)
server {
    listen 80;
    listen [::]:80;
    server_name rpc-http-pub.d-bis.org rpc-ws-pub.d-bis.org;

    # Trust Cloudflare IPs
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 131.0.72.0/22;
    real_ip_header CF-Connecting-IP;

    access_log /var/log/nginx/rpc-tunnel-access.log;
    error_log /var/log/nginx/rpc-tunnel-error.log;

    # HTTP RPC endpoint
    location / {
        if ($host = rpc-http-pub.d-bis.org) {
            proxy_pass http://127.0.0.1:8545;
        }
        if ($host = rpc-ws-pub.d-bis.org) {
            proxy_pass http://127.0.0.1:8546;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
    }
}
NGINX_HTTP

nginx -t && systemctl reload nginx
EOF
```

**Then update tunnel config to use HTTP:**
```yaml
ingress:
  - hostname: rpc-http-pub.d-bis.org
    service: http://192.168.11.251:80  # Changed from https://443
```

**Recommendation:** Keep HTTPS (Option A) for simplicity and security.

---

## Step 6: Verify Configuration

### 6.1 Check Tunnel Status

```bash
# Check cloudflared service
ssh root@192.168.11.10 "pct exec 102 -- systemctl status cloudflared"

# View tunnel logs
ssh root@192.168.11.10 "pct exec 102 -- journalctl -u cloudflared -f"
```

**In Cloudflare Dashboard:**
- Go to Zero Trust → Networks → Tunnels
- Tunnel status should show "Healthy" (green)

### 6.2 Test DNS Resolution

```bash
# Test DNS resolution
dig rpc-http-pub.d-bis.org
nslookup rpc-http-pub.d-bis.org

# Should resolve to Cloudflare IPs (if proxied)
```

### 6.3 Test Endpoints

```bash
# Test HTTP RPC endpoint
curl https://rpc-http-pub.d-bis.org/health
curl -X POST https://rpc-http-pub.d-bis.org \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# Test WebSocket RPC endpoint
wscat -c wss://rpc-ws-pub.d-bis.org
```

---

## Benefits of Using Cloudflare Tunnel

1. **🔒 Security:**
   - Origin IPs hidden from public
   - No need to expose ports on firewall
   - DDoS protection at Cloudflare edge

2. **⚡ Performance:**
   - Global CDN (though RPC responses shouldn't be cached)
   - Reduced latency for global users
   - Automatic SSL/TLS at edge

3. **🛡️ DDoS Protection:**
   - Cloudflare automatically mitigates attacks
   - Rate limiting available
   - Bot protection

4. **📊 Analytics:**
   - Traffic analytics in Cloudflare dashboard
   - Request logs
   - Security events

5. **🔧 Management:**
   - Centralized tunnel management
   - Easy to add/remove routes
   - No firewall changes needed

---

## Troubleshooting

### Tunnel Not Connecting

**Symptoms:** Tunnel shows "Unhealthy" in dashboard

**Solutions:**
```bash
# Check cloudflared service
pct exec 102 -- systemctl status cloudflared

# View logs
pct exec 102 -- journalctl -u cloudflared -n 50

# Verify credentials
pct exec 102 -- cat /etc/cloudflared/credentials.json

# Test tunnel connection
pct exec 102 -- cloudflared tunnel info
```

### DNS Not Resolving

**Symptoms:** Domain doesn't resolve or resolves incorrectly

**Solutions:**
1. Verify DNS record type is CNAME (not A)
2. Verify proxy is enabled (orange cloud)
3. Verify target is correct: `<tunnel-id>.cfargotunnel.com`
4. Wait for DNS propagation (up to 5 minutes)

### Connection Timeout

**Symptoms:** DNS resolves but connection times out

**Solutions:**
```bash
# Check if Nginx is running
pct exec 2501 -- systemctl status nginx

# Check if port 443 is listening
pct exec 2501 -- ss -tuln | grep 443

# Test direct connection (bypassing tunnel)
curl -k https://192.168.11.251/health

# Check tunnel config
pct exec 102 -- cat /etc/cloudflared/config.yml
```

### SSL Certificate Errors

**Symptoms:** SSL certificate warnings

**Solutions:**
1. If using self-signed certs, clients will see warnings (expected)
2. Consider using Let's Encrypt certificates
3. Or rely on Cloudflare SSL (terminate at edge, use HTTP internally)

---

## Architecture Summary

### Request Flow with Tunnel

1. **Client** → `https://rpc-http-pub.d-bis.org`
2. **DNS** → Resolves to Cloudflare IPs (via CNAME to tunnel)
3. **Cloudflare Edge** → SSL termination, DDoS protection
4. **Cloudflare Tunnel** → Encrypted connection to cloudflared
5. **cloudflared (VMID 102)** → Forwards to `https://192.168.11.251:443`
6. **Nginx (VMID 2501)** → Receives HTTPS, routes to `127.0.0.1:8545`
7. **Besu RPC** → Processes request, returns response
8. **Response** → Reverse path back to client

---

## Quick Reference

**Tunnel Configuration:**
```yaml
ingress:
  - hostname: rpc-http-pub.d-bis.org
    service: https://192.168.11.251:443
  - hostname: rpc-ws-pub.d-bis.org
    service: https://192.168.11.251:443
  - hostname: rpc-http-prv.d-bis.org
    service: https://192.168.11.252:443
  - hostname: rpc-ws-prv.d-bis.org
    service: https://192.168.11.252:443
  - service: http_status:404
```

**DNS Records:**
```
rpc-http-pub.d-bis.org → CNAME → <tunnel-id>.cfargotunnel.com (🟠 Proxied)
rpc-ws-pub.d-bis.org → CNAME → <tunnel-id>.cfargotunnel.com (🟠 Proxied)
rpc-http-prv.d-bis.org → CNAME → <tunnel-id>.cfargotunnel.com (🟠 Proxied)
rpc-ws-prv.d-bis.org → CNAME → <tunnel-id>.cfargotunnel.com (🟠 Proxied)
```

---

## Related Documentation

- [RPC_DNS_CONFIGURATION.md](/docs/04-configuration/RPC_DNS_CONFIGURATION.md) - Direct DNS configuration
- [CLOUDFLARE_DNS_TO_CONTAINERS.md](CLOUDFLARE_DNS_TO_CONTAINERS.md) - General tunnel setup
- [CLOUDFLARE_NGINX_INTEGRATION.md](../05-network/CLOUDFLARE_NGINX_INTEGRATION.md) - Nginx integration

