跳轉到

6.4 上線:自訂域名、HTTPS、CI/CD 與回滾策略#

本節目標#

程式都寫完了,本節做「從能用到上線」的最後一哩:

  1. 把專案推上 GitHub,讓 Cloudflare Pages 走 Git 整合自動建置
  2. 掛上自訂網域 bitpoint.example(延續第 2 章註冊的網域),HTTPS 自動到齊
  3. 設定 production 與 preview 兩套環境變數
  4. 學會看 dig 驗證 DNS、檢查 cache headers,以及最保命的 Rollback

第一步:推上 GitHub,接上自動建置#

git init && git add . && git commit -m "章6完成:部落格+留言板+檔案下載"
git remote add origin git@github.com:<你的帳號>/bitpoint-blog.git
git push -u origin main

到 Cloudflare Dashboard → Workers & Pages → bitpoint-blog → Settings → Build & deployments,確認 Git 整合設定(第 3 章初次連結時已預設好):

設定 值 說明
Production branch main 推到 main = 上線
Framework preset Astro 自動偵測,對應 npm run build
Build command npm run build 產出 dist/
Output directory dist Pages 部署這個資料夾(含 functions/)

之後每一次 git push,Cloudflare 都會:clone → npm install → build → 部署到邊緣,全程約一分鐘。這就是 3.3 節學的 CI/CD,從今天起永遠不需要手動上傳。

第二步:自訂網域與 HTTPS#

Custom domains → Set up a custom domain,輸入 bitpoint.example(請換成你自己第 2 章註冊的網域)。因為網域 DNS 也託管在同一個 Cloudflare 帳號:

  • Pages 會自動加一條 CNAME(bitpoint → bitpoint-blog.pages.dev)
  • Universal SSL 自動簽發憑證,https:// 直接可用(2.4 節的原理在此受益)

不必手動改任何 DNS 記錄。

驗證 DNS 生效#

用第 2 章學過的 dig:

dig bitpoint.example CNAME +short
# → bitpoint-blog.pages.dev.        主域名被 proxy 時看不到,屬正常

dig bitpoint.example +short
# → 視 proxy 模式而定:DNS only 回 CNAME/target;Proxied 回兩組 Cloudflare IP

dig +trace bitpoint.example A | grep -E "bitpoint|cloudflare" | head

接著驗證 HTTPS 與憑證:

curl -sI https://bitpoint.example/ | head -8
# HTTP/2 200
# server: cloudflare        <- 已在邊緣
# ...

curl -svI https://bitpoint.example 2>&1 | grep -E "subject|issuer"
# subject: CN=bitpoint.example
# issuer:  CN=Google Trust Services ...(Cloudflare 向 CA 代簽的邊緣憑證)

環境變數:prod vs preview#

Pages 對同一個 repo 維護兩套設定:Production(main 分支)與 Preview(其他分支 / PR)。到 Settings → Environment variables 分別設定:

變數 Production Preview 用途
PUBLIC_API_BASE https://bitpoint.example ''(同源) build 時抓 API 的基底
PUBLIC_SITE_NAME BitPoint 部落格 [Preview] BitPoint 頁首標題可預覽環境自己看差異

注意 PUBLIC_ 前綴的變數會被編進靜態產物,是公開的;祕密(如未來的 API token)只用於 runtime bindings,進 Functions D1/R2 bindings 設定,絕不放在 PUBLIC_*。

另外別忘了把第 5 章的 D1 binding(DB)與 R2 binding(BUCKET) 各自掛到 Production 與 Preview 兩套環境——建議 Preview 綁「本機或測試用」的第二組 database/bucket,留言測試才不會髒了正式資料。

部署細節:commit 的來源要能追溯到 deployment#

每次部署在 Deployments 頁都有一列記錄:commit message、分支、部署結果。建議的 commit 紀律:

  • main 只推能上線的版本(部署即上線)
  • 功能開發在 feature 分支:Push 後自動生成 https://<hash>.bitpoint-blog.pages.dev 預覽網址,傳 PR 連結給自己與朋友點擊測試
  • 測過沒問題再 merge 回 main

Rollback:三分鐘的保命符#

發現新版炸了(例如留言區回 500、首頁白屏),別在線上 debug:

Deployments → 找上一個正常版本 → 右側 ⋯ → Rollback to this deployment

推新版本 → 發現異常 → Rollback(數十秒,全球生效)→ 本地找原因 → 修好再推

Pages 的 Rollback 是立即切換指標而非重新建置,所以極快;但注意兩件事:

  • D1 / R2 的資料不會跟著回滾——網站回舊版,資料庫還是新版的 schema。改欄位的 migration 要「只加不刪、能向下相容」
  • 回滾前後多看一眼 Logs,確認 500 的原因不是資料問題(那回滾程式也救不了)

上線體檢:cache headers 與效能#

最後用 curl 做一輪健康檢查(8.2 節會精修,這裡先求基本正確):

# 1) 靜態頁:應該被邊緣快取
curl -sI https://bitpoint.example/ | grep -i "cf-cache-status\|cache-control"
# cf-cache-status: HIT   (第二次請求起)

# 2) API:不該被快取(我們設了 no-store)
curl -sI https://bitpoint.example/api/posts | grep -i "cf-cache-status\|cache-control"
# cf-cache-status: DYNAMIC / BYPASS

# 3) 檔案下載:可快取(我們設了 max-age=3600)
curl -sI https://bitpoint.example/api/files/handout.pdf | grep -i "cache-control\|etag"

# 4) 全球任一節點都動
curl -sI https://bitpoint.example/api/posts | grep -i "age:"

檢查清單:

  • https://bitpoint.example 回 200、無混合內容警告
  • 首頁二次請求 cf-cache-status: HIT
  • 留言送出後重新整理,留言仍在
  • 檔案可下載、檔名正常(非亂碼)
  • Preview 環境的留言寫到測試資料庫,不是正式的

小結與練習#

網站正式活在全球邊緣上了:push 即部署、branch 即預覽、出事即回滾。第 6 章的旅程到此完成——一個名副其實的「部落格 + 留言板 + 檔案下載」網站,從規劃、實作到上線一條路走完。

練習

  1. 開一個 feature/dark-mode 分支隨便改個顏色,推上去找到它的 Preview 網址,觀察與 Production 的差異(記得到環境變數那節設定的 PUBLIC_SITE_NAME 前綴)。
  2. 故意推一個會 500 的版本(如把 binding 名字改錯)到一個測試專案,練習從 Deployments 頁 Rollback,計時它多久恢復。
  3. 用 dig 查十個你常用的網站,觀察哪些回 Cloudflare IP——你會發現邊緣平台早已是半個網際網路。