6.4 上線:自訂域名、HTTPS、CI/CD 與回滾策略#
本節目標#
程式都寫完了,本節做「從能用到上線」的最後一哩:
- 把專案推上 GitHub,讓 Cloudflare Pages 走 Git 整合自動建置
- 掛上自訂網域
bitpoint.example(延續第 2 章註冊的網域),HTTPS 自動到齊 - 設定 production 與 preview 兩套環境變數
- 學會看 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 章的旅程到此完成——一個名副其實的「部落格 + 留言板 + 檔案下載」網站,從規劃、實作到上線一條路走完。
練習
- 開一個
feature/dark-mode分支隨便改個顏色,推上去找到它的 Preview 網址,觀察與 Production 的差異(記得到環境變數那節設定的PUBLIC_SITE_NAME前綴)。 - 故意推一個會 500 的版本(如把 binding 名字改錯)到一個測試專案,練習從 Deployments 頁 Rollback,計時它多久恢復。
- 用
dig查十個你常用的網站,觀察哪些回 Cloudflare IP——你會發現邊緣平台早已是半個網際網路。