「Drupal 很慢」這個名聲,絕大部分來自主機代管,而它幾乎總是一個採購決定,不是軟體問題。網站被認真地做了出來,然後上線在一個以「幾個 PHP 檔案的形象網站」定價的方案上。結果就是:一套帶著正經算繪管線的內容管理系統,跑在一個自己改不了的記憶體上限裡,跑在一個自己控制不了的作業碼快取上,還沒有一個能執行自身工具的命令列。

人們心裡拿來對比的是 WordPress,而這個對比是錯的。WordPress 幾乎在任何環境下都能勉強跑得動,是因為它的市占率逼著主機商把它做成幾乎在任何環境下都能勉強跑得動。Drupal 的前提不同:它假定你有較新的 PHP、較新的資料庫、真正的快取後端、一個命令列,以及一套把程式碼庫當成建置產物、而不是當成「可以直接編輯的資料夾」的部署流程。

Drupal 到底需要主機提供什麼? 不低於你所用版本下限的 PHP、較新的 MySQL、MariaDB 或 PostgreSQL、實務上 256MB 的 PHP 記憶體、OPcache、能執行 Composer 與 Drush 的命令列存取、一條真正的 cron 排程,以及在有登入使用者之後的外部物件快取。廉價的共享主機會同時在其中三四項上不合格。


Drupal 對伺服器的真實需求

官方公布的需求很短、很具體,而且完全公開,可是幾乎沒有人在付款之前讀過它。這些需求還是分版本的,而這一點眼下格外重要,因為其中兩條下限會在 2026 年 12 月改變。

PHP 版本下限沒有商量餘地

Drupal 11 要求 PHP 8.3 起跳,支援 8.3、8.4 和 8.5。Drupal 10 要求 8.1,最高支援到 8.4,而 Drupal 12 又把下限抬到 PHP 8.5。這些數字來自 Drupal 自己的 PHP 需求文件,也只有這一份清單值得信任。

這件事比看上去更重要,因為 PHP 分支本身也會到期。php.net 的支援版本頁面 把 PHP 8.2 的安全支援終止日訂在 2026 年 12 月 31 日,8.3 到 2027 年 12 月 31 日,8.4 到 2028 年 12 月 31 日。PHP 8.1 已經過期了。一家宣傳「提供 PHP 8.1 和 8.2」的主機商,賣給你的是一套現在就沒有修補、或者幾個月內就會沒有修補的技術堆疊。

兩個日期還撞在一起。Drupal 10 在 2026 年 12 月 9 日結束生命週期,而根據 核心發行排程,Drupal 12 就在同一週發行。如果你的主機提供不了 PHP 8.3 或更新的版本,之後你就無法執行受支援的 Drupal。如果你還停在 10,我們談 Drupal 遷移的費用、路徑與期限 的文章講了這代表什麼。

資料庫引擎和它們真正的最低版本

按照 資料庫伺服器需求,Drupal 11 需要 MariaDB 10.6 以上、MySQL 8.0 以上、PostgreSQL 16 以上,或者 SQLite 3.45 以上。Drupal 10 寬鬆得多,只要 MariaDB 10.3.7、MySQL 5.7.8、PostgreSQL 12 和 SQLite 3.26。這正是為什麼一次升級有時會連帶逼出一次客戶完全沒預料到的資料庫升級。

有兩個細節常被跳過。在 MySQL 和 MariaDB 上,儲存引擎必須是 InnoDB,因為 Drupal 依賴交易與列級鎖定。在 PostgreSQL 上,安裝之前必須在 Drupal 使用的資料庫裡建立 pg_trgm 擴充套件,而一個不允許你執行 CREATE EXTENSION 的代管資料庫服務就是不能用的。

SQLite 確實受官方支援,用於本機開發也完全夠用,但一旦有好幾位編輯人員同時儲存內容,它就不是正式環境的答案了,因為最先觸頂的是寫入並行度。

記憶體、擴充套件與網頁伺服器

Drupal 文件裡的最低值是 64MB 的 PHP 記憶體,低於這個數它會發出警告。同一頁還寫著,正式環境上 128MB 或 256MB 是常態,媒體檔案多的網站需要更多。實務上請把 256MB 當成工作值,並且預期還要為命令列再往上調,因為吃記憶體的是 Composer 和大規模遷移,而不是頁面輸出。

擴充套件清單平淡無奇,但仍然值得逐項核對:帶資料庫驅動的 PDO、XML、JSON、mbstring、cURL、用於對外 HTTPS 的 OpenSSL,以及產生圖片衍生尺寸所需的 GD 或 ImageMagick。Drupal 12 還加上了用於密碼雜湊的 Argon2,這又是一件很舊的 PHP 建置不會帶的東西。

