Cloudflare Pages 教學:部署守門、線上驗收與退版

重點摘要

Cloudflare Pages 是 Cloudflare 的網站託管服務,免費方案每站最多 2 萬個檔、靜態檔案請求不限次數。用 wrangler 部署很快,但 Functions 從執行指令的目錄拿、部署完約 1 分鐘內正式網址還是舊版這類坑,要靠部署前守門、部署後線上實測和退版程序擋住。

Cloudflare Pages 是 Cloudflare 提供的網站託管服務,把建好的 HTML、CSS、圖片傳上去就能上線,需要伺服器端程式時再掛 Pages Functions,免費方案就放得下一般的公司官網、內容站和落地頁。要部署得穩,我們的做法是把建置、守門、部署、線上驗收寫成同一支腳本,任何一關沒過就停在上一版,出事時用 Cloudflare 保留的部署紀錄退回。

這篇的坑來自我們 2026 年 8 月到 10 月在自家與客戶的多個 Cloudflare Pages 專案上的實測,部署工具是 wrangler 4.119 與 4.148,作業系統是 Windows。官方規格以 2026 年 10 月 23 日查到的 Cloudflare 文件為準,免費額度之後可能會調整,上線前要再對一次。

Cloudflare Pages 是什麼?適合哪些網站

Cloudflare Pages 是 Cloudflare 的網站託管服務,主要放靜態網站:事先建好的 HTML、CSS、JavaScript 和圖片,上傳後由 Cloudflare 的全球網路送給訪客,不用自己顧主機。需要表單、轉址這類伺服器端功能,可以加跑在 Cloudflare Workers 上的 Pages Functions。公司官網、內容站、落地頁都適合,需要常駐程式的服務就不適合。

拿 Cloudflare Pages 免費架站,要先看清楚這幾個數字(2026 年 10 月 23 日查官方文件):

項目 免費方案 官方出處
每站檔案數 20,000 個 Pages 限制
單一檔案大小 25 MiB 同上
Git 連動的建置次數 每月 500 次,一次只能建 1 個 同上
每個專案的自訂網域 100 個 同上
靜態檔案請求 不限次數、免費 Functions 計價
Functions 請求 跟 Workers 共用每天 100,000 次,UTC 午夜重置 同上
Functions 每次請求的 CPU 時間 10 毫秒 Workers 限制
KV 讀取、寫入、列出 每天 100,000、1,000、1,000 次 KV 限制、KV 計價

官方對「靜態」的定義是:沒有叫用 Functions 的請求。依這個定義,middleware 掛在全站時每個請求都會叫用 Functions,全部算進每天 10 萬次的額度。純靜態網站幾乎碰不到上限,掛了全站 middleware 的網站,要另外估一下每天的請求量。

部署方式:Git 連動、wrangler、拖拉上傳差在哪

Cloudflare Pages 有三種部署方式:接 GitHub 或 GitLab,讓 Cloudflare 每次推送後自己建置;在本機或排程主機建好網站,再用 wrangler 指令上傳;或在後台把資料夾直接拖進去。三種的檔案上限和能不能帶 Functions 都不一樣,我們的網站幾乎都用 wrangler,因為建置後、上傳前要先跑自己寫的檢查,檢查沒過就不上傳。

方式 怎麼做 檔案上限 能不能帶 Functions 適合
Git 連動 推到 GitHub/GitLab,Cloudflare 幫你建置 20,000 個 可以 用框架、建置流程單純的專案
wrangler pages deploy 自己建好,再用指令上傳資料夾 20,000 個,單檔 25 MiB 可以,從執行指令的目錄拿 上傳前要跑自己的檢查
後台拖拉上傳 在後台把資料夾拖進去 1,000 個,單檔 25 MiB 不行 一次性的小頁

wrangler 這一列的「從執行指令的目錄拿」最容易出事。官方的 Direct Upload 文件寫,用 wrangler 部署時,「if a functions folder exists where the command is run」,那個 functions 資料夾就會跟著上傳;Functions 入門文件也說,functions 資料夾要放在專案根目錄,不是放在 dist 這種輸出資料夾裡。換句話說,你要部署的資料夾裡就算有 functions,wrangler 也不看。

