#!/usr/bin/env bash # Fix RPC configuration for Thirdweb on VMID 2400 # - Update Nginx to handle both HTTP and WebSocket on port 443 # - Update tunnel route to point to Nginx # - Enable EIP-7702 support in Besu if available # # Usage: ./scripts/fix-rpc-thirdweb-config.sh set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # Configuration VMID=2400 PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}" TUNNEL_ID="26138c21-db00-4a02-95db-ec75c07bda5b" HOSTNAME="rpc.public-0138.defi-oracle.io" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_info "═══════════════════════════════════════════════════════════" log_info " FIXING RPC CONFIGURATION FOR THIRDWEB (VMID 2400)" log_info "═══════════════════════════════════════════════════════════" echo "" # Check SSH access log_info "Checking SSH access..." if ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "echo 'SSH OK'" &>/dev/null; then log_error "Cannot access $PROXMOX_HOST via SSH" exit 1 fi log_success "SSH access confirmed" # Step 1: Update Nginx configuration to handle both HTTP and WebSocket on port 443 log_info "Step 1: Updating Nginx configuration..." ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \ "pct exec $VMID -- bash" << 'NGINX_FIX_EOF' # Backup current config cp /etc/nginx/sites-available/rpc-thirdweb /etc/nginx/sites-available/rpc-thirdweb.backup.$(date +%Y%m%d_%H%M%S) # Create updated Nginx configuration cat > /etc/nginx/sites-available/rpc-thirdweb << 'NGINX_EOF' # HTTP to HTTPS redirect server { listen 80; listen [::]:80; server_name rpc.public-0138.defi-oracle.io; # Redirect all HTTP to HTTPS return 301 https://$host$request_uri; } # HTTPS server - HTTP RPC API (port 8545) and WebSocket RPC (port 8546) server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name rpc.public-0138.defi-oracle.io; # Cloudflare Origin Certificate ssl_certificate /etc/nginx/ssl/cloudflare-origin.crt; ssl_certificate_key /etc/nginx/ssl/cloudflare-origin.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Trust Cloudflare IPs for real IP 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; # Logging access_log /var/log/nginx/rpc-thirdweb-access.log; error_log /var/log/nginx/rpc-thirdweb-error.log; # Increase timeouts for RPC calls proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; send_timeout 300s; client_max_body_size 10M; # WebSocket RPC endpoint (port 8546) - handles WebSocket upgrade requests location / { # Check for WebSocket upgrade set $ws_backend "http://127.0.0.1:8545"; if ($http_upgrade) { set $ws_backend "http://127.0.0.1:8546"; } proxy_pass $ws_backend; proxy_http_version 1.1; # WebSocket headers proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; # Ensure Connection header is set correctly for WebSocket if ($http_upgrade != '') { proxy_set_header Connection "upgrade"; } 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_set_header CF-Connecting-IP $http_cf_connecting_ip; proxy_set_header CF-Ray $http_cf_ray; proxy_buffering off; proxy_request_buffering off; # Extended timeouts (especially for WebSocket) proxy_read_timeout 86400; proxy_send_timeout 86400; proxy_connect_timeout 300s; # CORS headers (for ThirdWeb web apps) add_header Access-Control-Allow-Origin "*" always; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; add_header Access-Control-Allow-Headers "Content-Type, Authorization" always; # Handle OPTIONS requests if ($request_method = OPTIONS) { return 204; } } # Health check endpoint location /health { access_log off; return 200 "healthy\n"; add_header Content-Type text/plain; } } NGINX_EOF # Test configuration if nginx -t 2>&1; then echo "SUCCESS" else echo "FAILED" exit 1 fi # Reload Nginx systemctl reload nginx NGINX_FIX_EOF if [[ $? -eq 0 ]]; then log_success "Nginx configuration updated" else log_error "Failed to update Nginx configuration" exit 1 fi # Step 2: Update Cloudflare Tunnel route to point to Nginx (port 80) log_info "Step 2: Updating Cloudflare Tunnel route..." ENV_FILE="$PROJECT_ROOT/.env" if [ -f "$ENV_FILE" ]; then source "$ENV_FILE" fi CLOUDFLARE_ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-}" CLOUDFLARE_API_KEY="${CLOUDFLARE_API_KEY:-}" CLOUDFLARE_EMAIL="${CLOUDFLARE_EMAIL:-}" CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}" if [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then log_error "CLOUDFLARE_ACCOUNT_ID not set in .env" exit 1 fi # Determine auth method if [ -n "$CLOUDFLARE_API_TOKEN" ]; then AUTH_HEADERS=(-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN") elif [ -n "$CLOUDFLARE_API_KEY" ] && [ -n "$CLOUDFLARE_EMAIL" ]; then AUTH_HEADERS=(-H "X-Auth-Email: $CLOUDFLARE_EMAIL" -H "X-Auth-Key: $CLOUDFLARE_API_KEY") else log_error "No Cloudflare API credentials found" exit 1 fi # Get current tunnel configuration log_info "Fetching current tunnel configuration..." CURRENT_CONFIG=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/cfd_tunnel/$TUNNEL_ID/configurations" \ "${AUTH_HEADERS[@]}" \ -H "Content-Type: application/json") if ! echo "$CURRENT_CONFIG" | jq -e '.success' >/dev/null 2>&1; then log_error "Failed to fetch tunnel configuration" exit 1 fi # Extract current ingress rules CURRENT_INGRESS=$(echo "$CURRENT_CONFIG" | jq -c '.result.config.ingress // []') # Update the RPC route to point to Nginx (port 80) instead of directly to Besu log_info "Updating tunnel route: $HOSTNAME → http://127.0.0.1:80 (Nginx)" CURRENT_INGRESS=$(echo "$CURRENT_INGRESS" | jq "[.[] | if .hostname == \"$HOSTNAME\" then .service = \"http://127.0.0.1:80\" else . end]") # Separate catch-all from other rules CATCH_ALL=$(echo "$CURRENT_INGRESS" | jq '[.[] | select(.hostname == null or .hostname == "" or (.service | startswith("http_status")))]') OTHER_ROUTES=$(echo "$CURRENT_INGRESS" | jq '[.[] | select(.hostname != null and .hostname != "" and (.service | startswith("http_status") | not))]') # Build new ingress if [ "$(echo "$CATCH_ALL" | jq 'length')" -eq 0 ]; then CATCH_ALL='[{"service":"http_status:404"}]' fi NEW_INGRESS=$(jq -n --argjson routes "$OTHER_ROUTES" --argjson catchall "$CATCH_ALL" '$routes + $catchall') # Build complete config NEW_CONFIG=$(jq -n \ --argjson ingress "$NEW_INGRESS" \ '{ config: { ingress: $ingress } }') # Update tunnel configuration RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/cfd_tunnel/$TUNNEL_ID/configurations" \ "${AUTH_HEADERS[@]}" \ -H "Content-Type: application/json" \ --data "$NEW_CONFIG") if echo "$RESPONSE" | jq -e '.success' >/dev/null 2>&1; then log_success "Tunnel route updated: $HOSTNAME → http://127.0.0.1:80" else ERROR=$(echo "$RESPONSE" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null || echo "API call failed") log_error "Failed to update tunnel route: $ERROR" exit 1 fi # Step 3: Check and enable EIP-7702 support in Besu log_info "Step 3: Checking EIP-7702 support in Besu..." BESU_CONFIG="/etc/besu/config-rpc-thirdweb.toml" # Check if EIP-7702 is already configured EIP_7702_CHECK=$(ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \ "pct exec $VMID -- grep -i '7702\|eip-7702' $BESU_CONFIG 2>/dev/null || echo 'not found'") if [[ "$EIP_7702_CHECK" == "not found" ]]; then log_info "EIP-7702 not found in config. Checking Besu version..." # Check Besu version - EIP-7702 support was added in Besu 24.1.0 BESU_VERSION=$(ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \ "pct exec $VMID -- java -jar /opt/besu/lib/besu-*.jar --version 2>&1 | grep -oP 'besu/v\\K[0-9.]+' | head -1" 2>/dev/null || echo "unknown") if [[ "$BESU_VERSION" != "unknown" ]]; then log_info "Besu version: $BESU_VERSION" # Check if version >= 24.1.0 VERSION_MAJOR=$(echo "$BESU_VERSION" | cut -d. -f1) VERSION_MINOR=$(echo "$BESU_VERSION" | cut -d. -f2) if [[ $VERSION_MAJOR -gt 24 ]] || [[ $VERSION_MAJOR -eq 24 && $VERSION_MINOR -ge 1 ]]; then log_info "Besu version supports EIP-7702. Adding configuration..." # Add EIP-7702 to genesis or config # Note: EIP-7702 is typically enabled via genesis file or fork configuration # For now, we'll document that it needs to be enabled in the genesis file log_warn "EIP-7702 needs to be enabled in the genesis file (cancun fork or later)" log_info "Current network uses ChainID 138. EIP-7702 requires Cancun fork or later." else log_warn "Besu version $BESU_VERSION may not support EIP-7702 (requires 24.1.0+)" fi else log_warn "Could not determine Besu version" fi else log_success "EIP-7702 already configured" fi # Summary echo "" log_success "═══════════════════════════════════════════════════════════" log_success " RPC CONFIGURATION FIXED" log_success "═══════════════════════════════════════════════════════════" echo "" log_info "✅ Nginx updated to handle HTTP and WebSocket on port 443" log_info "✅ Tunnel route updated to point to Nginx (port 80)" log_info "✅ EIP-7702 status checked" echo "" log_info "Next steps:" echo " 1. Test HTTP RPC:" echo " curl -k https://rpc.public-0138.defi-oracle.io \\" echo " -X POST -H 'Content-Type: application/json' \\" echo " -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":1}'" echo "" echo " 2. Test WebSocket RPC (requires WebSocket client)" echo "" echo " 3. For EIP-7702: Ensure genesis file includes Cancun fork or later" echo ""