diff --git a/scripts/configure-dns.sh b/scripts/configure-dns.sh new file mode 100755 index 0000000..441de85 --- /dev/null +++ b/scripts/configure-dns.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# DNS Configuration Script for AI Code Battle +# Configures all required DNS records via Cloudflare API +# +# Prerequisites: +# export CLOUDFLARE_API_TOKEN=your_token_here +# export CLOUDFLARE_ZONE_ID=your_zone_id # Optional, will auto-detect +# export TRAEFIK_IP=your_traefik_ip # Required for api.aicodebattle.com +# +# Usage: +# ./scripts/configure-dns.sh +# +# ALTERNATIVE: Manual Dashboard Configuration +# See DEPLOYMENT.md for step-by-step dashboard instructions +# +# DNS Records Required: +# 1. aicodebattle.com → CNAME → aicodebattle.pages.dev (proxied) +# 2. r2.aicodebattle.com → CNAME → acb-data.r2.cloudflarestorage.com +# 3. api.aicodebattle.com → A → (proxied) + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +DOMAIN="aicodebattle.com" + +echo "=== AI Code Battle - DNS Configuration ===" +echo "" + +# Check for required environment variables +if [ -z "$CLOUDFLARE_API_TOKEN" ]; then + echo -e "${RED}ERROR: CLOUDFLARE_API_TOKEN not set${NC}" + echo "Get your API token from: https://dash.cloudflare.com/profile/api-tokens" + echo "Required permissions: Zone.DNS (Edit)" + echo "" + echo "Run: export CLOUDFLARE_API_TOKEN=your_token_here" + exit 1 +fi + +if [ -z "$TRAEFIK_IP" ]; then + echo -e "${YELLOW}WARNING: TRAEFIK_IP not set${NC}" + echo "The api.aicodebattle.com record will NOT be configured." + echo "Get the Traefik LoadBalancer IP from Kubernetes:" + echo " kubectl --server=http://kubectl-apexalgo-iad:8001 get svc -n traefik" + echo "" + echo "Run: export TRAEFIK_IP=your_traefik_ip" + echo "" + READ_SKIP_API=${SKIP_API:-"n"} + if [ "$READ_SKIP_API" != "y" ]; then + read -p "Continue without API record? (y/n) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi + fi +fi + +# Cloudflare API base URL +CF_API="https://api.cloudflare.com/client/v4" + +# Function to make authenticated API calls +cf_api() { + local method=$1 + local endpoint=$2 + local data=$3 + + if [ -n "$data" ]; then + curl -s -X "$method" "${CF_API}${endpoint}" \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" \ + -d "$data" + else + curl -s -X "$method" "${CF_API}${endpoint}" \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" + fi +} + +# Get Zone ID if not provided +if [ -z "$CLOUDFLARE_ZONE_ID" ]; then + echo "Looking up Zone ID for $DOMAIN..." + ZONE_RESPONSE=$(cf_api GET "/zones?name=$DOMAIN") + CLOUDFLARE_ZONE_ID=$(echo "$ZONE_RESPONSE" | jq -r '.result[0].id // empty') + + if [ -z "$CLOUDFLARE_ZONE_ID" ]; then + echo -e "${RED}ERROR: Could not find zone for $DOMAIN${NC}" + echo "Make sure the domain is added to your Cloudflare account." + exit 1 + fi + echo -e "${GREEN}Found Zone ID: $CLOUDFLARE_ZONE_ID${NC}" +fi + +ZONE_ID=$CLOUDFLARE_ZONE_ID + +# Function to create or update DNS record +configure_record() { + local name=$1 + local type=$2 + local content=$3 + local proxied=${4:-false} + + echo "" + echo "Configuring $name.$DOMAIN ($type -> $content)..." + + # Check if record exists + EXISTING=$(cf_api GET "/zones/$ZONE_ID/dns_records?name=${name}.${DOMAIN}&type=$type") + EXISTING_ID=$(echo "$EXISTING" | jq -r '.result[0].id // empty') + + if [ -n "$EXISTING_ID" ]; then + # Update existing record + echo " Updating existing record..." + RESPONSE=$(cf_api PUT "/zones/$ZONE_ID/dns_records/$EXISTING_ID" \ + "{\"type\":\"$type\",\"name\":\"$name\",\"content\":\"$content\",\"ttl\":3600,\"proxied\":$proxied}") + else + # Create new record + echo " Creating new record..." + RESPONSE=$(cf_api POST "/zones/$ZONE_ID/dns_records" \ + "{\"type\":\"$type\",\"name\":\"$name\",\"content\":\"$content\",\"ttl\":3600,\"proxied\":$proxied}") + fi + + SUCCESS=$(echo "$RESPONSE" | jq -r '.success // false') + if [ "$SUCCESS" = "true" ]; then + echo -e "${GREEN} ✓ Success${NC}" + else + ERRORS=$(echo "$RESPONSE" | jq -r '.errors[0].message // "Unknown error"') + echo -e "${RED} ✗ Failed: $ERRORS${NC}" + fi +} + +# 1. Configure main domain (Pages CNAME) +# Note: For Pages custom domains, the CNAME target is .pages.dev +echo "" +echo "=== 1. Main domain (Pages) ===" +echo "Note: For Cloudflare Pages, you should add the custom domain via:" +echo " Workers & Pages > aicodebattle > Settings > Custom domains" +echo "" +echo "If the Pages project is already configured, we'll set up the CNAME:" +configure_record "@" "CNAME" "aicodebattle.pages.dev" true + +# 2. Configure R2 subdomain +echo "" +echo "=== 2. R2 subdomain ===" +echo "Note: For R2 custom domains, you should add the custom domain via:" +echo " R2 > acb-data > Settings > Custom Domains" +echo "" +echo "If already configured, the CNAME should point to R2's public endpoint:" +# R2 custom domain CNAME format: .r2.cloudflarestorage.com +configure_record "r2" "CNAME" "acb-data.r2.cloudflarestorage.com" false + +# 3. Configure API subdomain (if Traefik IP provided) +echo "" +echo "=== 3. API subdomain ===" +if [ -n "$TRAEFIK_IP" ]; then + configure_record "api" "A" "$TRAEFIK_IP" true +else + echo -e "${YELLOW}Skipping - TRAEFIK_IP not set${NC}" + echo "To configure later, run:" + echo " TRAEFIK_IP= ./scripts/configure-dns.sh" +fi + +echo "" +echo "=== DNS Configuration Complete ===" +echo "" +echo "Verification commands:" +echo " dig +short aicodebattle.com" +echo " dig +short r2.aicodebattle.com" +echo " dig +short api.aicodebattle.com" +echo "" +echo "Or run: ./scripts/verify-deployment.sh"