pr_01m47d24b0e6n91zwymwxg0vpx/scripts/setup-custom-domains.sh
| 1 | #!/usr/bin/env bash |
| 2 | # Sets up custom domains for deployed apps, once. Safe to run again: each |
| 3 | # step skips what exists. Run after scripts/setup-deployments.sh, then |
| 4 | # deploy with scripts/deploy.sh (deployments, then pages). |
| 5 | # |
| 6 | # Custom domains are Cloudflare for SaaS custom hostnames on the apps' zone |
| 7 | # (g1t.page). Turn Cloudflare for SaaS on for the zone first, in the |
| 8 | # dashboard: SSL/TLS, Custom Hostnames. Until then the API answers with |
| 9 | # codes 1404 or 1456, and g1t says custom domains are being switched on. |
| 10 | # |
| 11 | # This script: |
| 12 | # 1. creates the g1t-domains KV namespace (hostname -> app) and writes its |
| 13 | # id into services/deployments and services/pages wrangler.jsonc; |
| 14 | # 2. adds the fallback origin's DNS record: domains.g1t.page, proxied |
| 15 | # AAAA 100:: (what every custom domain points at); |
| 16 | # 3. sets domains.g1t.page as the zone's custom hostname fallback origin. |
| 17 | # |
| 18 | # Steps 2 and 3 need CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY (a Global API |
| 19 | # Key), or CLOUDFLARE_ZONE_TOKEN with DNS: Edit and SSL and Certificates: |
| 20 | # Edit on the zone; otherwise it says what to do by hand. |
| 21 | # |
| 22 | # The deployments service's own token (its CLOUDFLARE_API_TOKEN secret) |
| 23 | # also needs SSL and Certificates: Edit on the zone, to add custom |
| 24 | # hostnames. Add that permission to the token in the dashboard. |
| 25 | set -euo pipefail |
| 26 | |
| 27 | ROOT="$(cd "$(dirname "$0")/.." && pwd)" |
| 28 | export CLOUDFLARE_API_TOKEN="${CLOUDFLARE_DEPLOY_TOKEN:-}" |
| 29 | export CLOUDFLARE_ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-1e6f2cffa3f445920836e8ebe446bb58}" |
| 30 | ZONE_ID="${G1T_APPS_ZONE_ID:-45d1c969bdd9d593756e70d5f45c2cbb}" |
| 31 | FALLBACK="${G1T_DOMAINS_FALLBACK:-domains.g1t.page}" |
| 32 | API="https://api.cloudflare.com/client/v4" |
| 33 | w() { npx wrangler "$@"; } |
| 34 | |
| 35 | echo "== KV namespace g1t-domains" |
| 36 | if grep -q DOMAINS_KV_ID "$ROOT/services/deployments/wrangler.jsonc" "$ROOT/services/pages/wrangler.jsonc"; then |
| 37 | id=$(cd "$ROOT" && w kv namespace list 2>/dev/null | tr -d '\n ' | grep -oE '"id":"[0-9a-f]{32}","title":"g1t-domains"' | grep -oE '[0-9a-f]{32}' | head -1 || true) |
| 38 | if [ -z "$id" ]; then |
| 39 | id=$(cd "$ROOT" && w kv namespace create g1t-domains </dev/null 2>&1 | grep -oE '[0-9a-f]{32}' | head -1 || true) |
| 40 | fi |
| 41 | [ -n "$id" ] || { echo "Could not create the namespace; is wrangler logged in? (npx wrangler whoami)"; exit 1; } |
| 42 | sed -i "s/DOMAINS_KV_ID/$id/" "$ROOT/services/deployments/wrangler.jsonc" "$ROOT/services/pages/wrangler.jsonc" |
| 43 | echo "Using $id; wrote it into both wrangler.jsonc files. Commit that." |
| 44 | else |
| 45 | echo "Already set." |
| 46 | fi |
| 47 | |
| 48 | cf() { |
| 49 | local method="$1" path="$2" body="${3:-}" |
| 50 | local auth=() |
| 51 | if [ -n "${CLOUDFLARE_ZONE_TOKEN:-}" ]; then |
| 52 | auth=(-H "Authorization: Bearer $CLOUDFLARE_ZONE_TOKEN") |
| 53 | else |
| 54 | auth=(-H "X-Auth-Email: $CLOUDFLARE_EMAIL" -H "X-Auth-Key: $CLOUDFLARE_API_KEY") |
| 55 | fi |
| 56 | curl -sS -X "$method" "$API$path" "${auth[@]}" -H "Content-Type: application/json" ${body:+--data "$body"} |
| 57 | } |
| 58 | |
| 59 | echo "== Fallback origin $FALLBACK" |
| 60 | if [ -n "${CLOUDFLARE_ZONE_TOKEN:-}" ] || { [ -n "${CLOUDFLARE_API_KEY:-}" ] && [ -n "${CLOUDFLARE_EMAIL:-}" ]; }; then |
| 61 | if cf GET "/zones/$ZONE_ID/dns_records?name=$FALLBACK" | grep -q "\"name\":\"$FALLBACK\""; then |
| 62 | echo "DNS record exists." |
| 63 | else |
| 64 | cf POST "/zones/$ZONE_ID/dns_records" \ |
| 65 | "{\"type\":\"AAAA\",\"name\":\"$FALLBACK\",\"content\":\"100::\",\"proxied\":true,\"comment\":\"g1t custom domains: the Cloudflare for SaaS fallback origin, served by g1t-pages\"}" \ |
| 66 | | grep -q '"success":true' && echo "Added $FALLBACK AAAA 100:: (proxied)." || { echo "Could not add the DNS record."; exit 1; } |
| 67 | fi |
| 68 | answer=$(cf PUT "/zones/$ZONE_ID/custom_hostnames/fallback_origin" "{\"origin\":\"$FALLBACK\"}") |
| 69 | if echo "$answer" | grep -q '"success":true'; then |
| 70 | echo "Fallback origin set to $FALLBACK." |
| 71 | elif echo "$answer" | grep -qE '"code":(1404|1456)'; then |
| 72 | echo "Cloudflare for SaaS is not on for the zone yet. Turn it on (SSL/TLS, Custom Hostnames), then run this again." |
| 73 | else |
| 74 | echo "Could not set the fallback origin: $answer"; exit 1 |
| 75 | fi |
| 76 | else |
| 77 | cat <<EOF |
| 78 | Set CLOUDFLARE_ZONE_TOKEN (or CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY) to do this for you, or by hand: |
| 79 | 1. On the g1t.page zone, add a proxied DNS record: type AAAA, name ${FALLBACK%%.*}, content 100:: |
| 80 | 2. SSL/TLS, Custom Hostnames: set the fallback origin to $FALLBACK |
| 81 | EOF |
| 82 | fi |
| 83 | |
| 84 | cat <<EOF |
| 85 | == Remaining by hand |
| 86 | - Give the deployments service's API token SSL and Certificates: Edit on |
| 87 | the g1t.page zone (it already has Workers Scripts and Account Analytics). |
| 88 | - Deploy, which applies each part's migrations first: |
| 89 | scripts/deploy.sh billing deployments pages web |
| 90 | EOF |