server {
listen 80; server_name foo.com; root /path;
location / {
index index.html index.htm index.php;
if (!-e $request_filename) {
rewrite . /index.php last;
}
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /path$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}
}
問題:
index 寫在 location 內 → 多 location 需重複;if (!-e ...) + rewrite → if 是 rewrite 模塊指令,非聲明式,易產生非預期行為;fastcgi_params 缺 SCRIPT_FILENAME 定義 → 硬編碼路徑,不靈活;try_files $uri =404 → 開啟 cgi.fix_pathinfo 時極大安全風險(任意文件解析為 PHP)。塊層級:http → server → location,內層繼承外層指令值為默認值。善用此機制消除重複。
server {
listen 80;
server_name foo.com;
root /path;
index index.html index.htm index.php; # 放 server 級,所有 location 繼承
location / {
try_files $uri $uri/ /index.php$is_args$args; # 替代 if+rewrite
}
location ~ \.php$ {
try_files $uri =404; # 安全過濾,防 cgi.fix_pathinfo 漏洞
include fastcgi.conf; # 含 SCRIPT_FILENAME $document_root$fastcgi_script_name
fastcgi_pass 127.0.0.1:9000;
}
}
| 指令 | 作用 | 為何優於舊寫法 |
|---|---|---|
| index @ server | 全局默認首頁 | 一次聲明,所有 location 生效 |
| try_files | 按序嘗試文件/目錄/回退 | 聲明式、無副作用、性能更好 |
| fastcgi.conf | 標準 fastcgi 參數含 SCRIPT_FILENAME | 避免硬編碼、避免重複定義導致數組型指令疊加 |
| try_files $uri =404 | PHP 文件必須存在才傳給 PHP-FPM | 徹底修復 cgi.fix_pathinfo=1 導致的任意代碼執行漏洞 |
fastcgi.conf 多一行:fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_param 為數組型指令:同級多次定義會疊加而非覆蓋,若同時 include 兩者並自定義 SCRIPT_FILENAME,會傳兩個值給 PHP-FPM,極其危險。統一用 fastcgi.conf。理解繼承、聲明式配置、安全過濾三大原理,拋棄「複製貼上」文化,構建乾淨、安全、可維護的 Nginx + PHP 架構。