caddy本身不内置php解释器,必须通过php_fastcgi指令将.php请求转发给php-fpm处理;常见问题包括漏配php_fastcgi、地址不匹配、root路径未声明或映射错误,导致源码泄露或502错误。

PHP 脚本在 Caddy 中无法直接执行,必须通过 FastCGI 转发给 PHP-FPM
Caddy 本身不内置 PHP 解释器,它不会像 Apache 的 mod_php 或 Nginx 的嵌入式模块那样直接执行 .php 文件。你看到的“PHP 脚本没运行,只显示源码”或“502 Bad Gateway”,基本都卡在这一步——Caddy 没把请求正确交给 php-fpm。
核心动作是:Caddy 接收 HTTP 请求 → 判断路径匹配 .php → 用 php_fastcgi 指令把请求转给本地或远程的 php-fpm 进程(通常是 127.0.0.1:9000 或 Unix socket)→ php-fpm 执行脚本并返回响应。
配置 php_fastcgi 时最常见的三个错
多数问题出在 Caddyfile 的 FastCGI 配置上,不是 PHP 没装好,而是 Caddy 不知道怎么连、连谁、连什么路径。
- 漏写
php_fastcgi指令,只写了file_server—— 这会导致.php文件被当成静态文件直接返回源码 - 地址写错:
php_fastcgi 127.0.0.1:9000但php-fpm实际监听的是/run/php/php8.2-fpm.sock(Ubuntu/Debian 默认),或反过来 - 没配
root或路径映射错误,导致SCRIPT_FILENAME环境变量传给 PHP-FPM 的是空路径或错误路径,PHP 报No input file specified.
正确示例(Unix socket 方式,推荐):
localhost {
root * /var/www/html
php_fastcgi unix//run/php/php8.2-fpm.sock
file_server
}
注意:root 必须在 php_fastcgi 前声明,否则 FastCGI 无法解析真实文件路径。
验证 PHP-FPM 是否就绪,别只看 systemctl status php8.2-fpm
服务 running ≠ 可用。常见假阳性:
-
php-fpm进程在,但监听地址被注释或改成了127.0.0.1:9001,而 Caddy 还在连:9000 - socket 文件权限不对,Caddy 进程(通常是
caddy用户)无法读写/run/php/php8.2-fpm.sock -
listen.owner和listen.group在/etc/php/8.2/fpm/pool.d/www.conf里设成了www-data,但 Caddy 没加进这个组
快速验证命令:
sudo ss -tulpn | grep ':9000\|php-fpm\|sock' # 查看是否真在监听;若用 socket,检查: ls -l /run/php/php8.2-fpm.sock
调试时打开 Caddy 的日志和 PHP 的错误报告
默认 Caddy 日志不输出 FastCGI 错误详情,PHP 也可能静默失败。
- 在 Caddyfile 里加
log块,捕获 upstream 错误:
log {
output file /var/log/caddy/error.log
}
- 确保 PHP 的
display_errors = On和log_errors = On在php.ini里启用,并确认error_log路径可写 - 临时在 PHP 脚本开头加
error_reporting(E_ALL); ini_set('display_errors', '1');,排除配置覆盖问题
典型报错线索:upstream timed out (110: Connection timed out) → PHP-FPM 没响应;connect() failed (111: Connection refused) → 地址/端口/sock 不通;Primary script unknown → root 或 php_fastcgi 路径映射错。
最常被忽略的是:Caddy 的 root 路径必须和 PHP-FPM 实际要执行的文件物理路径完全一致,且 php_fastcgi 指令必须出现在该路由块内——放错位置(比如套在另一个 handle 里没生效)就等于没配。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