wrangler 從哪裡拿 Functions

執行指令的目錄 functions/ 會上傳 dist/(要部署的) 網站檔案照常上傳 dist/ 裡面的 functions/ 不會被拿去當 Functions 執行目錄沒有 functions 就整版沒有 部署照樣顯示 Deployment complete
示意圖:wrangler pages deploy 只拿執行指令那個目錄底下的 functions,要部署的資料夾裡的不算

我們的上線流程:建置、守門、部署、線上驗收

照 Cloudflare Pages 教學把指令跑完、網址打得開,只是上線的一半,另一半是部署前後的檢查。我們的每個網站都只有一支部署腳本,依序跑建置、守門、產生 sitemap、部署、線上驗收、通知搜尋引擎,任何一關回傳非 0 就整條停下,網站停在上一版。這支腳本本身也做過負面測試:故意弄壞一個檔案,確認它真的會停、而且沒有部署出去。

一支腳本跑完的上線流程

  1. 建置從同一份原始檔產出整站,CSS 版本號用內容雜湊
  2. 守門連結、結構化資料、檔案白名單,任一項沒過就停
  3. 產生 sitemap日期只跟著內容走,不跟建置時間
  4. 部署從乾淨的暫存目錄執行 wrangler,只放本專案的 functions
  5. 線上驗收用部署專屬網址比對內容、標頭、轉址
  6. 通知搜尋引擎驗收過了才送 IndexNow
示意圖:我們的部署腳本固定六關,任何一關回傳非 0 就停,網站留在上一版

一定要寫成一支腳本,是因為手動串起來的指令,前一個失敗不會擋住下一個:守門回傳失敗,wrangler 照樣會把網站推上去。

守門要擋什麼,我們是一次一次踩出來的:

部署完要驗什麼?線上實測清單

部署指令顯示成功,只代表檔案傳上去了,不代表線上就是你要的樣子。我們部署完會用程式逐項驗:Functions 有沒有跟著上去、內容是不是新版、標頭規則有沒有命中、不存在的網址是不是回 404、自訂網域與憑證是否生效。每一項都對應一次真的出過的事,驗不過的部署要當成失敗處理。

驗什麼 怎麼驗 沒驗會怎樣
Functions 有沒有上去 輸出要有「Uploading Functions bundle」這行,部署 API 回的 uses_functions 要是 true 兩個站的 www 網址從 301 變 200,整站多一份複本
內容是不是新版 用部署專屬網址(8 碼.專案名.pages.dev)驗,或等 1 分鐘以上 剛部署完約 1 分鐘內,正式網址還在給舊內容
本機與線上一致 用位元組比對,先剝掉 Cloudflare 自訂網域插入的統計 script 沒剝乾淨時 246 頁全部誤判不一致
標頭規則有沒有命中 curl 看回應標頭,目錄型網址要寫 /:slug/ 以為全站關快取,其實只有首頁生效
不存在的網址 亂打一個網址,要回 404 沒有 404.html 時,任何網址都回 200 加首頁
檢查程式沒被擋 自己的檢查程式帶自訂的 User-Agent Python 預設的 UA 會被 Cloudflare 擋(403 或 1010),誤判成網站壞了
自訂網域 用 API 綁網域後確認 DNS 有 CNAME zone 裡 0 筆記錄,網域打不開

幾項要多說明。_headers 的寫法,官方文件說明可以用 :placeholder_name 這種佔位符比對路徑;我們實測 /slug/ 這種目錄型網址,寫 /、/*.html、/*/ 都不會命中,要寫 /:slug/。某站以為全站關了快取,其實只有首頁生效,40 次取樣有 5% 拿到舊版,看起來很像部署還沒傳完。

