#!/bin/bash # Cloudflare Setup Script for Miracles In Motion # This script helps configure Cloudflare for the production deployment set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Configuration DOMAIN="miraclesinmotion.org" STATIC_WEB_APP_NAME="${STATIC_WEB_APP_NAME:-mim-prod-web}" AZURE_RESOURCE_GROUP="${AZURE_RESOURCE_GROUP:-rg-miraclesinmotion-prod}" echo -e "${GREEN}🌐 Cloudflare Setup Script${NC}" echo "==================================" echo "" # Check if Cloudflare CLI is installed if ! command -v cloudflared &> /dev/null; then echo -e "${YELLOW}⚠️ Cloudflare CLI (cloudflared) not found.${NC}" echo "Install it from: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/" echo "" fi # Check if jq is installed if ! command -v jq &> /dev/null; then echo -e "${YELLOW}⚠️ jq not found. Installing...${NC}" # Try to install jq (this may vary by OS) if [[ "$OSTYPE" == "linux-gnu"* ]]; then sudo apt-get update && sudo apt-get install -y jq elif [[ "$OSTYPE" == "darwin"* ]]; then brew install jq fi fi # Get Azure Static Web App default hostname echo -e "${GREEN}📋 Getting Azure Static Web App information...${NC}" AZURE_STATIC_WEB_APP_URL=$(az staticwebapp show \ --name "$STATIC_WEB_APP_NAME" \ --resource-group "$AZURE_RESOURCE_GROUP" \ --query "defaultHostname" -o tsv 2>/dev/null || echo "") if [ -z "$AZURE_STATIC_WEB_APP_URL" ]; then echo -e "${RED}❌ Could not find Static Web App. Please check the name and resource group.${NC}" echo "Usage: STATIC_WEB_APP_NAME=your-app-name AZURE_RESOURCE_GROUP=your-rg ./setup-cloudflare.sh" exit 1 fi echo -e "${GREEN}✅ Found Static Web App: ${AZURE_STATIC_WEB_APP_URL}${NC}" echo "" # Prompt for Cloudflare API credentials echo -e "${YELLOW}📝 Cloudflare API Configuration${NC}" echo "You need a Cloudflare API token with the following permissions:" echo " - Zone:Read, DNS:Edit, SSL:Edit, Page Rules:Edit" echo "" read -p "Enter your Cloudflare API Token: " CF_API_TOKEN read -p "Enter your Cloudflare Zone ID (or we'll look it up): " CF_ZONE_ID if [ -z "$CF_ZONE_ID" ]; then echo "Looking up Zone ID for $DOMAIN..." CF_ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" | jq -r '.result[0].id') if [ -z "$CF_ZONE_ID" ] || [ "$CF_ZONE_ID" == "null" ]; then echo -e "${RED}❌ Could not find Zone ID for $DOMAIN${NC}" exit 1 fi fi echo -e "${GREEN}✅ Zone ID: $CF_ZONE_ID${NC}" echo "" # Function to create DNS record create_dns_record() { local record_type=$1 local record_name=$2 local record_content=$3 local proxy=$4 echo "Creating DNS record: $record_name.$DOMAIN -> $record_content" local data=$(jq -n \ --arg type "$record_type" \ --arg name "$record_name" \ --arg content "$record_content" \ --argjson proxied "$proxy" \ '{ type: $type, name: $name, content: $content, proxied: $proxied, ttl: 1 }') local response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data "$data") local success=$(echo "$response" | jq -r '.success') if [ "$success" == "true" ]; then echo -e "${GREEN}✅ DNS record created successfully${NC}" else local errors=$(echo "$response" | jq -r '.errors[]?.message' | tr '\n' ' ') echo -e "${YELLOW}⚠️ DNS record may already exist or error: $errors${NC}" fi } # Create CNAME records echo -e "${GREEN}📝 Creating DNS Records...${NC}" create_dns_record "CNAME" "www" "$AZURE_STATIC_WEB_APP_URL" "true" create_dns_record "CNAME" "@" "$AZURE_STATIC_WEB_APP_URL" "true" echo "" # Configure SSL/TLS settings echo -e "${GREEN}🔒 Configuring SSL/TLS...${NC}" curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/settings/ssl" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{"value":"full"}' | jq -r '.success' && echo -e "${GREEN}✅ SSL mode set to Full${NC}" || echo -e "${YELLOW}⚠️ Could not update SSL settings${NC}" curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/settings/always_use_https" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{"value":"on"}' | jq -r '.success' && echo -e "${GREEN}✅ Always Use HTTPS enabled${NC}" || echo -e "${YELLOW}⚠️ Could not enable Always Use HTTPS${NC}" echo "" # Create Page Rules echo -e "${GREEN}📋 Creating Page Rules...${NC}" # Rule 1: Force HTTPS create_page_rule() { local url=$1 local settings=$2 local rule_name=$3 local data=$(jq -n \ --arg url "$url" \ --argjson settings "$settings" \ '{ targets: [ { target: "url", constraint: { operator: "matches", value: $url } } ], actions: $settings, priority: 1, status: "active" }') local response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/pagerules" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data "$data") local success=$(echo "$response" | jq -r '.success') if [ "$success" == "true" ]; then echo -e "${GREEN}✅ Page rule '$rule_name' created${NC}" else echo -e "${YELLOW}⚠️ Could not create page rule '$rule_name'${NC}" fi } # Create page rules HTTPS_SETTINGS='[{"id": "always_use_https"}]' create_page_rule "*${DOMAIN}/*" "$HTTPS_SETTINGS" "Force HTTPS" echo "" # Configure Security Settings echo -e "${GREEN}🛡️ Configuring Security Settings...${NC}" curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/settings/security_level" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{"value":"medium"}' | jq -r '.success' && echo -e "${GREEN}✅ Security level set to Medium${NC}" || echo -e "${YELLOW}⚠️ Could not update security level${NC}" curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/settings/browser_check" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{"value":"on"}' | jq -r '.success' && echo -e "${GREEN}✅ Browser Integrity Check enabled${NC}" || echo -e "${YELLOW}⚠️ Could not enable browser check${NC}" echo "" # Configure Speed Settings echo -e "${GREEN}⚡ Configuring Speed Settings...${NC}" curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/settings/minify" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{"value":{"css":"on","html":"on","js":"on"}}' | jq -r '.success' && echo -e "${GREEN}✅ Minification enabled${NC}" || echo -e "${YELLOW}⚠️ Could not enable minification${NC}" curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/settings/brotli" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{"value":"on"}' | jq -r '.success' && echo -e "${GREEN}✅ Brotli compression enabled${NC}" || echo -e "${YELLOW}⚠️ Could not enable Brotli${NC}" echo "" # Add custom domain to Azure Static Web App echo -e "${GREEN}🔗 Adding Custom Domain to Azure Static Web App...${NC}" az staticwebapp hostname set \ --name "$STATIC_WEB_APP_NAME" \ --resource-group "$AZURE_RESOURCE_GROUP" \ --hostname "$DOMAIN" 2>/dev/null && echo -e "${GREEN}✅ Custom domain $DOMAIN added${NC}" || echo -e "${YELLOW}⚠️ Domain may already be added or DNS not ready${NC}" az staticwebapp hostname set \ --name "$STATIC_WEB_APP_NAME" \ --resource-group "$AZURE_RESOURCE_GROUP" \ --hostname "www.$DOMAIN" 2>/dev/null && echo -e "${GREEN}✅ Custom domain www.$DOMAIN added${NC}" || echo -e "${YELLOW}⚠️ Domain may already be added or DNS not ready${NC}" echo "" # Summary echo -e "${GREEN}✅ Cloudflare Setup Complete!${NC}" echo "==================================" echo "" echo "Next Steps:" echo "1. Verify DNS propagation (may take 24-48 hours)" echo "2. Verify SSL certificates are provisioned" echo "3. Test the website at https://$DOMAIN" echo "4. Monitor Cloudflare analytics" echo "" echo "DNS Records Created:" echo " - www.$DOMAIN -> $AZURE_STATIC_WEB_APP_URL" echo " - $DOMAIN -> $AZURE_STATIC_WEB_APP_URL" echo "" echo "Cloudflare Settings:" echo " - SSL Mode: Full (strict)" echo " - Always Use HTTPS: Enabled" echo " - Security Level: Medium" echo " - Minification: Enabled" echo " - Brotli Compression: Enabled" echo ""