241 lines
9.0 KiB
Bash
241 lines
9.0 KiB
Bash
|
|
#!/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 ""
|
||
|
|
|