沒有 404.html 的問題,官方的 Serving Pages 文件寫得很清楚:專案頂層沒有 404.html,Pages 會當成單頁應用程式處理。它對搜尋的影響和修法,寫在 soft 404 正在白燒你的爬取預算。Cloudflare Pages 還會把 .html 網址轉到無副檔名的網址,canonical 和 sitemap 要寫成同一種形式,見新站沒被索引的檢查。

自訂網域方面,官方文件說,在後台加網域、網域又已經在 Cloudflare 上時,確認後會自動加 CNAME;但沒先在 Pages 專案裡綁定就自己加 CNAME,會出現 522 錯誤。我們 2026 年 8 月 30 日用 API 綁網域時發現,API 這條路不會自動建 DNS,zone 裡是 0 筆記錄,要手動建 CNAME,建好後憑證約 40 到 70 秒生效。

最後是預覽網址。官方的預覽部署文件寫,每個預覽部署預設都帶 X-Robots-Tag: noindex,不會被搜尋引擎收錄;但「專案名.pages.dev」這個正式預設網址不會自動 noindex,自訂網域上線之後,它就是整站的完整複本。我們的做法是 canonical 一律寫正式網域,有的專案再用 Functions 把 pages.dev 轉到正式網域。

退版:每次部署都留一個網址

Cloudflare Pages 每次部署都會留下自己的網址,退版不用重新建置。官方的退版文件寫,只要是建置成功的正式部署,都可以當退版目標,在後台的部署清單選「Rollback to this deployment」,確認後正式網址立刻換回那一版;預覽部署不能拿來退版。退回之後,比目前更新的版本也還是可以再選回來。

部署紀錄還有兩個用處。一是查「Google 當時抓到什麼」:部署歷史 API 每頁最多 25 筆,超過會回 400,可以逐版打開舊網址看當時的內容。二是量改版前的速度:舊版網址還活著,修完速度要比較時,可以拿舊版和新版用同一種量法各量一次。我們的部署腳本失敗時,會直接印出一行退回上一版的指令,出事的人不用臨時查文件。

「部署失敗」也要分清楚是哪一種,因為處理方式完全不同。我們的通知固定分三種寫:

失敗發生在 線上現在是哪一版 要做什麼
上線前的檢查沒過 還是上一版 修內容,重跑腳本
上傳失敗 還是上一版,沒有更新 查網路或權限,重跑部署
已上傳,但線上驗收沒過 已經是新版 判斷影響,必要時馬上退版

Cloudflare 缺點與限制:Functions、KV 和 wrangler

Cloudflare Pages 的免費額度對靜態網站很夠用,會碰到限制的多半是 Functions 和 KV 這些伺服器端功能,以及 wrangler 在 Windows 上的小毛病。我們撞過四個:Functions 每次請求只有 10 毫秒 CPU、KV 列出操作每天只有 1,000 次、用 API 設的環境變數會默默消失、wrangler 在中文路徑會當掉。

Cloudflare Workers 的 CPU 時間。 免費方案每次請求只有 10 毫秒 CPU,付費方案預設 30 秒、最多 5 分鐘。2026 年 9 月 11 日,我們在一個跑在 Cloudflare 免費方案上的後台測密碼雜湊(PBKDF2):迭代 10 萬次可以登入,15 萬次就回 500,錯誤碼 1101;OWASP 建議的 60 萬次,在免費方案上做不到。更麻煩的是,用不存在的帳號測登入會得到「正常」的假象,因為那條路走的是另一個低成本的流程。官方文件寫 CPU 超限會回錯誤 1102,我們那次看到的是 1101,所以只看錯誤碼判斷不了是不是 CPU 超限,要用階梯測試找上限。

KV 的列出次數。 KV 免費方案讀取每天 10 萬次,列出(list)只有 1,000 次。2026 年 9 月 10 日我們有一支 Worker 用 list 讀名單,額度打爆後整支 Worker 回錯誤 1101,到台北時間早上 8 點(UTC 0 點)才重置。名單類資料改成維護一個索引 key,用 get 讀,就不會再撞到。