在網頁伺服器這一側,Drupal 支援 Apache 2.4.7 以上和 Nginx 1.1 以上,並且 從 Drupal 11.0.0 起不再支援 Microsoft IIS。Apache 需要 mod_rewrite 來提供乾淨的 URL,還需要 AllowOverride All 才能讓隨附的 .htaccess 生效。最後這一點最容易絆倒人:Drupal 的一部分保護規則只存在於 .htaccess 裡,所以用 Nginx 部署時必須在伺服器設定中手動把它們重寫一遍。這是一個例行步驟,也是一個被例行跳過的步驟,而它正是我們做 伺服器安全稽核 時最先要看的東西之一。

共享主機為什麼撐不住 Drupal

共享主機並不是劣質主機,它只是為另一種形狀的應用做了最佳化,而 Drupal 會在它的限制上以四種可預期的方式撞碎。

沒有命令列就沒有 Composer 和 Drush

現在的 Drupal 是一個 Composer 專案。核心、社群模組以及它們的 PHP 相依套件全部由 Composer 解析,而一旦 Composer 開始管理某個模組,它就必須連核心一起管理。把 Composer 和手動改檔案混著用,正是一個網站最後完全無法更新的典型路徑。

一個帶檔案管理員的控制台做不到這件事,FTP 用戶端也做不到。沒有 SSH,你同時也失去了 Drush,而重建快取、匯入設定、執行資料庫更新和重設使用者密碼,實際上都是靠 Drush 完成的。一個你無法對它執行 drush cr 的網站,是一個每一步復原動作都要變成工單的網站。

那些你看不見、更改不了的限制

共享帳號上的 memory_limit 由別人決定,通常是 128MB,有時更低,而且當你遇到那次需要 512MB 的遷移時,沒有任何途徑把它調上去。

更大的問題是 OPcache。它把預先編譯的指令碼位元組碼放在共享記憶體裡,這樣 PHP 就不必在每個請求上重新解析檔案;而在共享主機上,那塊記憶體區是幾百個帳號共用的。Drupal 有好幾千個 PHP 檔案,所以它在這塊被爭搶的記憶體區裡是個重量級房客,於是被擠出去。症狀就是:有人造訪之後的一分鐘裡網站很快,一個小時後又變慢了。

然後是那些根本就不存在的東西:沒有 Redis,沒有 Memcached,沒有對 PHP 行程管理員的控制權,也沒有辦法跑一個長時間執行的佇列工作行程。

從來沒有真正跑起來的 cron

Drupal 的自動 cron 模組 預設每三小時執行一次,並且由造訪網站的終端使用者觸發。在流量大的網站上,這代表偶爾會有某位訪客用自己的頁面載入時間替搜尋索引買單。在冷清的網站上,這代表 cron 實質上根本不跑:搜尋索引會過期,紀錄資料表永遠不會被清理,可用的安全更新也永遠不會被檢查。

文件建議改為從外部觸發 cron,因為那樣總能準時執行,而且耗用的資源更少。這需要一條真正的 crontab 記錄,而最便宜的那一級並不提供。

各層快取,以及訪客真正命中的是哪一層

Drupal 的快取層比多數人以為的要多,而且這些層次不是互相替代的關係。它們是疊起來的,每一層接住上一層沒能接住的東西。

OPcache 完全位於 Drupal 之下

OPcache 不是 Drupal 的功能。它在直譯器這一層快取編譯後的 PHP 位元組碼,所以無論 Drupal 的哪一層快取是否命中,它對每個請求都生效。這一層設錯了,上面的任何東西都補不回來,因為每個請求在抵達路由之前,都要先付一遍重新編譯框架的代價。共享記憶體要給得寬裕,並且在正式環境關閉時間戳記驗證,因為正式環境上的檔案集合只在部署時才變動。

Internal Page Cache 與 Dynamic Page Cache

Internal Page Cache 是一個核心模組,預設啟用,而且只服務匿名使用者。它假定每位匿名訪客看到的是同一個頁面,在首次請求時把整個回應存下來,之後重複使用。對於沒有個人化的行銷網站,幾乎所有工作都是這一層做的。

Dynamic Page Cache 同樣是核心模組,同樣預設啟用,但它對所有人生效,包括已登入的使用者。它的做法是讓算繪系統把頁面上真正屬於個人的部分換成佔位符,再把周圍的一切快取起來。這就是為什麼一個登入狀態下的 Drupal 頁面依然可以大部分被快取:真正動態的只有使用者選單和少數幾個區塊。

