Files
proxmox/scripts/update-all-dns-to-public-ip.sh.bak
defiQUG fbda1b4beb
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands
- CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround
- CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check
- NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere
- MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates
- LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 15:46:57 -08:00

352 lines
12 KiB
Bash
Executable File

#!/usr/bin/env bash
# Update all Cloudflare DNS records to point to single public IP (76.53.10.36)
# Sets all records to DNS only mode (gray cloud) for direct NAT routing
# Supports multiple zones: sankofa.nexus, d-bis.org, mim4u.org, defi-oracle.io
# UDM Pro port forwarding: 76.53.10.36:80/443 → 192.168.11.167:80/443 (NPMplus)
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"; }
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# Source .env file (set +u so values with $ in them don't trigger unbound variable)
if [ -f "$PROJECT_ROOT/.env" ]; then
set +u
# shellcheck source=/dev/null
source "$PROJECT_ROOT/.env"
set -u
else
log_error ".env file not found at $PROJECT_ROOT/.env"
exit 1
fi
# Public IP for all services (76.53.10.36 - UDM Pro port forwarding to NPMplus 192.168.11.167)
PUBLIC_IP="${PUBLIC_IP:-76.53.10.36}"
# Cloudflare authentication
if [ -n "${CLOUDFLARE_API_TOKEN:-}" ]; then
AUTH_HEADER="Authorization: Bearer $CLOUDFLARE_API_TOKEN"
log_info "Using API Token authentication"
elif [ -n "${CLOUDFLARE_EMAIL:-}" ] && [ -n "${CLOUDFLARE_API_KEY:-}" ]; then
AUTH_HEADER_EMAIL="$CLOUDFLARE_EMAIL"
AUTH_HEADER_KEY="$CLOUDFLARE_API_KEY"
log_info "Using Email/API Key authentication"
else
log_error "Missing Cloudflare credentials"
log_error "Required: CLOUDFLARE_API_TOKEN OR (CLOUDFLARE_EMAIL + CLOUDFLARE_API_KEY)"
exit 1
fi
# Zone IDs (can be set in .env or passed as parameters)
ZONE_SANKOFA_NEXUS="${CLOUDFLARE_ZONE_ID_SANKOFA_NEXUS:-}"
ZONE_D_BIS_ORG="${CLOUDFLARE_ZONE_ID_D_BIS_ORG:-${CLOUDFLARE_ZONE_ID:-}}"
ZONE_MIM4U_ORG="${CLOUDFLARE_ZONE_ID_MIM4U_ORG:-}"
ZONE_DEFI_ORACLE_IO="${CLOUDFLARE_ZONE_ID_DEFI_ORACLE_IO:-}"
# Function to make Cloudflare API request
cf_api_request() {
local method="$1"
local zone_id="$2"
local endpoint="$3"
local data="${4:-}"
local url="https://api.cloudflare.com/client/v4/zones/${zone_id}${endpoint}"
if [ -n "${CLOUDFLARE_API_TOKEN:-}" ]; then
if [ -n "$data" ]; then
curl -s -X "$method" "$url" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data "$data"
else
curl -s -X "$method" "$url" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json"
fi
else
if [ -n "$data" ]; then
curl -s -X "$method" "$url" \
-H "X-Auth-Email: $AUTH_HEADER_EMAIL" \
-H "X-Auth-Key: $AUTH_HEADER_KEY" \
-H "Content-Type: application/json" \
--data "$data"
else
curl -s -X "$method" "$url" \
-H "X-Auth-Email: $AUTH_HEADER_EMAIL" \
-H "X-Auth-Key: $AUTH_HEADER_KEY" \
-H "Content-Type: application/json"
fi
fi
}
# Function to get existing DNS record
get_dns_record() {
local zone_id="$1"
local name="$2"
local type="${3:-A}"
local response=$(cf_api_request "GET" "$zone_id" "/dns_records?name=${name}&type=${type}")
echo "$response" | jq -r '.result[0] // empty' 2>/dev/null || echo ""
}
# Function to delete DNS record
delete_dns_record() {
local zone_id="$1"
local record_id="$2"
local response=$(cf_api_request "DELETE" "$zone_id" "/dns_records/$record_id")
if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
return 0
else
return 1
fi
}
# Function to get all DNS records (any type) for a name
get_all_dns_records() {
local zone_id="$1"
local name="$2"
local response=$(cf_api_request "GET" "$zone_id" "/dns_records?name=${name}")
echo "$response" | jq -r '.result[] // empty' 2>/dev/null || echo ""
}
# Function to create or update DNS A record
create_or_update_dns_record() {
local zone_id="$1"
local zone_name="$2"
local name="$3"
local ip="$4"
local proxied="${5:-false}"
# Handle apex domain (@ symbol) and construct full domain name
local full_name
if [ "$name" = "@" ]; then
full_name="${zone_name}"
elif [[ "$name" == *".${zone_name}" ]] || [[ "$name" == "${zone_name}" ]]; then
# Already a full domain name (ends with zone name or is zone name)
full_name="${name}"
else
# Subdomain - append zone name
full_name="${name}.${zone_name}"
fi
log_info "Processing: $full_name$ip (proxied: $proxied)"
# Check for existing CNAME records (must delete before creating A record)
local all_records=$(get_all_dns_records "$zone_id" "$full_name")
if [ -n "$all_records" ] && [ "$all_records" != "null" ]; then
echo "$all_records" | jq -r 'select(.type == "CNAME") | .id' | while read -r cname_id; do
if [ -n "$cname_id" ] && [ "$cname_id" != "null" ]; then
log_info " Deleting existing CNAME record (ID: ${cname_id:0:8}...)"
if delete_dns_record "$zone_id" "$cname_id"; then
log_success " Deleted CNAME record"
else
log_warn " Failed to delete CNAME record"
fi
fi
done
fi
# Get existing A record
local existing=$(get_dns_record "$zone_id" "$full_name" "A")
local data=$(jq -n \
--arg name "$full_name" \
--arg content "$ip" \
--argjson proxied "$proxied" \
'{
type: "A",
name: $name,
content: $content,
proxied: $proxied,
ttl: 1
}')
if [ -n "$existing" ] && [ "$existing" != "null" ]; then
local record_id=$(echo "$existing" | jq -r '.id')
log_info " Updating existing record (ID: ${record_id:0:8}...)"
local response=$(cf_api_request "PUT" "$zone_id" "/dns_records/$record_id" "$data")
if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
log_success " Updated: $full_name"
return 0
else
local error=$(echo "$response" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null || echo "Unknown error")
log_error " Failed to update: $error"
return 1
fi
else
log_info " Creating new record"
local response=$(cf_api_request "POST" "$zone_id" "/dns_records" "$data")
if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
log_success " Created: $full_name"
return 0
else
local error=$(echo "$response" | jq -r '.errors[0].message // "Unknown error"' 2>/dev/null || echo "Unknown error")
log_error " Failed to create: $error"
return 1
fi
fi
}
# Function to process a zone
process_zone() {
local zone_id="$1"
local zone_name="$2"
shift 2
local records=("$@")
if [ -z "$zone_id" ]; then
log_warn "Skipping zone $zone_name (no zone ID configured)"
return 0
fi
log_info ""
log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log_info "Processing Zone: $zone_name"
log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
local success_count=0
local fail_count=0
for record in "${records[@]}"; do
if create_or_update_dns_record "$zone_id" "$zone_name" "$record" "$PUBLIC_IP" "false"; then
((success_count++))
else
((fail_count++))
fi
done
log_info ""
log_info "Zone Summary: $success_count succeeded, $fail_count failed"
return $fail_count
}
# Main execution
main() {
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔧 Cloudflare DNS Update - Direct Public IP Routing"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
log_info "Public IP: $PUBLIC_IP"
log_info "Proxy Mode: DNS Only (gray cloud)"
echo ""
local total_failures=0
# sankofa.nexus domain records
if [ -n "$ZONE_SANKOFA_NEXUS" ]; then
SANKOFA_RECORDS=(
"@" # sankofa.nexus
"www" # www.sankofa.nexus
"phoenix" # phoenix.sankofa.nexus
"www.phoenix" # www.phoenix.sankofa.nexus
"the-order" # the-order.sankofa.nexus
)
if ! process_zone "$ZONE_SANKOFA_NEXUS" "sankofa.nexus" "${SANKOFA_RECORDS[@]}"; then
((total_failures++))
fi
else
log_warn "Skipping sankofa.nexus (no zone ID configured)"
fi
# d-bis.org domain records
if [ -n "$ZONE_D_BIS_ORG" ]; then
DBIS_RECORDS=(
"rpc-http-pub" # rpc-http-pub.d-bis.org
"rpc-ws-pub" # rpc-ws-pub.d-bis.org
"rpc" # rpc.d-bis.org (primary RPC)
"rpc2" # rpc2.d-bis.org (secondary RPC)
"ws.rpc" # ws.rpc.d-bis.org (primary WebSocket)
"ws.rpc2" # ws.rpc2.d-bis.org (secondary WebSocket)
"rpc-http-prv" # rpc-http-prv.d-bis.org
"rpc-ws-prv" # rpc-ws-prv.d-bis.org
"explorer" # explorer.d-bis.org
"dbis-admin" # dbis-admin.d-bis.org
"dbis-api" # dbis-api.d-bis.org
"dbis-api-2" # dbis-api-2.d-bis.org
"secure" # secure.d-bis.org
)
if ! process_zone "$ZONE_D_BIS_ORG" "d-bis.org" "${DBIS_RECORDS[@]}"; then
((total_failures++))
fi
else
log_warn "Skipping d-bis.org (no zone ID configured)"
fi
# mim4u.org domain records
if [ -n "$ZONE_MIM4U_ORG" ]; then
MIM4U_RECORDS=(
"@" # mim4u.org
"www" # www.mim4u.org
"secure" # secure.mim4u.org
"training" # training.mim4u.org
)
if ! process_zone "$ZONE_MIM4U_ORG" "mim4u.org" "${MIM4U_RECORDS[@]}"; then
((total_failures++))
fi
else
log_warn "Skipping mim4u.org (no zone ID configured)"
fi
# defi-oracle.io domain records
if [ -n "$ZONE_DEFI_ORACLE_IO" ]; then
DEFI_ORACLE_RECORDS=(
"explorer" # explorer.defi-oracle.io (Blockscout - same as explorer.d-bis.org)
"rpc.public-0138" # rpc.public-0138.defi-oracle.io
"rpc" # rpc.defi-oracle.io (HTTP RPC)
"wss" # wss.defi-oracle.io (WebSocket RPC)
)
if ! process_zone "$ZONE_DEFI_ORACLE_IO" "defi-oracle.io" "${DEFI_ORACLE_RECORDS[@]}"; then
((total_failures++))
fi
else
log_warn "Skipping defi-oracle.io (no zone ID configured)"
fi
# Summary
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ $total_failures -eq 0 ]; then
log_success "✅ DNS Update Complete"
else
log_warn "⚠️ DNS Update Complete with $total_failures zone(s) having failures"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
log_info "📋 Summary:"
log_info " • All records point to: $PUBLIC_IP"
log_info " • Proxy mode: DNS Only (gray cloud)"
log_info " • Routing: Direct NAT → Nginx → Backend Services"
echo ""
log_info "⏳ Wait 1-5 minutes for DNS propagation"
log_info "🧪 Test with: dig sankofa.nexus +short"
log_info "🧪 Test with: dig secure.d-bis.org +short"
echo ""
return $total_failures
}
# Run main function
main "$@"