#!/usr/bin/env bash # Add ingress rule for VMID 2400 Cloudflare Tunnel # Usage: ./add-vmid2400-ingress.sh set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR/.." # Load environment variables (set +u so values with $ in them don't trigger unbound variable) if [[ -f ".env" ]]; then set +u # shellcheck source=/dev/null source .env 2>/dev/null || true set -u fi # Tunnel configuration TUNNEL_ID="26138c21-db00-4a02-95db-ec75c07bda5b" HOSTNAME="rpc.public-0138.defi-oracle.io" SERVICE="http://127.0.0.1:8545" # Cloudflare API configuration CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}" CLOUDFLARE_ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-}" CLOUDFLARE_EMAIL="${CLOUDFLARE_EMAIL:-}" CLOUDFLARE_API_KEY="${CLOUDFLARE_API_KEY:-}" # Colors GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } # Check for required tools if ! command -v curl >/dev/null 2>&1; then error "curl is required" exit 1 fi if ! command -v jq >/dev/null 2>&1; then error "jq is required. Install with: apt-get install jq" exit 1 fi # Validate credentials if [[ -z "$CLOUDFLARE_API_TOKEN" ]] && [[ -z "$CLOUDFLARE_ACCOUNT_ID" ]]; then if [[ -z "$CLOUDFLARE_API_KEY" ]] || [[ -z "$CLOUDFLARE_EMAIL" ]]; then error "Cloudflare API credentials not found!" error "Set CLOUDFLARE_API_TOKEN or CLOUDFLARE_EMAIL + CLOUDFLARE_API_KEY in .env" exit 1 fi fi # Get account ID if not set if [[ -z "$CLOUDFLARE_ACCOUNT_ID" ]]; then info "Getting account ID..." if [[ -n "$CLOUDFLARE_API_TOKEN" ]]; then RESPONSE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ -H "Content-Type: application/json") CLOUDFLARE_ACCOUNT_ID=$(echo "$RESPONSE" | jq -r '.result.id // empty' 2>/dev/null || echo "") if [[ -z "$CLOUDFLARE_ACCOUNT_ID" ]]; then # Try getting from accounts list RESPONSE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts" \ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ -H "Content-Type: application/json") CLOUDFLARE_ACCOUNT_ID=$(echo "$RESPONSE" | jq -r '.result[0].id // empty' 2>/dev/null || echo "") fi fi if [[ -z "$CLOUDFLARE_ACCOUNT_ID" ]]; then error "Could not determine account ID" error "Please set CLOUDFLARE_ACCOUNT_ID in .env file" exit 1 fi fi info "Account ID: $CLOUDFLARE_ACCOUNT_ID" info "Tunnel ID: $TUNNEL_ID" # Get current tunnel configuration info "Fetching current tunnel configuration..." if [[ -n "$CLOUDFLARE_API_TOKEN" ]]; then AUTH_HEADER="Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" else AUTH_HEADER="X-Auth-Email: ${CLOUDFLARE_EMAIL}" AUTH_KEY_HEADER="X-Auth-Key: ${CLOUDFLARE_API_KEY}" fi CURRENT_CONFIG=$(curl -s -X GET \ "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/cfd_tunnel/${TUNNEL_ID}/configurations" \ -H "$AUTH_HEADER" \ ${AUTH_KEY_HEADER:+-H "$AUTH_KEY_HEADER"} \ -H "Content-Type: application/json") # Check if we got valid response if ! echo "$CURRENT_CONFIG" | jq -e . >/dev/null 2>&1; then error "Failed to fetch tunnel configuration" error "Response: $CURRENT_CONFIG" exit 1 fi # Extract current ingress rules CURRENT_INGRESS=$(echo "$CURRENT_CONFIG" | jq -r '.result.config.ingress // []' 2>/dev/null || echo "[]") info "Current ingress rules: $(echo "$CURRENT_INGRESS" | jq '. | length')" # Check if rule already exists EXISTING_RULE=$(echo "$CURRENT_INGRESS" | jq -r ".[] | select(.hostname == \"$HOSTNAME\") | .hostname" 2>/dev/null || echo "") if [[ -n "$EXISTING_RULE" ]]; then warn "Ingress rule for $HOSTNAME already exists" info "Updating existing rule..." # Remove existing rule, keep others, ensure catch-all is last UPDATED_INGRESS=$(echo "$CURRENT_INGRESS" | jq \ --arg hostname "$HOSTNAME" \ --arg service "$SERVICE" \ '[.[] | select(.hostname != $hostname and .service != "http_status:404")] + [{"hostname": $hostname, "service": $service, "originRequest": {"noTLSVerify": true}}] + [{"service": "http_status:404"}]') else info "Adding new ingress rule..." # Add new rule, ensure catch-all is last UPDATED_INGRESS=$(echo "$CURRENT_INGRESS" | jq \ --arg hostname "$HOSTNAME" \ --arg service "$SERVICE" \ '[.[] | select(.service != "http_status:404")] + [{"hostname": $hostname, "service": $service, "originRequest": {"noTLSVerify": true}}] + [{"service": "http_status:404"}]') fi # Create config JSON CONFIG_DATA=$(echo "$UPDATED_INGRESS" | jq -c '{ config: { ingress: . } }') info "Updating tunnel configuration..." info "New ingress rules:" echo "$UPDATED_INGRESS" | jq -r '.[] | " - \(.hostname // "catch-all"): \(.service)"' # Update tunnel configuration RESPONSE=$(curl -s -X PUT \ "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/cfd_tunnel/${TUNNEL_ID}/configurations" \ -H "$AUTH_HEADER" \ ${AUTH_KEY_HEADER:+-H "$AUTH_KEY_HEADER"} \ -H "Content-Type: application/json" \ -d "$CONFIG_DATA") # Check response if echo "$RESPONSE" | jq -e '.success == true' >/dev/null 2>&1; then info "✓ Ingress rule added successfully!" info " $HOSTNAME → $SERVICE" echo "" info "Configuration will propagate within 1-2 minutes" info "Test with: curl -X POST https://$HOSTNAME -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":1}'" else error "Failed to add ingress rule" ERRORS=$(echo "$RESPONSE" | jq -r '.errors[]?.message // .error // "Unknown error"' 2>/dev/null | head -3) error "Errors: $ERRORS" error "Response: $RESPONSE" exit 1 fi