Files
goodgo-platform/infra/cloudflare-dns.sh
Ho Ngoc Hai e5f7acf7da
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 58s
Deploy / Build Web Image (push) Failing after 14s
Deploy / Rollback Production (push) Has been skipped
CI / E2E Tests (push) Has been skipped
Deploy / Build API Image (push) Failing after 3m8s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 1m21s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
feat: production infra — nginx configs, deploy script, security hardening
- Add Nginx reverse-proxy configs for api.goodgo.vn and platform.goodgo.vn
  with SSL, gzip, rate limiting, security headers, and WebSocket support
- Add Cloudflare DNS setup script for A/AAAA/CNAME records
- Add server-setup.sh for Ubuntu provisioning (Docker, fail2ban, UFW,
  swap, unattended-upgrades)
- Add deploy-production.sh for manual production deployments
- Add env.production.example with all required environment variables
- Bind container ports to 127.0.0.1 in docker-compose.prod.yml
  (security: prevent direct access bypassing Nginx)
- Fix deploy workflow: add -T flag to exec, sync Nginx configs,
  copy pgbouncer and backup configs to server

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
2026-04-13 14:11:25 +07:00

193 lines
6.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# ==============================================================================
# GoodGo Platform — Cloudflare DNS Setup
# Adds DNS records for platform.goodgo.vn, api.goodgo.vn, grafana.goodgo.vn
#
# Prerequisites:
# export CF_API_TOKEN="your-cloudflare-api-token"
# export CF_ZONE_ID="your-goodgo-vn-zone-id"
#
# Usage:
# ./infra/cloudflare-dns.sh
# ./infra/cloudflare-dns.sh --dry-run # Preview without creating
# ./infra/cloudflare-dns.sh --delete # Remove records
# ==============================================================================
set -euo pipefail
# ── Configuration ─────────────────────────────────────────────────────────────
CF_API_TOKEN="${CF_API_TOKEN:?Error: Set CF_API_TOKEN environment variable}"
CF_ZONE_ID="${CF_ZONE_ID:?Error: Set CF_ZONE_ID environment variable}"
TARGET_IP="${TARGET_IP:-185.225.232.65}"
CF_API="https://api.cloudflare.com/client/v4"
DRY_RUN=false
DELETE=false
# Parse flags
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=true ;;
--delete) DELETE=true ;;
esac
done
# DNS records to manage
declare -a SUBDOMAINS=("platform" "api" "grafana")
# ── Colors ────────────────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
log() { echo -e "${GREEN}[DNS]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
# ── Helpers ───────────────────────────────────────────────────────────────────
cf_api() {
local method="$1"
local endpoint="$2"
shift 2
curl -s -X "$method" \
"${CF_API}${endpoint}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
"$@"
}
get_record_id() {
local name="$1"
cf_api GET "/zones/${CF_ZONE_ID}/dns_records?type=A&name=${name}.goodgo.vn" \
| jq -r '.result[0].id // empty'
}
# ── Verify API Token ─────────────────────────────────────────────────────────
log "Verifying Cloudflare API token..."
VERIFY=$(cf_api GET "/user/tokens/verify")
if [ "$(echo "$VERIFY" | jq -r '.success')" != "true" ]; then
err "Invalid Cloudflare API token!"
echo "$VERIFY" | jq .
exit 1
fi
log "API token verified."
# ── Verify Zone ──────────────────────────────────────────────────────────────
ZONE_NAME=$(cf_api GET "/zones/${CF_ZONE_ID}" | jq -r '.result.name')
if [ "$ZONE_NAME" != "goodgo.vn" ]; then
err "Zone ID does not match goodgo.vn! Got: ${ZONE_NAME}"
exit 1
fi
log "Zone verified: ${ZONE_NAME}"
# ── Process DNS Records ─────────────────────────────────────────────────────
echo ""
log "=========================================="
if $DELETE; then
log " Deleting DNS records"
elif $DRY_RUN; then
log " DRY RUN — no changes will be made"
else
log " Creating/Updating DNS records"
fi
log " Target IP: ${TARGET_IP}"
log "=========================================="
echo ""
for sub in "${SUBDOMAINS[@]}"; do
FQDN="${sub}.goodgo.vn"
EXISTING_ID=$(get_record_id "$sub")
if $DELETE; then
if [ -n "$EXISTING_ID" ]; then
if $DRY_RUN; then
info "[DRY RUN] Would delete: ${FQDN} (ID: ${EXISTING_ID})"
else
RESULT=$(cf_api DELETE "/zones/${CF_ZONE_ID}/dns_records/${EXISTING_ID}")
if [ "$(echo "$RESULT" | jq -r '.success')" = "true" ]; then
log "Deleted: ${FQDN}"
else
err "Failed to delete ${FQDN}: $(echo "$RESULT" | jq -r '.errors[0].message')"
fi
fi
else
warn "Record not found: ${FQDN} — skipping delete"
fi
continue
fi
RECORD_DATA=$(cat <<EOF
{
"type": "A",
"name": "${sub}",
"content": "${TARGET_IP}",
"ttl": 1,
"proxied": true,
"comment": "GoodGo Platform — managed by infra/cloudflare-dns.sh"
}
EOF
)
if [ -n "$EXISTING_ID" ]; then
# Update existing record
if $DRY_RUN; then
info "[DRY RUN] Would update: ${FQDN}${TARGET_IP} (Proxied, ID: ${EXISTING_ID})"
else
RESULT=$(cf_api PUT "/zones/${CF_ZONE_ID}/dns_records/${EXISTING_ID}" -d "$RECORD_DATA")
if [ "$(echo "$RESULT" | jq -r '.success')" = "true" ]; then
log "Updated: ${FQDN}${TARGET_IP} (Proxied)"
else
err "Failed to update ${FQDN}: $(echo "$RESULT" | jq -r '.errors[0].message')"
fi
fi
else
# Create new record
if $DRY_RUN; then
info "[DRY RUN] Would create: ${FQDN}${TARGET_IP} (Proxied)"
else
RESULT=$(cf_api POST "/zones/${CF_ZONE_ID}/dns_records" -d "$RECORD_DATA")
if [ "$(echo "$RESULT" | jq -r '.success')" = "true" ]; then
NEW_ID=$(echo "$RESULT" | jq -r '.result.id')
log "Created: ${FQDN}${TARGET_IP} (Proxied) [ID: ${NEW_ID}]"
else
err "Failed to create ${FQDN}: $(echo "$RESULT" | jq -r '.errors[0].message')"
fi
fi
fi
done
# ── Verify DNS ───────────────────────────────────────────────────────────────
if ! $DRY_RUN && ! $DELETE; then
echo ""
log "Verifying DNS records..."
echo ""
for sub in "${SUBDOMAINS[@]}"; do
FQDN="${sub}.goodgo.vn"
RECORD=$(cf_api GET "/zones/${CF_ZONE_ID}/dns_records?type=A&name=${FQDN}")
IP=$(echo "$RECORD" | jq -r '.result[0].content // "NOT FOUND"')
PROXIED=$(echo "$RECORD" | jq -r '.result[0].proxied // "N/A"')
info "${FQDN}${IP} (proxied: ${PROXIED})"
done
fi
echo ""
log "=========================================="
log " DNS setup complete!"
if ! $DELETE; then
log ""
log " Cloudflare SSL/TLS settings (manual):"
log " - SSL mode: Full (Strict)"
log " - Always Use HTTPS: ON"
log " - Minimum TLS: 1.2"
log " - HTTP/2: ON"
log " - Brotli: ON"
log ""
log " Generate Origin Certificate at:"
log " Cloudflare Dashboard → SSL/TLS → Origin Server"
log " Save as: /etc/ssl/goodgo/origin.pem"
log " /etc/ssl/goodgo/origin-key.pem"
fi
log "=========================================="