一般來說,要讓 Nginx 遇到 PHP 程式時,只要按照以下寫法就可以將 request 轉接給 php-fpm 處理:
server {
location / {
try_files $uri $uri/index.html =404;
}
location ~ .php* {
root /home/www/data;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
假設 project 在 document root (如上面的就是 /home/www/data),設定方式其實不難,網路到處都可以找的到。像是 Laravel 可以參考 pretty URL 的設定方式,把 index.php 隱藏起來:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
上面這個設定,可以讓 request 從「http://my.site/user/1」,被改寫為「http://my.site/index.php/user/1」,這個時候 index.php 就可以從 $_SERVER 的參數來判斷到底要走哪個 route。
但假設寫的專案沒有一個 domain name、沒辦法做 virtual host,可以讓專案根目錄當作 document root,且新的 PHP framework 都會把 index.php 放在 /public 目錄下來避免安全問題,這樣的 URL rewrite 就會出問題。
例如今天的 request 是「http://my.site/project/user/1」,在經過上面的 route 以後會被轉成「http://my.site/index.php/project/user/1」,而實際上我們需要的是「http://my.site/project/index.php/user/1」才能讓專案正確運作。
這時需要另外建立 route 規則。先把 http://my.site/project 對應到的正確檔案路徑設定好:
location ^~ /project {
# define script real path
alias /home/www/data/project/public;
try_files $uri $uri/ /project/public/index.php$uri;
}
到這邊算是設定完成一半,暫停來看一下目前 routing 的情況。請求「http://my.site/project/user/1」會被轉換為「http://my.site/project/public/index.php/project/user/1」。index.php 後半部的參數差了一點點,把「project/」片段拿掉就完成了。
這時我們再新增一條規則,使用 REGEX 來處理後面這段參數:
location @project-rule {
# 若 URI 起始為 /project/
# 把後面的參數抓出來,放在 /project/public/index.php/ 後方
rewrite ^/project/(.*)$ /project/public/index.php/$1 last;
}
調整後,完整的 Nginx URL rewrite 規則會長這樣:
location ^~ /project {
alias /home/www/data/project/public;
# 一般規則無法正確找到路徑
# 就使用 @project-rule 規則來做查詢
try_files $uri $uri/ @project-rule;
}
location @project-rule {
rewrite ^/project/(.*)$ /project/public/index.php/$1 last;
}
Nginx 的 rewrite rule 實在很難 debug,這段是自己花了數小時嘗試錯誤並觀察 $_SERVER 參數變化才找到規律的,希望多少對大家有一點幫助。