pr_01m47d24b0e6n91zwymwxg0vpx/scripts/setup-custom-domains.sh

90 lines4,585 bytesCodeBlame
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.
25set -euo pipefail
26
27ROOT="$(cd "$(dirname "$0")/.." && pwd)"
28export CLOUDFLARE_API_TOKEN="${CLOUDFLARE_DEPLOY_TOKEN:-}"
29export CLOUDFLARE_ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-1e6f2cffa3f445920836e8ebe446bb58}"
30ZONE_ID="${G1T_APPS_ZONE_ID:-45d1c969bdd9d593756e70d5f45c2cbb}"
31FALLBACK="${G1T_DOMAINS_FALLBACK:-domains.g1t.page}"
32API="https://api.cloudflare.com/client/v4"
33w() { npx wrangler "$@"; }
34
35echo "== KV namespace g1t-domains"
36if 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."
44else
45 echo "Already set."
46fi
47
48cf() {
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
59echo "== Fallback origin $FALLBACK"
60if [ -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
76else
77 cat <<EOF
78Set 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
81EOF
82fi
83
84cat <<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
90EOF