239 lines
8.2 KiB
Bash
Executable File
239 lines
8.2 KiB
Bash
Executable File
#!/bin/bash
|
|
echo "#############################################################"
|
|
echo "# "
|
|
echo "# WARNING: This script will REPLACE ALL DNS records at "
|
|
echo "# the target domain ($CF_DOMAIN)! "
|
|
echo "# "
|
|
echo "# All existing DNS records for the listed subdomains will "
|
|
echo "# be deleted and replaced with new CNAME records. "
|
|
echo "# "
|
|
echo "#############################################################"
|
|
echo ""
|
|
echo "-------------------------------------------------------------"
|
|
echo "Cloudflare Credentials Required"
|
|
echo "Please ensure your .env file contains the following variables:"
|
|
echo " CF_API_TOKEN=your_cloudflare_api_token"
|
|
echo " CF_ZONE_ID=your_cloudflare_zone_id"
|
|
echo " CF_TUNNEL_ID=your_cloudflared_tunnel_id"
|
|
echo " CF_DOMAIN=yourdomain.com"
|
|
echo ""
|
|
echo "You can find these values in your Cloudflare dashboard:"
|
|
echo " - API Token: https://dash.cloudflare.com/profile/api-tokens (Create a token with Zone:DNS:Edit and Access:Apps:Edit permissions for your domain)"
|
|
echo " - Zone ID: On your domain's overview page"
|
|
echo " - Tunnel ID: In the Zero Trust dashboard under Access > Tunnels"
|
|
echo " - Domain: The domain you want to use for your services"
|
|
echo ""
|
|
echo "-------------------------------------------------------------"
|
|
echo ""
|
|
read -p "Type 'y' to continue or any other key to abort: " consent
|
|
if [[ "$consent" != "y" && "$consent" != "Y" ]]; then
|
|
echo "Aborted by user."
|
|
exit 1
|
|
fi
|
|
# Source environment variables from the .env file in the same directory
|
|
ENV_FILE="$(dirname "$0")/.env"
|
|
if [ -f "$ENV_FILE" ]; then
|
|
export $(grep -v '^#' "$ENV_FILE" | xargs)
|
|
else
|
|
echo "Error: .env file not found at $ENV_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if required Cloudflare variables are set
|
|
if [ -z "$CF_API_TOKEN" ] || [ -z "$CF_ZONE_ID" ] || [ -z "$CF_TUNNEL_ID" ] || [ -z "$CF_DOMAIN" ]; then
|
|
echo "Error: One or more required Cloudflare environment variables (CF_API_TOKEN, CF_ZONE_ID, CF_TUNNEL_ID, CF_DOMAIN) are not set in $ENV_FILE."
|
|
exit 1
|
|
fi
|
|
|
|
# Check if jq is installed
|
|
if ! command -v jq &> /dev/null; then
|
|
echo "Error: jq is required but not installed. Please install jq to continue."
|
|
echo "On Debian/Ubuntu: sudo apt-get install jq"
|
|
echo "On RHEL/CentOS: sudo yum install jq"
|
|
exit 1
|
|
fi
|
|
|
|
# Array of subdomains based on docker-compose.yml services
|
|
SUBDOMAINS=(
|
|
"homepage"
|
|
"excalidraw"
|
|
"listmonk"
|
|
"monica"
|
|
"flatnotes"
|
|
"code-server"
|
|
"ollama"
|
|
"open-webui"
|
|
"gitea"
|
|
"mini-qr"
|
|
"ferdium"
|
|
"answer"
|
|
"nocodb"
|
|
"n8n"
|
|
"convertx"
|
|
"rocket"
|
|
"live"
|
|
)
|
|
|
|
# First, remove existing DNS records for these subdomains
|
|
echo "Removing existing DNS records..."
|
|
|
|
for subdomain in "${SUBDOMAINS[@]}"; do
|
|
echo "Checking for existing records for $subdomain.$CF_DOMAIN..."
|
|
|
|
# Get all DNS records for this subdomain
|
|
RECORDS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records?name=$subdomain.$CF_DOMAIN" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
-H "Content-Type: application/json")
|
|
|
|
# Extract record IDs
|
|
RECORD_IDS=$(echo $RECORDS | jq -r '.result[].id')
|
|
|
|
# Delete each record
|
|
for record_id in $RECORD_IDS; do
|
|
echo "Deleting record $record_id for $subdomain.$CF_DOMAIN..."
|
|
|
|
curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records/$record_id" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
-H "Content-Type: application/json"
|
|
done
|
|
done
|
|
|
|
echo "All existing records have been removed."
|
|
|
|
# Add CNAME records for each subdomain
|
|
for subdomain in "${SUBDOMAINS[@]}"; do
|
|
echo "Adding CNAME record for $subdomain.$CF_DOMAIN..."
|
|
|
|
curl -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 "{
|
|
\"type\": \"CNAME\",
|
|
\"name\": \"$subdomain\",
|
|
\"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\",
|
|
\"ttl\": 1,
|
|
\"proxied\": true
|
|
}"
|
|
|
|
echo -e "\n"
|
|
done
|
|
|
|
echo "All CNAME records have been added."
|
|
|
|
# Add root domain record
|
|
echo "Adding root domain (@ record)..."
|
|
curl -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 "{
|
|
\"type\": \"CNAME\",
|
|
\"name\": \"@\",
|
|
\"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\",
|
|
\"ttl\": 1,
|
|
\"proxied\": true
|
|
}"
|
|
echo -e "\n"
|
|
echo "Root domain CNAME record has been added."
|
|
|
|
# Now create the Cloudflare Access applications
|
|
echo "Creating Cloudflare Access applications..."
|
|
|
|
# 1. Create wildcard access application for all subdomains
|
|
echo "Creating wildcard access application for *.$CF_DOMAIN..."
|
|
WILDCARD_APP_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
--data "{
|
|
\"name\": \"All Applications - $CF_DOMAIN\",
|
|
\"domain\": \"*.$CF_DOMAIN\",
|
|
\"type\": \"self_hosted\",
|
|
\"session_duration\": \"24h\",
|
|
\"app_launcher_visible\": true,
|
|
\"skip_interstitial\": true
|
|
}")
|
|
|
|
# Extract the application ID from the response
|
|
WILDCARD_APP_ID=$(echo $WILDCARD_APP_RESPONSE | jq -r '.result.id')
|
|
|
|
if [ -z "$WILDCARD_APP_ID" ] || [ "$WILDCARD_APP_ID" == "null" ]; then
|
|
echo "Error creating wildcard access application. Response: $WILDCARD_APP_RESPONSE"
|
|
else
|
|
echo "Successfully created wildcard access application with ID: $WILDCARD_APP_ID"
|
|
|
|
# Create policy for emails ending with the domain
|
|
echo "Creating email domain policy for wildcard application..."
|
|
EMAIL_DOMAIN=$(echo $CF_DOMAIN | cut -d'.' -f1,2)
|
|
|
|
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$WILDCARD_APP_ID/policies" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
--data "{
|
|
\"name\": \"Allow Domain Emails\",
|
|
\"decision\": \"allow\",
|
|
\"include\": [{
|
|
\"email_domain\": {
|
|
\"domain\": \"$EMAIL_DOMAIN\"
|
|
}
|
|
}],
|
|
\"require\": [],
|
|
\"exclude\": [],
|
|
\"precedence\": 1,
|
|
\"purpose\": \"Authentication for domain users\",
|
|
\"session_duration\": \"24h\"
|
|
}"
|
|
|
|
echo "Email domain policy created."
|
|
fi
|
|
|
|
# 2. Create specific access application for Gitea
|
|
echo "Creating access application for gitea.$CF_DOMAIN..."
|
|
GITEA_APP_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
--data "{
|
|
\"name\": \"Gitea $CF_DOMAIN\",
|
|
\"domain\": \"gitea.$CF_DOMAIN\",
|
|
\"type\": \"self_hosted\",
|
|
\"app_launcher_visible\": true,
|
|
\"skip_interstitial\": true
|
|
}")
|
|
|
|
# Extract the application ID from the response
|
|
GITEA_APP_ID=$(echo $GITEA_APP_RESPONSE | jq -r '.result.id')
|
|
|
|
if [ -z "$GITEA_APP_ID" ] || [ "$GITEA_APP_ID" == "null" ]; then
|
|
echo "Error creating Gitea access application. Response: $GITEA_APP_RESPONSE"
|
|
else
|
|
echo "Successfully created Gitea access application with ID: $GITEA_APP_ID"
|
|
|
|
# Create bypass policy for everyone - Updated format
|
|
echo "Creating bypass policy for Gitea application..."
|
|
|
|
POLICY_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$GITEA_APP_ID/policies" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
--data "{
|
|
\"name\": \"Bypass for Everyone\",
|
|
\"decision\": \"bypass\",
|
|
\"include\": [{
|
|
\"everyone\": {}
|
|
}],
|
|
\"require\": [],
|
|
\"exclude\": []
|
|
}")
|
|
|
|
# Check if policy creation was successful
|
|
POLICY_SUCCESS=$(echo $POLICY_RESPONSE | jq -r '.success')
|
|
|
|
if [ "$POLICY_SUCCESS" == "true" ]; then
|
|
POLICY_ID=$(echo $POLICY_RESPONSE | jq -r '.result.id')
|
|
echo "Bypass policy for Gitea created successfully with ID: $POLICY_ID"
|
|
else
|
|
ERROR_MSG=$(echo $POLICY_RESPONSE | jq -r '.errors[0].message')
|
|
echo "Error creating bypass policy for Gitea: $ERROR_MSG"
|
|
echo "Full response: $POLICY_RESPONSE"
|
|
fi
|
|
fi
|
|
|
|
echo "Cloudflare Access applications setup complete."
|