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
@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
的请求重定向到/foo/
(附加/
以规范化目录的路径),如果磁盘上存在/foo/index.php
。 -
下一部分处理根据磁盘上是否存在匹配文件来执行路径重写。这也具有记住
.php
之后路径部分的副作用(如果请求路径中包含.php
)。这对于 Caddy 正确设置 FastCGI 环境变量非常重要。-
首先,它检查
{path}
是否是磁盘上存在的文件。如果是,则重写到该路径。这实际上会短路其余部分,并确保针对磁盘上确实存在的文件的请求不会被其他方式重写(见下面的步骤)。例如,如果您在磁盘上有一个/js/app.js
文件,那么对该路径的请求将保持不变。 -
其次,它检查
{path}/index.php
是否是磁盘上存在的文件。如果是,则重写到该路径。对于像/foo/
这样的目录的请求,它将查找/foo//index.php
(它会被规范化为/foo/index.php
),如果存在,则将请求重写到该路径。这种行为有时很有用,如果您在 webroot 的子目录中运行另一个 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 应用程序时,每个应用程序的 webroot 必须不同,以便 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}"
}
}