
在 Apache 与 PHP-FPM 协同部署时,传统 .htaccess 中的 ErrorDocument 404 可能失效,导致返回原始“File not found”而非自定义 404 页面;根本原因在于 PHP-FPM 的 SetHandler 全局接管了所有匹配文件(含不存在路径),需通过条件判断限制其仅作用于真实存在的 PHP 文件。
在 apache 与 php-fpm 协同部署时,传统 `.htaccess` 中的 `errordocument 404` 可能失效,导致返回原始“file not found”而非自定义 404 页面;根本原因在于 php-fpm 的 `sethandler` 全局接管了所有匹配文件(含不存在路径),需通过条件判断限制其仅作用于真实存在的 php 文件。
Apache 默认会将所有匹配 FilesMatch 模式的请求(如 *.php)直接交由 PHP-FPM 处理,无论该 PHP 文件是否存在。当用户访问一个不存在的路径(如 /notapage)时,若该路径恰好被 FilesMatch \.php$ 意外匹配(例如因重写规则、PATH_INFO 或模糊匹配),Apache 会尝试用 SetHandler 转发给 PHP-FPM;而 PHP-FPM 在找不到对应文件时会返回 404 响应体 "File not found." —— 这个响应绕过了 Apache 的 ErrorDocument 机制,因此自定义 404 页面完全不会触发。
解决的关键在于:仅对真实存在的 PHP 文件启用代理处理,将不存在路径的请求交还给 Apache 自身处理流程,使其能正常执行 ErrorDocument 404 指令。
✅ 正确做法是修改 PHP-FPM 的 Apache 配置(通常为 /etc/httpd/conf.d/php.conf 或 /etc/apache2/mods-enabled/php8.x.conf),将无条件的 SetHandler 替换为带存在性校验的 <If> 条件块:
<FilesMatch \.(php|phar)$>
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
</If>
</FilesMatch>? 说明:-f %{REQUEST_FILENAME} 表示仅当请求的文件物理存在时,才启用 PHP-FPM 代理。对于 /notapage 这类不存在的路径,该条件为假,Apache 将跳过 SetHandler,继续执行后续规则(包括 .htaccess 中的 ErrorDocument 404)。
立即学习“PHP免费学习笔记(深入)”;
⚠️ 注意事项:
- 切勿使用 ProxyErrorOverride On:该指令强制 Apache 用自定义错误页覆盖后端(PHP-FPM)返回的任何错误响应,虽可能“显示”404页,但会破坏 HTTP 状态码(如将 500 错误也转为 404)、干扰调试,且不符合语义规范;
- 修改配置后必须重启 Apache(sudo systemctl restart httpd 或 apache2),不能仅 reload(部分版本中 SetHandler 条件逻辑需完整重载);
- 确保 .htaccess 中的 ErrorDocument 404 指向的是站内相对路径或协议绝对路径(如 ErrorDocument 404 /404.html 更推荐,避免跨域重定向开销);
- 若使用 mod_rewrite 进行前端控制器(如 Laravel/WordPress),请确认 RewriteRule 未意外将 404 请求重写为 index.php 并触发 PHP-FPM 处理——此时也需配合 RewriteCond -f 或 -d 做存在性判断。
最终验证:访问任意不存在路径(如 /this-page-does-not-exist),应返回 HTTP 状态码 404,且响应体为你指定的自定义页面内容,而非 File not found.。



















