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 套接字或 unix 套接字文件。
-
root 设置站点的根文件夹。建议始终将
root
指令 与php_fastcgi
结合使用,但当您的 PHP-FPM 上游使用与 Caddy 不同的根目录时,覆盖此设置可能很有用(请参阅 示例)。如果使用root
指令,则默认为其值,否则默认为 Caddy 的当前工作目录。 -
split 设置用于将 URI 分割成两部分的子字符串。第一个匹配的子字符串将用于从路径中分割出 “路径信息”。第一部分附加匹配的子字符串,并将被假定为实际的资源(CGI 脚本)名称。第二部分将设置为 PATH_INFO 供 CGI 脚本使用。默认值:
.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 是一个 持续时间值,用于设置连接到上游套接字时等待的时间。默认值:
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
),如果该路径存在,则将请求重写到该路径。如果您在 Web 根目录的子目录中运行另一个 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 套接字监听的 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 应用程序时,每个应用程序的 Web 根目录必须不同,以便 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}"
}
}