環境變數。 用 Cloudflare API 設 Pages 的環境變數時,type 寫 plain_text 會回 success,回應裡也列出變數名稱,但重新讀取就不見了,程式拿到的是空值。我們一律改用 secret_text,設完一定重新讀回來比對;環境變數改了之後,要重新部署一次才生效。

wrangler 與中文路徑。 wrangler 4.119 在中文路徑下直接當掉,退出碼 0xC0000409,同一個指令在英文路徑就成功。wrangler 4.148 在中文路徑部署其實成功、線上也換了,退出碼卻是 3221226505,會讓看退出碼的腳本誤判成失敗。台灣的團隊很常把專案放在中文資料夾,部署用的暫存目錄一律改成英文路徑。

實測數據:我們在 Cloudflare Pages 量到的

我們 2026 年 8 月到 10 月在 Cloudflare Pages 與 Workers 上量到的結果,多數是單一網站、單次事件,有些是兩個站同時中招。數字是當時的版本與方案,wrangler 版本更新後行為可能會變,引用時請連同日期一起看。

項目 做法 結果 條件、日期、樣本數
wrangler 執行目錄 從沒有 functions/ 的目錄部署 顯示 Deployment complete,那一版卻沒有 middleware,www 網址從 301 變 200 2 個站,2026-09-22
部署後的正式網址 部署完馬上掃正式網址 約 1 分鐘內還是舊內容,部署專屬網址已是新版 1 個站,2026-09-24
_headers 規則 寫 /、/*.html、/*/ 想涵蓋目錄型網址 只有首頁生效,40 次取樣有 5% 拿到舊版 1 個站,2026-08
本機與線上比對 文字模式讀檔、沒剝 Cloudflare 插入的 script 246 頁全部誤判不一致 1 個站,2026-09-28
部署資料夾 wrangler 整包上傳 審核清單、備份檔、145 張產圖原稿線上全部回 200 某內容站,2026-10-21
內嵌 CSS 建站程式原封不動內嵌 改版註解出現在 191 頁的原始碼 1 個站,2026-09-25
Workers CPU PBKDF2 迭代次數階梯測試 10 萬次可登入,15 萬次回 500(錯誤碼 1101) 免費方案,2026-09-11
KV list() 免費方案用 list 讀名單 每天 1,000 次,打爆後整支 Worker 回 1101 1 支 Worker,2026-09-10
環境變數 API 設 plain_text 回 success,重新讀取就不見 1 個專案,2026-09-14
自訂網域 用 API 綁網域 zone 0 筆記錄要手動建 CNAME,憑證 40~70 秒生效 我們的官網,2026-08-30
wrangler 中文路徑 4.119 與 4.148 4.119 當掉(0xC0000409);4.148 部署成功但退出碼 3221226505 Windows,2026-09-24/2026-10-07

部署踩過的坑:現象、原因、怎麼修

這些坑的共同點是「指令說成功、畫面看起來正常」:wrangler 印出 Deployment complete、API 回 success、守門亮綠燈,問題卻已經在線上。我們 2026 年 8 月到 10 月在多個 Cloudflare Pages 專案上各踩過至少一次。

www 網址突然變成整站複本 現象:2026 年 9 月 22 日,兩個站的 www 網址從 301 轉址變成 200,整站被複製一份,wrangler 照樣印出 Deployment complete。 原因:wrangler 從執行指令的目錄拿 functions,那次是從沒有 functions 的目錄部署,那一版完全沒有 middleware。 怎麼修:每次建一個乾淨的暫存目錄,只放本專案的 functions,在那裡執行 wrangler;輸出沒有「Uploading Functions bundle」就判定部署失敗。

別的專案把我的網址轉走 現象:某站部署之後,網址被轉到另一個網站去。 原因:多個專案共用同一個部署目錄,其中一支部署腳本會先把共用的 functions 整個刪掉、換成自己的,下一個在那裡部署的站就帶著別人的轉址規則上線。 怎麼修:不共用部署目錄,每個專案用自己的乾淨暫存目錄;部署後驗「預設網址不可以被轉走」。

