#!/usr/bin/env bash # Configure Cloudflare DNS and tunnel for Blockscout Explorer # Usage: ./configure-cloudflare-explorer.sh set -euo pipefail DOMAIN="${DOMAIN:-d-bis.org}" EXPLORER_DOMAIN="explorer.d-bis.org" EXPLORER_IP="${EXPLORER_IP:-192.168.11.140}" EXPLORER_PORT="${EXPLORER_PORT:-80}" # 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"; } # Check for .env file with Cloudflare credentials ENV_FILE="${ENV_FILE:-.env}" if [ ! -f "$ENV_FILE" ]; then log_error "Environment file not found: $ENV_FILE" log_info "Please create $ENV_FILE with:" log_info " CLOUDFLARE_API_TOKEN=your-token" log_info " DOMAIN=d-bis.org" log_info " TUNNEL_TOKEN=your-tunnel-token" exit 1 fi source "$ENV_FILE" if [ -z "${CLOUDFLARE_API_TOKEN:-}" ]; then log_error "CLOUDFLARE_API_TOKEN not set in $ENV_FILE" exit 1 fi log_info "Configuring Cloudflare for Blockscout Explorer" log_info "Domain: $EXPLORER_DOMAIN" log_info "Target: http://$EXPLORER_IP:$EXPLORER_PORT" # Get Zone ID log_info "Getting zone ID for $DOMAIN..." ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" | jq -r '.result[0].id // empty') if [ -z "$ZONE_ID" ] || [ "$ZONE_ID" = "null" ]; then log_error "Failed to get zone ID for $DOMAIN" exit 1 fi log_success "Zone ID: $ZONE_ID" # Extract tunnel ID from tunnel token or configuration TUNNEL_ID="" if [ -n "${TUNNEL_TOKEN:-}" ]; then # Try to extract tunnel ID from token (if it's in the format we expect) TUNNEL_ID=$(echo "$TUNNEL_TOKEN" | base64 -d 2>/dev/null | jq -r '.TunnelID // empty' 2>/dev/null || echo "") fi # If no tunnel ID found, try to get it from Cloudflare API if [ -z "$TUNNEL_ID" ]; then log_info "Getting tunnel information..." ACCOUNT_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" | jq -r '.result[0].id // empty') if [ -n "$ACCOUNT_ID" ] && [ "$ACCOUNT_ID" != "null" ]; then TUNNELS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json") TUNNEL_ID=$(echo "$TUNNELS" | jq -r '.result[0].id // empty' 2>/dev/null || echo "") fi fi # Check if DNS record already exists log_info "Checking for existing DNS record..." EXISTING_RECORD=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$EXPLORER_DOMAIN&type=CNAME" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" | jq -r '.result[0] // empty') if [ -n "$EXISTING_RECORD" ] && [ "$EXISTING_RECORD" != "null" ]; then RECORD_ID=$(echo "$EXISTING_RECORD" | jq -r '.id') log_warn "DNS record already exists (ID: $RECORD_ID)" log_info "Updating existing record..." if [ -n "$TUNNEL_ID" ] && [ "$TUNNEL_ID" != "null" ]; then TARGET="${TUNNEL_ID}.cfargotunnel.com" log_info "Using Cloudflare Tunnel: $TARGET" else TARGET="$EXPLORER_IP" log_warn "No tunnel ID found, using direct IP (may not work behind NAT)" fi UPDATE_RESULT=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ --data "{ \"type\": \"CNAME\", \"name\": \"explorer\", \"content\": \"$TARGET\", \"proxied\": true, \"ttl\": 1 }") SUCCESS=$(echo "$UPDATE_RESULT" | jq -r '.success // false') if [ "$SUCCESS" = "true" ]; then log_success "DNS record updated successfully" else ERROR=$(echo "$UPDATE_RESULT" | jq -r '.errors[0].message // "Unknown error"') log_error "Failed to update DNS record: $ERROR" exit 1 fi else log_info "Creating new DNS record..." if [ -n "$TUNNEL_ID" ] && [ "$TUNNEL_ID" != "null" ]; then TARGET="${TUNNEL_ID}.cfargotunnel.com" RECORD_TYPE="CNAME" log_info "Using Cloudflare Tunnel: $TARGET" else TARGET="$EXPLORER_IP" RECORD_TYPE="A" log_warn "No tunnel ID found, using A record with direct IP (may not work behind NAT)" fi CREATE_RESULT=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ --data "{ \"type\": \"$RECORD_TYPE\", \"name\": \"explorer\", \"content\": \"$TARGET\", \"proxied\": true, \"ttl\": 1 }") SUCCESS=$(echo "$CREATE_RESULT" | jq -r '.success // false') if [ "$SUCCESS" = "true" ]; then log_success "DNS record created successfully" else ERROR=$(echo "$CREATE_RESULT" | jq -r '.errors[0].message // "Unknown error"') log_error "Failed to create DNS record: $ERROR" exit 1 fi fi # If we have a tunnel, configure the tunnel route if [ -n "$TUNNEL_ID" ] && [ "$TUNNEL_ID" != "null" ] && [ -n "${ACCOUNT_ID:-}" ]; then log_info "Configuring Cloudflare Tunnel route..." # Get current tunnel configuration TUNNEL_CONFIG=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel/$TUNNEL_ID/config" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json") # This is complex - for now, log instructions log_info "" log_info "=== Cloudflare Tunnel Configuration Required ===" log_info "" log_info "Please configure the tunnel route manually in Cloudflare Zero Trust Dashboard:" log_info " 1. Go to: https://one.dash.cloudflare.com/" log_info " 2. Navigate to: Zero Trust → Networks → Tunnels" log_info " 3. Select your tunnel (ID: $TUNNEL_ID)" log_info " 4. Click 'Configure' → 'Public Hostnames'" log_info " 5. Add hostname:" log_info " - Subdomain: explorer" log_info " - Domain: $DOMAIN" log_info " - Service: http://$EXPLORER_IP:$EXPLORER_PORT" log_info " - Type: HTTP" log_info "" fi log_success "Cloudflare configuration complete!" log_info "" log_info "Summary:" log_info " - DNS Record: $EXPLORER_DOMAIN → $TARGET (🟠 Proxied)" if [ -n "$TUNNEL_ID" ]; then log_info " - Tunnel ID: $TUNNEL_ID" log_info " - Tunnel Route: Needs manual configuration (see above)" fi log_info "" log_info "Next steps:" log_info " 1. Wait for DNS propagation (1-5 minutes)" log_info " 2. Test: curl -I https://$EXPLORER_DOMAIN"