php_fastcgi
一種意見化的指令,可將要求代理至 PHP FastCGI 伺服器,例如 php-fpm。
Caddy 的 reverse_proxy
能夠服務任何 FastCGI 應用程式,但此指令特別針對 PHP 應用程式打造。此指令是一個便利的捷徑,取代了 較長的組態。
它預期網站根目錄中的任何 index.php
都會作為路由器。如果這不是你想要的,請重新組態 try_files
子指令 以修改預設的改寫行為,或以 展開式 為基礎,並根據你的需求自訂它。
除了下列的子指令之外,此指令也支援 reverse_proxy
的所有子指令。例如,你可以啟用負載平衡和健康檢查。
大多數現代的 PHP 應用程式不需要額外的子指令或自訂就能正常運作。子指令通常只用於某些特殊情況或搭配舊版的 PHP 應用程式。
語法
php_fastcgi [<matcher>] <php-fpm_gateways...> {
root <path>
split <substrings...>
index <filename>|off
try_files <files...>
env [<key> <value>]
resolve_root_symlink
capture_stderr
dial_timeout <duration>
read_timeout <duration>
write_timeout <duration>
<any other reverse_proxy subdirectives...>
}
-
<php-fpm_gateways...> 是 FastCGI 伺服器的 位址。通常是 TCP socket 或 unix socket 檔案。
-
root 將 root 資料夾設定為網站。建議在使用
php_fastcgi
時,總是使用root
指令,但當你的 PHP-FPM 上游使用與 Caddy 不同的 root 時,覆寫此指令會很有用(請參閱 範例)。如果使用,則預設為root
指令 的值,否則預設為 Caddy 的目前工作目錄。 -
split 設定用於將 URI 分割為兩部分的子字串。第一個匹配的子字串將用於將「路徑資訊」從路徑中分割出來。第一個部分加上匹配的子字串,並假設為實際資源(CGI 腳本)名稱。第二個部分將設定為 CGI 腳本要使用的 PATH_INFO。預設:
.php
-
index 指定要視為目錄索引檔案的檔案名稱。這會影響 擴充形式 中的檔案比對器。預設:
index.php
。當找不到匹配的檔案時,可以設定為off
以停用重寫回退到index.php
。 -
try_files 指定預設 try-files 重寫的覆寫。有關詳細資訊,請參閱
try_files
指令。預設:{path} {path}/index.php index.php
。 -
env 將額外的環境變數設定為給定的值。可以指定多次以設定多個環境變數。預設情況下,所有相關的 FastCGI 環境變數(包括 HTTP 標頭)都已設定,但你可以視需要新增或覆寫變數。
-
resolve_root_symlink 當
root
目錄是符號連結 (symlink) 時,這會啟用將其解析為實際值。這有時會用作部署策略,只需將符號連結交換為指向另一個目錄中的新版本即可。預設停用,以避免重複的系統呼叫。 -
capture_stderr 啟用擷取和記錄上游 fastcgi 伺服器在
stderr
上傳送的任何訊息。預設以WARN
等級進行記錄。如果回應有4xx
或5xx
狀態,則會改用ERROR
等級。預設情況下,會忽略stderr
。 -
dial_timeout 是一個 持續時間值,用於設定連線到上游 socket 時要等待多久。預設:
3s
。 -
read_timeout 是一個 持續時間值,用於設定從 FastCGI 上游讀取時要等待多久。預設:沒有逾時。
-
write_timeout 是一個 持續時間值,用於設定傳送至 FastCGI 上游時要等待多久。預設:沒有逾時。
由於此指令是對反向代理的意見化包裝,因此你可以使用任何 reverse_proxy
的子指令自訂它。
展開式
php_fastcgi
指令(無子指令)與下列設定相同。大多數現代 PHP 應用程式都能順利使用此預設值。若您的應用程式無法順利使用,請自行參照此設定並依需要自訂,而非使用 php_fastcgi
捷徑。
route {
# Add trailing slash for directory requests
@canonicalPath {
file {path}/index.php
not path */
}
redir @canonicalPath {http.request.orig_uri.path}/ 308
# If the requested file does not exist, try index files
@indexFiles file {
try_files {path} {path}/index.php index.php
split_path .php
}
rewrite @indexFiles {file_match.relative}
# Proxy PHP files to the FastCGI responder
@phpFiles path *.php
reverse_proxy @phpFiles <php-fpm_gateway> {
transport fastcgi {
split .php
}
}
}
說明
-
第一個區段處理要求路徑的正規化。目標是確保目標為磁碟上目錄的請求實際上已將尾斜線
/
新增至請求路徑,如此一來,只有單一 URL 對該目錄的請求有效。這是透過使用請求比對器執行,該比對器只比對不以斜線結尾的請求,且對應至磁碟上包含
index.php
檔案的目錄,如果比對成功,則執行 HTTP 308 重新導向,並附加上尾斜線。例如,如果磁碟上存在/foo/index.php
,則會將路徑為/foo
的請求重新導向至/foo/
(附加上/
,以正規化目錄的路徑)。 -
下一個區段處理根據磁碟上是否存在相符檔案來執行路徑改寫。這也具有記住
.php
之後路徑部分的副作用(如果請求路徑中有.php
)。這對於 Caddy 正確設定 FastCGI 環境變數非常重要。-
首先,它會檢查
{path}
是否為磁碟上存在的檔案。如果是,則會改寫至該路徑。這基本上會短路其餘部分,並確保對確實存在於磁碟上的檔案的請求不會被改寫(請參閱以下步驟)。因此,例如,如果您在磁碟上有一個/js/app.js
檔案,則對該路徑的請求將保持不變。 -
其次,它會檢查
{path}/index.php
是否為磁碟上存在的檔案。如果是,則會改寫至該路徑。對於目錄(例如/foo/
)的請求,它會尋找/foo//index.php
(會正規化為/foo/index.php
),如果存在,則會將請求改寫至該路徑。如果您在網站根目錄的子目錄中執行另一個 PHP 應用程式,則此行為有時會很有用。 -
最後,如果該檔案存在,它會改寫至
index.php
(對於現代 PHP 應用程式,幾乎總是應該存在)。這允許您的 PHP 應用程式使用index.php
腳本作為其進入點,來處理任何不對應至磁碟上檔案的路徑的請求。
-
-
最後,最後一個區段實際上會將請求代理至您的 PHP FastCGI(或 PHP-FPM)服務,以實際執行您的 PHP 程式碼。請求比對器只會比對以
.php
結尾的請求,因此,不是 PHP 腳本且確實存在於磁碟上的任何檔案不會由這個指令處理,且會中斷。
php_fastcgi
指令通常不足以單獨使用。它幾乎總是與 root
指令 配合使用,以設定檔案在磁碟上的位置(對於現代 PHP 應用程式,這可能是 /var/www/html/public
,其中 public
目錄包含您的 index.php
),以及 file_server
指令 來提供您的靜態檔案(您的 JS、CSS、影像等),這些檔案不會由這個指令處理,而是會透過其他方式處理。
範例
將所有 PHP 要求代理到監聽於 127.0.0.1:9000
的 FastCGI 回應器
php_fastcgi 127.0.0.1:9000
相同,但僅適用於 /blog/
下的要求
php_fastcgi /blog/* localhost:9000
當透過 Unix socket 使用 PHP-FPM 監聽時
php_fastcgi unix//run/php/php8.2-fpm.sock
root
指令 幾乎總是用於指定包含 PHP 程式碼的目錄,而 file_server
指令 則用於提供靜態檔案
example.com {
root * /var/www/html/public
php_fastcgi 127.0.0.1:9000
file_server
}
當使用 Caddy 提供多個 PHP 應用程式時,每個應用程式的網站根目錄必須不同,以便 Caddy 能夠分別讀取和提供您的靜態檔案,並偵測 PHP 檔案是否存在。
如果您使用 Docker,您的 PHP-FPM 容器通常會將檔案掛載在相同的根目錄。在這種情況下,解決方案是將檔案掛載到您的 Caddy 容器中的不同目錄,然後使用 root
子指令 為每個容器設定根目錄
app1.example.com {
root * /srv/app1/public
php_fastcgi app1:9000 {
root /var/www/html/public
}
file_server
}
app2.example.com {
root * /srv/app2/public
php_fastcgi app2:9000 {
root /var/www/html/public
}
file_server
}
對於不使用 index.php
作為進入點的 PHP 網站,您可以改為發出 404
錯誤。錯誤可以透過 handle_errors
指令 捕捉和處理
example.com {
php_fastcgi localhost:9000 {
try_files {path} {path}/index.php =404
}
handle_errors {
respond "{err.status_code} {err.status_text}"
}
}