文件
一個 專案

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 等級完成。 如果回應的狀態為 4xx5xx,則將改為使用 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}"
	}
}