BigPipe 與算繪快取

在這兩者之下是算繪快取,它快取單一區塊、欄位、檢視結果和實體算繪結果。一個沒有命中頁面快取的頁面,通常也是靠一堆算繪快取命中拼起來的,而不是從資料庫重新建構。

剩下的部分交給 BigPipe。它從 Drupal 8.1 起進入核心,在 8.3 轉為穩定,從 8.5 起進入標準安裝設定檔。它不再等所有佔位符解析完畢,而是立刻把可快取的頁面送出去,隨後再把個人化片段串流過來。它不需要任何設定,而且對已登入使用者的幫助遠大於對匿名使用者。

所以,在一個設定正確的網站上,匿名訪客命中的是 Internal Page Cache,或者它前面的 CDN,而且根本碰不到上面這些東西的大部分。登入中的編輯人員則在每個請求上都命中 Dynamic Page Cache、算繪快取和 BigPipe,這正是已驗證流量成本高得多的原因。

外部物件快取

上面每一層都需要一個地方來存放自己的項目。預設那個地方是資料庫裡的快取資料表,也就是說你的快取讀取會在同一台伺服器上和內容查詢互相搶資源。

Redis 模組 把快取、鎖定、洪泛控制和佇列這幾個後端搬到 Redis 或 Valkey 這類相容儲存上,可以用 PhpRedis 擴充套件、Relay 擴充套件,也可以用純 PHP 的 Predis 函式庫。Memcached 是等價的替代方案。對一個小型匿名網站,這改變不了多少。對一個有登入使用者的網站,它通常是眼下能拿到的最大一項改善,因為它把最吵鬧的寫入負載從資料庫裡搬走了,同時讓鎖定變得便宜。

Drupal 前面的反向代理與 CDN

Varnish、Nginx 這樣的反向代理,或者一個 CDN,會在 PHP 完全沒被牽扯進來之前就把請求回答掉。對匿名流量來說,這是「用個位數毫秒送出一個頁面」和「用幾百毫秒送出一個頁面」的差別。它同時也是人們最害怕的一層,因為在新聞網站或商店上留下過期內容是一種看得見的失敗。

讓 CDN 變安全的是快取標籤

Drupal 的答案是快取標籤。快取標籤描述的是資料相依性,寫成 node:5user:3node_list 這樣的字串。每一筆快取項目都記錄自己相依於哪些標籤,所以編輯第 5 號節點時,凡是引用過它的快取片段、頁面和檢視,無論出現在哪裡都會被作廢。

關鍵在於 Drupal 能把這些標籤對外發布出去。社群模組會把它們當成 Fastly 的 Surrogate-Key 標頭或 Cloudflare 的 Cache-Tag 標頭送出去,CDN 隨後在 Drupal 發話時依標籤清除。這就把 CDN 從一場以時間為賭注的賭博變成了事件驅動的快取:你可以設定很長的存活時間,因為一次編輯會在幾秒內精準清除受影響的那些 URL。

要留意標頭預算。Cloudflare 的 依快取標籤清除文件 規定 Cache-Tag 標頭在扣掉欄位名稱之後總長上限為 16KB,大致相當於 1,000 個唯一標籤,API 呼叫中每個標籤最長 1,024 個字元,儀表板一次清除最多 100 個標籤。一個列出大量實體的 Drupal 檢視所產生的標籤會遠遠超過這個數,所以一個「什麼都列」的頁面會無聲無息地把標頭撐爆,除非在模組裡設定了裁剪或雜湊。

選擇 Drupal 主機:四個級距,說實話

真正的選項只有四個,而選哪一個由兩件事決定:你有沒有已驗證流量,以及你有沒有人來維運這台伺服器。下面的區間是英國客戶依我們的經驗通常支付的價格,未含加值稅,屬於參考值而不是任何供應商的報價。

級距每月典型費用買到的是什麼
共享主機GBP 3 到 GBP 15Drupal 需要的一樣也沒有
非代管 VPS 或雲端主機GBP 20 到 GBP 120完整控制權,但沒有維運的人
代管型 Drupal 平台GBP 40 到 GBP 800 以上一套定好型的技術堆疊與流程
客製化基礎架構GBP 400 起什麼都有,連同隨之而來的義務

共享主機

不適合任何要在正式環境跑 Drupal 的人。它在命令列存取、記憶體、作業碼快取、物件快取和 cron 上會同時不合格。如果預算確實卡在這裡,用差不多的錢買一台小的非代管執行個體,是更好的花法。

