Files
proxmox/scripts/configure-cloudflare-explorer-complete-auto.sh
defiQUG cb47cce074 Complete markdown files cleanup and organization
- Organized 252 files across project
- Root directory: 187 → 2 files (98.9% reduction)
- Moved configuration guides to docs/04-configuration/
- Moved troubleshooting guides to docs/09-troubleshooting/
- Moved quick start guides to docs/01-getting-started/
- Moved reports to reports/ directory
- Archived temporary files
- Generated comprehensive reports and documentation
- Created maintenance scripts and guides

All files organized according to established standards.
2026-01-06 01:46:25 -08:00

400 lines
14 KiB
Bash
Executable File

#!/bin/bash
# Complete Cloudflare Configuration for Explorer - Automated
# Uses .env credentials to configure DNS, SSL, and tunnel routes
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
log_error() { echo -e "${RED}[✗]${NC} $1"; }
log_section() { echo -e "${CYAN}════════════════════════════════════════${NC}"; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="${ENV_FILE:-$SCRIPT_DIR/../.env}"
# Configuration
DOMAIN="${DOMAIN:-d-bis.org}"
EXPLORER_DOMAIN="explorer.d-bis.org"
EXPLORER_IP="${EXPLORER_IP:-192.168.11.140}"
EXPLORER_PORT="${EXPLORER_PORT:-80}"
VMID=5000
PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}"
TUNNEL_TOKEN="eyJhIjoiNTJhZDU3YTcxNjcxYzVmYzAwOWVkZjA3NDQ2NTgxOTYiLCJ0IjoiYjAyZmUxZmUtY2I3ZC00ODRlLTkwOWItN2NjNDEyOThlYmU4IiwicyI6Ik5HTmtOV0kwWXpNdFpUVmxaUzAwTVRFMkxXRXdNMk10WlRJNU1ETTFaRFF4TURBMiJ9"
echo ""
log_section
log_info " COMPLETE CLOUDFLARE EXPLORER CONFIGURATION"
log_info " Using .env Credentials for Full Automation"
log_section
echo ""
# Step 1: Load .env file
log_info "Step 1: Loading credentials from .env file..."
if [ ! -f "$ENV_FILE" ]; then
log_error ".env file not found: $ENV_FILE"
log_info "Looking for .env files..."
find "$SCRIPT_DIR/.." -maxdepth 2 -name ".env" -type f 2>/dev/null | head -3
log_info ""
log_info "Please create .env file with:"
echo " CLOUDFLARE_API_TOKEN=your-token"
echo " CLOUDFLARE_ZONE_ID=your-zone-id (optional)"
echo " CLOUDFLARE_ACCOUNT_ID=your-account-id (optional)"
echo " DOMAIN=d-bis.org"
exit 1
fi
# Source .env file
set -a
source "$ENV_FILE"
set +a
log_success ".env file loaded"
# Check for required credentials
CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}"
CLOUDFLARE_API_KEY="${CLOUDFLARE_API_KEY:-}"
CLOUDFLARE_EMAIL="${CLOUDFLARE_EMAIL:-}"
CLOUDFLARE_ZONE_ID="${CLOUDFLARE_ZONE_ID:-}"
CLOUDFLARE_ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-}"
# Determine auth method
AUTH_METHOD=""
AUTH_HEADERS=()
# Check for API_TOKEN first (preferred), then API_KEY
if [ -n "$CLOUDFLARE_API_TOKEN" ]; then
AUTH_METHOD="token"
AUTH_HEADERS=(-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN")
log_success "Using API Token authentication"
elif [ -n "$CLOUDFLARE_API_KEY" ] && [ -n "$CLOUDFLARE_EMAIL" ]; then
AUTH_METHOD="key"
# Remove quotes from API_KEY if present
CLOUDFLARE_API_KEY=$(echo "$CLOUDFLARE_API_KEY" | tr -d '"')
CLOUDFLARE_EMAIL=$(echo "$CLOUDFLARE_EMAIL" | tr -d '"')
AUTH_HEADERS=(-H "X-Auth-Email: $CLOUDFLARE_EMAIL" -H "X-Auth-Key: $CLOUDFLARE_API_KEY")
log_success "Using API Key authentication"
else
log_error "No Cloudflare API credentials found in .env"
log_info "Required: CLOUDFLARE_API_TOKEN or (CLOUDFLARE_API_KEY + CLOUDFLARE_EMAIL)"
exit 1
fi
# Function to find container node
find_container_node() {
ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \
"for node in ml110 pve pve2; do if pvesh get /nodes/\$node/lxc/$VMID/status/current --output-format json >/dev/null 2>&1; then echo \$node; break; fi; done" 2>/dev/null || echo "pve2"
}
# Function to execute command in container
exec_container() {
local cmd="$1"
# Try direct pct exec via main host first
ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" "pct exec $VMID -- bash -c '$cmd'" 2>&1
}
# Step 2: Install Cloudflare Tunnel Service
log_section
log_info "Step 2: Installing Cloudflare Tunnel Service"
log_section
log_info "Checking cloudflared installation..."
if ! exec_container "command -v cloudflared >/dev/null 2>&1"; then
log_info "Installing cloudflared..."
exec_container "cd /tmp && wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && dpkg -i cloudflared-linux-amd64.deb || apt install -f -y"
log_success "cloudflared installed"
else
log_success "cloudflared already installed"
fi
log_info "Installing tunnel service with token..."
INSTALL_OUTPUT=$(exec_container "cloudflared service install $TUNNEL_TOKEN 2>&1" || echo "INSTALL_FAILED")
if echo "$INSTALL_OUTPUT" | grep -q -E "successfully|installed|Service installed"; then
log_success "Tunnel service installed"
else
log_warn "Installation output: $INSTALL_OUTPUT"
# Continue - service might already be installed
fi
log_info "Starting cloudflared service..."
exec_container "systemctl start cloudflared" || true
exec_container "systemctl enable cloudflared" || true
sleep 3
CLOUDFLARED_STATUS=$(exec_container "systemctl is-active cloudflared 2>/dev/null || echo 'inactive'")
if [ "$CLOUDFLARED_STATUS" = "active" ]; then
log_success "Cloudflared service is running"
else
log_warn "Cloudflared service is $CLOUDFLARED_STATUS"
fi
# Get tunnel ID
log_info "Getting tunnel ID..."
TUNNEL_LIST=$(exec_container "cloudflared tunnel list 2>&1" || echo "")
TUNNEL_ID=$(echo "$TUNNEL_LIST" | grep -v "NAME" | head -1 | awk '{print $1}' || echo "")
if [ -n "$TUNNEL_ID" ]; then
log_success "Tunnel ID: $TUNNEL_ID"
else
log_warn "Could not get tunnel ID from tunnel list"
# Try to extract from token (base64 decode)
TUNNEL_ID=$(echo "$TUNNEL_TOKEN" | base64 -d 2>/dev/null | jq -r '.TunnelID // empty' 2>/dev/null || echo "")
if [ -n "$TUNNEL_ID" ]; then
log_success "Tunnel ID from token: $TUNNEL_ID"
else
log_error "Cannot determine tunnel ID"
exit 1
fi
fi
# Step 3: Get Zone ID
log_section
log_info "Step 3: Getting Cloudflare Zone ID"
log_section
if [ -z "$CLOUDFLARE_ZONE_ID" ]; then
log_info "Fetching zone ID for $DOMAIN..."
ZONE_RESPONSE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN" \
"${AUTH_HEADERS[@]}" \
-H "Content-Type: application/json")
ZONE_ID=$(echo "$ZONE_RESPONSE" | jq -r '.result[0].id // empty' 2>/dev/null || echo "")
if [ -z "$ZONE_ID" ] || [ "$ZONE_ID" = "null" ]; then
ERROR=$(echo "$ZONE_RESPONSE" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null || echo "API call failed")
log_error "Failed to get zone ID: $ERROR"
exit 1
fi
log_success "Zone ID: $ZONE_ID"
else
ZONE_ID="$CLOUDFLARE_ZONE_ID"
log_success "Using provided Zone ID: $ZONE_ID"
fi
# Step 4: Get Account ID (for tunnel configuration)
log_section
log_info "Step 4: Getting Cloudflare Account ID"
log_section
if [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then
log_info "Fetching account ID..."
ACCOUNT_RESPONSE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts" \
"${AUTH_HEADERS[@]}" \
-H "Content-Type: application/json")
CLOUDFLARE_ACCOUNT_ID=$(echo "$ACCOUNT_RESPONSE" | jq -r '.result[0].id // empty' 2>/dev/null || echo "")
if [ -z "$CLOUDFLARE_ACCOUNT_ID" ] || [ "$CLOUDFLARE_ACCOUNT_ID" = "null" ]; then
log_warn "Could not get account ID automatically"
else
log_success "Account ID: $CLOUDFLARE_ACCOUNT_ID"
fi
else
log_success "Using provided Account ID: $CLOUDFLARE_ACCOUNT_ID"
fi
# Step 5: Configure DNS Record
log_section
log_info "Step 5: Configuring DNS Record"
log_section
TARGET="${TUNNEL_ID}.cfargotunnel.com"
log_info "DNS Target: $TARGET"
# Check if record exists
EXISTING_RECORD=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$EXPLORER_DOMAIN" \
"${AUTH_HEADERS[@]}" \
-H "Content-Type: application/json")
RECORD_ID=$(echo "$EXISTING_RECORD" | jq -r '.result[0].id // empty' 2>/dev/null || echo "")
EXISTING_TYPE=$(echo "$EXISTING_RECORD" | jq -r '.result[0].type // empty' 2>/dev/null || echo "")
DNS_DATA=$(jq -n \
--arg name "explorer" \
--arg target "$TARGET" \
'{
type: "CNAME",
name: $name,
content: $target,
proxied: true,
ttl: 1
}')
if [ -n "$RECORD_ID" ] && [ "$RECORD_ID" != "null" ]; then
log_info "Updating existing DNS record (ID: $RECORD_ID, Type: $EXISTING_TYPE)..."
if [ "$EXISTING_TYPE" != "CNAME" ]; then
log_warn "Existing record is type $EXISTING_TYPE, deleting and creating CNAME..."
curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
"${AUTH_HEADERS[@]}" \
-H "Content-Type: application/json" >/dev/null 2>&1
DNS_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
"${AUTH_HEADERS[@]}" \
-H "Content-Type: application/json" \
--data "$DNS_DATA")
else
DNS_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
"${AUTH_HEADERS[@]}" \
-H "Content-Type: application/json" \
--data "$DNS_DATA")
fi
else
log_info "Creating new DNS record..."
DNS_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
"${AUTH_HEADERS[@]}" \
-H "Content-Type: application/json" \
--data "$DNS_DATA")
fi
if echo "$DNS_RESPONSE" | jq -e '.success' >/dev/null 2>&1; then
log_success "DNS record configured successfully"
DNS_NAME=$(echo "$DNS_RESPONSE" | jq -r '.result.name' 2>/dev/null || echo "$EXPLORER_DOMAIN")
DNS_TARGET=$(echo "$DNS_RESPONSE" | jq -r '.result.content' 2>/dev/null || echo "$TARGET")
DNS_PROXIED=$(echo "$DNS_RESPONSE" | jq -r '.result.proxied' 2>/dev/null || echo "true")
log_info " Name: $DNS_NAME"
log_info " Target: $DNS_TARGET"
log_info " Proxied: $DNS_PROXIED"
else
ERROR=$(echo "$DNS_RESPONSE" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null || echo "API call failed")
log_error "Failed to configure DNS: $ERROR"
echo "$DNS_RESPONSE" | jq '.' 2>/dev/null || echo "$DNS_RESPONSE"
exit 1
fi
# Step 6: Configure Tunnel Route
log_section
log_info "Step 6: Configuring Tunnel Route"
log_section
if [ -z "$CLOUDFLARE_ACCOUNT_ID" ] || [ "$CLOUDFLARE_ACCOUNT_ID" = "null" ]; then
log_warn "Account ID not available - tunnel route must be configured manually"
log_info "Configure in Cloudflare Zero Trust Dashboard:"
echo " 1. Go to: https://one.dash.cloudflare.com/"
echo " 2. Zero Trust → Networks → Tunnels"
echo " 3. Select tunnel: $TUNNEL_ID"
echo " 4. Configure → Public Hostnames → Add hostname"
echo " 5. Subdomain: explorer, Domain: $DOMAIN"
echo " 6. Service: http://$EXPLORER_IP:$EXPLORER_PORT"
else
log_info "Configuring tunnel route via API..."
# Get current tunnel configuration
TUNNEL_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")
# Build new ingress configuration
NEW_CONFIG=$(jq -n \
--arg hostname "$EXPLORER_DOMAIN" \
--arg service "http://$EXPLORER_IP:$EXPLORER_PORT" \
'{
config: {
ingress: [
{
hostname: $hostname,
service: $service
},
{
service: "http_status:404"
}
]
}
}')
# Update tunnel configuration
TUNNEL_UPDATE=$(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 "$TUNNEL_UPDATE" | jq -e '.success' >/dev/null 2>&1; then
log_success "Tunnel route configured successfully"
else
ERROR=$(echo "$TUNNEL_UPDATE" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null || echo "API call failed")
log_warn "Tunnel route API configuration failed: $ERROR"
log_info "Please configure manually in Cloudflare Zero Trust Dashboard"
fi
fi
# Step 7: SSL/TLS Configuration (automatic with Cloudflare proxy)
log_section
log_info "Step 7: SSL/TLS Configuration"
log_section
log_info "SSL/TLS is automatically handled by Cloudflare when DNS is proxied"
log_success "SSL will be enabled automatically (Universal SSL)"
# Step 8: Verify Configuration
log_section
log_info "Step 8: Verifying Configuration"
log_section
log_info "Waiting for DNS propagation (10 seconds)..."
sleep 10
# Test DNS resolution
DNS_RESULT=$(dig +short "$EXPLORER_DOMAIN" 2>/dev/null | head -1 || echo "")
if [ -n "$DNS_RESULT" ]; then
log_success "DNS resolves to: $DNS_RESULT"
if echo "$DNS_RESULT" | grep -qE "^(104\.|172\.64\.|172\.65\.|172\.66\.|172\.67\.)"; then
log_success "DNS points to Cloudflare (proxied correctly)"
fi
else
log_warn "DNS not resolving yet (may need more time)"
fi
# Test public URL
log_info "Testing public URL..."
PUBLIC_HTTP=$(curl -s -o /dev/null -w "%{http_code}" "https://$EXPLORER_DOMAIN/api/v2/stats" 2>&1)
if [ "$PUBLIC_HTTP" = "200" ]; then
log_success "Public URL: HTTP 200 - Working!"
PUBLIC_RESPONSE=$(curl -s "https://$EXPLORER_DOMAIN/api/v2/stats" 2>&1)
if echo "$PUBLIC_RESPONSE" | grep -q -E "total_blocks|chain_id"; then
log_success "Public API: Valid response"
echo "$PUBLIC_RESPONSE" | jq -r '.total_blocks, .total_transactions, .total_addresses' 2>/dev/null || echo "$PUBLIC_RESPONSE" | head -5
fi
elif [ "$PUBLIC_HTTP" = "404" ]; then
log_warn "Public URL: HTTP 404 - May need more time for DNS/tunnel propagation"
elif [ "$PUBLIC_HTTP" = "502" ]; then
log_warn "Public URL: HTTP 502 - Tunnel routing issue, check tunnel route configuration"
else
log_warn "Public URL: HTTP $PUBLIC_HTTP"
fi
# Final Summary
echo ""
log_section
log_info " CONFIGURATION SUMMARY"
log_section
echo ""
log_success "✓ Cloudflared service: Installed and running"
log_success "✓ Tunnel ID: $TUNNEL_ID"
log_success "✓ DNS Record: $EXPLORER_DOMAIN$TARGET (🟠 Proxied)"
if [ -n "$CLOUDFLARE_ACCOUNT_ID" ]; then
log_success "✓ Tunnel Route: Configured via API"
else
log_warn "⚠ Tunnel Route: Manual configuration required"
fi
log_success "✓ SSL/TLS: Automatic (Cloudflare Universal SSL)"
echo ""
log_info "Configuration complete!"
log_info ""
log_info "Access your explorer at:"
echo " https://$EXPLORER_DOMAIN"
echo ""
log_info "If public URL is not working yet, wait 1-5 minutes for DNS propagation"
echo ""