
当 Nginx 访问 .php 文件时浏览器直接下载源码,本质是请求未被正确转发至 PHP-FPM,而是作为静态文件返回;根本原因通常是 location 匹配逻辑冲突、SCRIPT_FILENAME 路径拼接失败或 try_files 误拦截导致 FastCGI 流程中断。
当 nginx 访问 `.php` 文件时浏览器直接下载源码,本质是请求未被正确转发至 php-fpm,而是作为静态文件返回;根本原因通常是 `location` 匹配逻辑冲突、`script_filename` 路径拼接失败或 `try_files` 误拦截导致 fastcgi 流程中断。
你遇到的问题——在树莓派 1B 上部署 selfoss 时,访问 https://rss.getty.nz 导致 index.php 被下载而非执行——是一个典型且高频的 Nginx + PHP-FPM 配置断裂现象。虽然你已重启服务并清缓存,但问题根源不在服务状态,而在于 请求路由被意外截断,致使 .php 文件从未进入 location ~ \.php$ 块处理流程。
? 根本原因:try_files 在 location / 中提前终止了 PHP 请求
查看你的配置片段:
location / {
try_files $uri /public/$uri /index.php$is_args$args =404;
}
这一行看似合理(用于支持前端路由或静态资源回退),但它存在一个致命陷阱:当请求 / 时,Nginx 会按顺序尝试:
-
$uri→/(不存在) -
/public/→/public/(通常也不存在) -
/index.php$is_args$args→ 即/index.php(存在!)
✅ 此时 Nginx 直接返回/index.php文件内容(作为静态资源),根本不会触发location ~ \.php$的匹配!
→ 结果就是:浏览器收到Content-Type: application/octet-stream或未声明类型的原始 PHP 源码,自动触发下载。
这就是 Richard Smith 指出的关键:= 后的 =404 并非问题主因,而是整个 try_files 行在 location / 中错误地将 /index.php 当作静态路径兜底返回,绕过了 FastCGI 处理链。
✅ 正确配置:分离静态与动态请求,确保 PHP 走专用 location
你需要让所有 .php 请求强制命中 location ~ \.php$ 块,同时保留对 public/ 等子目录的静态支持。推荐修改如下:
server {
server_name rss.getty.nz;
root /var/www/rss.getty;
index index.php;
# ✅ 关键修正:移除 location / 中对 /index.php 的静态兜底
location / {
try_files $uri $uri/ /public/$uri /public/$uri/ =404;
# 注意:此处不再包含 "/index.php" —— PHP 入口必须由 .php location 处理
}
# ✅ 确保 .php 请求精准进入 FastCGI 流程
location ~ \.php$ {
# 使用系统标准 fastcgi.conf(已含 SCRIPT_FILENAME 等关键参数)
include fastcgi.conf;
# 显式指定 PHP-FPM socket(与你的 php7.4-fpm.sock 一致)
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# ⚠️ 必须设置 root,确保 $document_root 正确解析
root /var/www/rss.getty;
# 可选:显式声明入口,避免歧义
fastcgi_index index.php;
}
# 其他静态规则保持不变(略)
location ~* \.(gif|jpg|png)$ { ... }
location ~ ^/(favicons|thumbnails)/.*$ { ... }
location ~* ^/(data\/logs|data\/sqlite|config\.ini|\.ht) { deny all; }
# SSL 配置(保持不变)
listen [::]:443 ssl;
...
}
? 为什么
root要在location ~ \.php$中重复声明?
因为location /的root不会继承给嵌套location。若此处不声明,$document_root将回退到http{}或server{}级默认值(如/usr/share/nginx/html),导致SCRIPT_FILENAME拼出错误路径(如/usr/share/nginx/html/index.php),PHP-FPM 报File not found。树莓派资源有限,路径错误极易静默失败。
? 验证与加固步骤(树莓派特别注意)
-
语法检查 & 重载
sudo nginx -t && sudo systemctl reload nginx
-
确认 PHP-FPM 正在运行且监听正确 socket
sudo systemctl status php7.4-fpm sudo ss -tlnp | grep php7.4-fpm # 应看到类似:u_str LISTEN 0 128 /run/php/php7.4-fpm.sock
-
检查 socket 权限(树莓派常见坑)
ls -l /run/php/php7.4-fpm.sock # 正确权限应为:srw-rw---- 1 www-data www-data # 若属主不是 www-data,编辑 /etc/php/7.4/fpm/pool.d/www.conf: # listen.owner = www-data # listen.group = www-data # 然后重启:sudo systemctl restart php7.4-fpm
-
创建测试页验证
echo "<?php phpinfo(); ?>" | sudo tee /var/www/rss.getty/info.php
访问
https://rss.getty.nz/info.php—— 应显示 PHP 信息页,而非下载。
⚠️ 其他高危配置雷区(自查清单)
- ❌
location ~ \.php$中遗漏include fastcgi.conf;或include fastcgi_params; - ❌
fastcgi_param SCRIPT_FILENAME被手动覆盖但路径错误(如写成$request_filename) - ❌
root路径末尾有多余斜杠(/var/www/rss.getty/vs/var/www/rss.getty),影响$document_root解析 - ❌ 使用
if判断!-e $request_filename做伪静态(Nginx 官方明确反对,易引发 PATH_INFO 丢失)
✅ 总结:三步锁定 PHP 执行链
| 步骤 | 检查点 | 工具命令 |
|---|---|---|
| ① 请求是否进对 location |
curl -I https://rss.getty.nz/index.php 查看 Content-Type
|
若为 text/html 或 application/x-httpd-php → 成功;若为 application/octet-stream → 未进 PHP location |
| ② PHP-FPM 是否可达 |
fastcgi_pass 地址是否与 php-fpm.conf 中 listen 一致 |
sudo grep "^listen" /etc/php/7.4/fpm/pool.d/www.conf |
| ③ 脚本路径是否真实存在 |
SCRIPT_FILENAME 拼出的路径是否可读 |
在 error.log 中搜索 "Primary script unknown"
|
遵循以上修正,你的 selfoss 将顺利通过 Nginx 执行 PHP,而非触发下载。树莓派虽性能有限,但精准的 Nginx 路由配置能最大限度规避资源浪费——毕竟,让服务器做它该做的事,才是轻量部署的核心哲学。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