非代管 VPS 或雲端執行個體

每月大約 GBP 20 到 GBP 120 能買到一台擁有完整 root 權限的機器,這適合絕大多數 Drupal 網站。你可以自己選 PHP 版本、把 OPcache 調到合適大小、裝上 Redis、設定 crontab、把 Nginx 設定正確。你買不到的,是有人替你去做這些、去修補、去監控、去在凌晨兩點把它還原回來。這一級適合你已經有開發者或代理商在服務合約裡的情況,而真正的成本是那份合約,不是那台機器。

代管型 Drupal 專業平台

代管型 Drupal 主機對一個小網站大約從每月 GBP 40 起跳,並隨流量、環境數量和支援等級迅速上升。你買到的是一套本來就正確的、定好型的技術堆疊,外加以 Git 為基礎的部署、預備環境、備份,以及一位真正懂 Drupal 的人接電話。當另一個選項是「沒有人」時,它很值;當你為一個每月 4,000 次造訪的形象網站支付平台價格時,它就不值。

完整的客製化基礎架構

獨立資料庫、專用快取節點、負載平衡後面的一排應用伺服器、放檔案的物件儲存。這套東西大約在每月 GBP 400 以上才開始說得通,而且只在已驗證流量、系統整合或法規遵循需求讓代管級距變得彆扭的時候才成立。它是能力最強的一級,也是要求最高的一級,因為修補、監控和災難復原現在都歸你了。這些複雜度在應用層是從哪裡來的,我們的 Drupal 網站開發指南 有談。

部署:不要在伺服器上編輯檔案

既然 Composer 解析的是整棵相依樹,伺服器上的程式碼庫就是產出,不是工作區。就地改一個模組檔案,代表下一次 composer update 會把它覆蓋掉,也代表你的正式環境程式碼不再對應 Git 裡的任何東西。

一套正常的發行流程會在別處建置這個產物:在 CI 裡從已提交的 composer.lock 執行 composer install,這樣建置是可重現的,而正式主機根本不需要 Composer、不需要為相依解析準備 PHP 記憶體,也不需要對 vendor 的寫入權限。把結果送過去,執行資料庫更新,匯入設定,重建快取。回復就是把指標指回上一個產物。

這也順帶悄悄回答了主機的問題:一家指望你透過 FTP 編輯檔案的主機商,無論規格表上寫著什麼,都和 Drupal 的維護方式不相容。

設定同步放在什麼位置

Drupal 把生效中的設定保存在資料庫裡,並把它匯出成 YAML 檔案,內容類型、欄位、檢視和各項設定就是這樣在環境之間移動的。設定管理文件 說明來源網站和目標網站的 site UUID 必須一致,這也是第一次匯入失敗最常見的原因。

實際上,這代表設定就是程式碼。它和其他程式碼一起被提交、被審查、被部署,而匯入這一步是當成發行的一部分執行,而不是事後在管理介面裡點一遍。主機也必須支撐這一點:你需要一個執行匯入的地方,還需要一個環境,能讓失敗的匯入被回復,而不是半途留在正式環境裡。

檔案、媒體與備份

Drupal 有兩套檔案系統,而這個差別是承重的。公開的那套位於網站根目錄之下,由網頁伺服器直接提供。私有的那套位於網站根目錄之外,每一次對私有檔案的請求都會穿過 Drupal,以便檢查存取權限。

因此私有檔案比公開檔案昂貴得多,因為每一次下載都要啟動一次 PHP。一個要發送大型私有文件的網站,需要靜態檔案伺服器根本不需要的餘裕。

把媒體移到物件儲存

一旦檔案長在應用伺服器上,橫向擴充和重建都會變得難受,而且每一次備份都要馱上整個媒體庫。把公開檔案系統搬到 S3 相容的物件儲存,會把兩者分開,讓 CDN 可以直接提供媒體,也讓應用伺服器真正變成可拋棄的。

備份證明不了的事,還原演練能證明

一次備份只能證明檔案存在。一次還原演練能證明這個檔案是完整的、資料庫和檔案來自同一個時刻、你的憑證仍然有效,以及整件事要花多久。這是四種彼此獨立的失敗方式,而控制台裡的一個綠色勾勾一種都看不出來。

至少每年做兩次,用真正的碼錶計時,並把那個數字寫下來。如果還原要花六個小時而你的容忍度是一個小時,那麼問題在架構,不在備份。復原時間是一項主機需求,它屬於需求規格,而不屬於事故現場。