驗收驗到舊版 現象:剛部署完就掃正式網址,全部通過,事後發現掃到的是舊內容。 原因:部署完約 1 分鐘內,正式網址還在給舊內容,部署專屬網址已經是新的。 怎麼修:驗收一律用部署專屬網址,或等 1 分鐘以上,再跟本機建站產物逐頁比對。

本機和線上永遠對不上 現象:比對本機產物和線上網頁,246 頁全部顯示不一致。 原因:Python 文字模式讀檔會把 CRLF 轉成 LF,Cloudflare 自訂網域又會在 </body> 前插入一行統計 script。 怎麼修:用位元組比對,先剝掉 Cloudflare 插入的那一行再比。

正式資料被推回一週前 現象:從本機部署一個資料站,線上的資料倒退了 7 到 9 天。 原因:正式資料只在雲端主機上更新,本機是舊快照。 怎麼修:資料站只從雲端主機部署,本機部署前先同步,建站時沒有最新資料就擋。

手機版的修正,使用者看不到 現象:CSS 修好、部署成功,全新瀏覽器測也正常,回訪的人看到的還是舊版。 原因:HTML 引用的 ?v= 版本號沒跟著改,快取 4 小時內瀏覽器一直用舊檔。 怎麼修:版本號用 CSS、JS 檔的內容雜湊,建置時自動改寫,並驗每頁引用的版本號等於實際雜湊。

我們的方案:網站上線、部署守門與維運

我們幫客戶把網站放上 Cloudflare Pages 時,交付的是整條上線流程:建置、守門、部署、線上驗收、退版指令寫成同一支腳本,守門都做過負面測試,部署後用部署專屬網址自動驗收。網站上線、部署守門、監控與維運依功能報價,評估不收費,可以從自動化與網站維運聯絡我們。

網站如果要靠搜尋帶流量,上線流程通常跟技術 SEO 一起做:canonical、sitemap 日期、404、結構化資料都在守門裡。SEO 建置 $900 USDT、月維護 $400 USDT/月,方案在價格頁;sitemap 日期怎麼做寫在 sitemap lastmod 的內容雜湊做法,更多實作整理在 SEO 與 GEO 知識庫。

常見問題

Cloudflare Pages 免費嗎? 可以免費用。免費方案每站最多 20,000 個檔、單檔 25 MiB、Git 連動每月 500 次建置,靜態檔案請求不限次數;用到 Functions 時,請求跟 Workers 共用每天 100,000 次的額度,每次請求 CPU 時間 10 毫秒。

Cloudflare Pages 和 Cloudflare Workers 差在哪? Pages 放網站檔案,Workers 跑程式。Pages 專案裡的 Functions 其實就跑在 Workers 上,請求也算進 Workers 的額度;純靜態網站用 Pages 就夠,需要伺服器端邏輯時再加 Functions。

用 wrangler 部署,為什麼 Functions 沒有上去? 多半是執行指令的目錄不對。wrangler 拿的是執行指令那個目錄底下的 functions 資料夾,不是你要部署的資料夾裡的;部署完要看輸出有沒有「Uploading Functions bundle」,以及部署 API 回的 uses_functions 是不是 true。

部署錯了怎麼退回上一版? 在後台的部署清單選要退回的那一版,按「Rollback to this deployment」,正式網址會立刻換回去。只有建置成功的正式部署能當退版目標,預覽部署不行。

pages.dev 網址會被 Google 收錄嗎? 預覽部署不會,官方預設都帶 X-Robots-Tag: noindex;但「專案名.pages.dev」這個正式預設網址不會自動 noindex。自訂網域上線後,canonical 要寫正式網域,或用 Functions 把 pages.dev 轉過去。

這類問題,我們天天在解

把你的情境描述給我們,直接告訴你做不做得到、大概多少錢。

用 Telegram 聊需求
評估與報價不收費 · 回覆你的是工程師本人
TG 聊需求