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
結合使用,但當您的 PHP-FPM 上游使用與 Caddy 不同的根目錄時,覆蓋此設定可能很有用(請參閱範例)。 如果使用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
# This redirection is automatically disabled if "{http.request.uri.path}/index.php"
# doesn't appear in the try_files list
@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 and assume index.php always exists
@indexFiles file {
try_files {path} {path}/index.php index.php
try_policy first_exist_fallback
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 對該目錄的請求有效。僅當
try_files
子指令包含{path}/index.php
(預設值)時,才會發生此規範化。這是通過使用請求比對器來執行的,該比對器僅比對不以斜線結尾且對應於磁碟上包含
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}"
}
}