症狀:所有檢查都綠,憑證就是不來
這個站的上線目標很簡單:把 GitHub Pages 綁到自訂網域,拿到 HTTPS。 流程理論上是這樣——repo 推 main、CNAME 檔內寫 labs.moneyai168.com、 Cloudflare DNS 加 CNAME 指 boboidvtw.github.io、等 GitHub 後台簽憑證。
走完所有步驟以後,DNS 解析正確、CAA 沒擋住 Let's Encrypt、 GitHub Pages 的 build 顯示 success、HTTP 連線也通。 但打 Pages API:
GET /repos/<user>/<repo>/pages →
{ "cname": "labs.moneyai168.com", ... 沒有 https_certificate 欄位 }
這個欄位連「存在但 pending」都不是——它整個不存在。cert_state 也永遠回 None。 這代表 GitHub 沒有為這個網域啟動憑證簽發流程,而不是流程跑到一半。
第一次嘗試:純 API toggle,無效
直覺解法:把網域「拔掉、再加回去」逼系統重跑流程。
gh api -X PUT repos/<u>/<r>/pages -f cname:null
# 等一下
gh api -X PUT repos/<u>/<r>/pages -f cname=labs.moneyai168.com
沒用。Pages API 顯示 cname 是切掉了,但 https_certificate 仍然不存在, 重設網域後一樣不簽。
為什麼?因為 repo 裡還有 CNAME 檔。GitHub Pages 每次 build 都會讀這個檔案, 自動把網域宣告回去。也就是說——API 那邊我「拔掉」了網域,但 Pages 後端 在下一次 build 又從檔案重新讀進來。網域從未真正進入「不存在」的狀態, 流程也從未真正「重置」。
關鍵頓悟:要拔到「檔案層」才算數
API 是描述狀態的,但 Pages 後端的真實狀態是 API 設定 ∪ repo 內 CNAME 檔。 只動 API 不動檔案,等於一邊清、一邊有人補。
所以正確的重置順序是這樣:
1. git rm CNAME → commit → push(同步呼叫 API 把 cname 設 null)
2. 輪詢 Pages API 直到 cname 真的回 None,並且 https://<user>.github.io/<repo>/
直連回 200——這證明網域真的釋放了,請求可以走 default Pages URL
3. 重建 CNAME 檔 → commit → push(API 設 cname=labs.moneyai168.com)
4. 等憑證簽發——本次重加後第一次輪詢就看到 cert_state=approved
整個重置加上重簽,1 到 15 分鐘搞定。 對比之前糾結一小時零進展,差別不在「等久一點」,差別在「狀態真的歸零」。
還有一個附加坑:HTTPS enforced 切不過去
憑證剛 approved 的那幾秒,GitHub 後端有時還不允許切「Enforce HTTPS」。 API 會回類似「certificate not ready」的錯誤。但這時候憑證本身已經可用, 直接 curl https://<domain>/ 是 200。
解法:把切換動作做成輪詢的一部分,失敗就 5 秒後重試。
printf '{"https_enforced":true}' | gh api -X PUT \
repos/<u>/<r>/pages --input -
這個小延遲不影響站台運作——憑證已可用、HTTPS 已能連,只是「強制重導」這個開關 晚個幾分鐘才能切。可以非阻塞地等。
關鍵教訓
狀態存在多個地方時,重置要全部歸零:Pages 後端的網域是 API 設定 + repo 內 CNAME 檔的聯集。只動 API 不動檔案,等於一邊清、一邊補。
驗證「真的歸零」要用獨立通道:API 回 cname=None 不夠,還要 curl https://<user>.github.io/<repo>/ 直連回 200,證明請求真的走回 default Pages URL。兩個訊號同時對才信。
沒進度 ≠ 進行中:cert_state 永遠 None 不是「正在簽」,是「根本沒啟動」。如果 1 小時沒動靜,要懷疑流程從未開始,而不是繼續等。
非阻塞操作要做成輪詢:HTTPS enforce 切換的暫時失敗不影響服務,包成 5 秒重試的輪詢,比手動重跑乾淨。
留下可複用的 troubleshooting 路徑:這個坑下次還會踩,把「git rm CNAME → 雙重驗證 → 重建 CNAME」這條路徑寫進 memory,下次直接走,不要重新摸索。