正確地為 Drupal 主機做容量規劃

頁面瀏覽量是錯誤的單位。一個每月 200,000 次匿名頁面瀏覽、前面掛著 CDN 的網站,在一台小機器上可以很從容;而一個每月 8,000 次瀏覽的網站,如果其中大部分是登入狀態,反而可能吃力。

真正的驅動因素是已驗證流量

匿名請求可以由頁面快取或 CDN 回答,完全不碰 PHP;已驗證請求不行。它們中的每一個都要跑一遍算繪管線、對每個實體檢查存取權限、解析佔位符並寫入工作階段資料。實際要問的問題不是你有多少次造訪,而是你同時有多少位登入使用者,以及這些使用者被允許看到什麼。

編輯人員是最極端的情況。內容管理畫面屬於 Drupal 裡最重的頁面,而且按定義就無法快取,所以一個有十二位編輯人員同時工作的網站,會有一項它的公開流量完全暗示不出來的真實並行需求。

檢視、分類法與佇列作業

除了已驗證流量之外,可靠的成本來源還有幾處:帶很多篩選器和關聯的大型檢視會產生昂貴的聯結查詢;很深的分類法樹在每次算繪時都要走過術語階層;以及搜尋索引、訂閱來源匯入和媒體衍生檔案產生這類 cron 或佇列作業。

如果做得到,佇列工作行程不應該和訪客搶同一台網頁伺服器的資源。在規模較大的網站上,它們應該放在獨立的行程或機器上,這樣匯入積壓就不會拖慢前台。這是一個在採購時就要做出的架構決定,也正是代管級距開始不合身、而客製化基礎架構開始說得通的那個交界點。

把這個決定做對

這個模式很一致:主機不是買小了,而是買錯了形狀。沒有命令列,沒有物件快取,作業碼快取由別人控制,PHP 版本又快要脫離支援。把同一個網站搬到一台價格相近但規格正確的機器上,通常勝過任何數量的前端最佳化。

Mecanik 在 網站開發 工作中負責規劃、建置與維護 Drupal 基礎架構,當客戶擔心的是暴露面而不是速度時,我們會透過 伺服器安全稽核 檢視現有的技術堆疊。如果你需要的是人而不是平台,我們談 招聘 Drupal 開發者 的文章講了該看哪些方面。



常見問題

Drupal 11 的最低伺服器需求是什麼? PHP 8.3 或更新版本,資料庫為 MariaDB 10.6、MySQL 8.0、PostgreSQL 16 或 SQLite 3.45。網頁伺服器這一側是 Apache 2.4.7 或 Nginx 1.1 以上,並且從 Drupal 11.0.0 起不再支援 Microsoft IIS。PHP 記憶體低於 64MB 時 Drupal 會發出警告,但正式環境上實際的數字是 256MB。

Drupal 可以跑在共享主機上嗎? 它裝得起來,也回得了頁面,但共享主機通常會同時在三四項需求上不合格:沒有執行 Composer 或 Drush 的命令列存取、無法調高的 PHP 記憶體上限、沒有 Redis 或 Memcached,以及只有當訪客剛好打開頁面時才觸發的 cron。Drupal 很慢這個名聲,正是這些條件造出來的。

Drupal 主機代管應該花多少錢? 一個小型 Drupal 網站跑在設定正確的非代管機器上,在沒有人替你維運之前,通常每月落在 GBP 20 到 GBP 120 之間。代管型 Drupal 平台常見的起跳價接近 GBP 40,並隨流量和環境數量升到幾百英鎊。客製化基礎架構大約要在 GBP 400 以上才開始說得通。最便宜的那一級,很少是最便宜的結果。

Drupal 需要 Redis 嗎? 對一個小型匿名網站不需要,Internal Page Cache 加資料庫就夠了。一旦你有了登入使用者、編輯人員或者會員區,Redis 或 Memcached 這樣的外部物件快取就會把快取讀取、鎖定和佇列從資料庫裡搬走,而以花掉的錢來算,這通常是能買到的最大一項改善。

在動態的 Drupal 網站前面放 CDN 安全嗎? 安全,前提是依快取標籤作廢,而不是依時間。Drupal 會為一個回應所相依的一切記錄諸如 node:5 這樣的標籤,模組再把它們轉譯成 Cache-Tag 或 Surrogate-Key 標頭,於是 CDN 精準清除一次編輯所影響的那些頁面。沒有依標籤作廢,你就只能在過期頁面和形同虛設的快取之間二選一。