我們可能會遇到需要在一個域名下用幾套程序來構建一個網站,這時候可能需要在在不同的目錄下綁定不同的網站。
比如 根目錄 /
是用 Laravel 構建的cms程序,/blog
下綁定的是一個 wordpress 開源博客程序。
問題一:如何將不同程序的代碼目錄綁定到一個域名下的不同路徑?
一般來說各個網站的程序代碼在服務器上存放的位置是並列的。比如 /data/wwwroot/cms/
,/data/wwwroot/blog
我們要做的是將各個代碼目錄綁定在一個域名下的目錄樹上。
比如 http://demo.com/
指向訪問cms程序http:/demo.com/blog
訪問博客程序,(有點像 Linux文件系統的掛載)
處理方法是在 server{}
中根據請求路徑設置不同的 root
( 網站根目錄)
情況一, server 塊下只有一個域名,解決方法:
server {
server_name demo.com ;
index index.php index.html;
if ($host ~* ^demo\.com$) {
set $rootdir "/data/wwwroot/cms";
}
if ($request_uri ~* ^/blog/?.*) {
set $rootdir "/data/wwwroot/blog";
}
//如果有論壇程序,可以再綁定到 /bbs 目錄
if ($request_uri ~* ^/bbs/?.*) {
set $rootdir "/data/wwwroot/bbs";
}
root $rootdir;
}
這種情況比較簡單,根據請求路徑設置不同的根目錄路徑就行了。
情況二 server 塊下有多個域名
下面代碼做參考
server {
server_name demo.com api.demo.com;
index index.php index.html;
set $flag 0;
if ($host ~* ^demo\.com$) {
set $flag "${flag}1";
}
if ($request_uri ~* ^/blog/?.*) {
set $flag "${flag}2";
}
if ($flag = "01") {
set $rootdir "/data/wwwroot/cms";
}
// 當請求域名爲 demo.com, 並且 路徑爲 /blog 開頭時,設置代碼根目錄
if ($flag = "012") {
set $rootdir "/data/wwwroot/blog";
}
root $rootdir;
}
因爲 Nginx 不支持if的多條件 and 和 or, 這裏用變通的方式,通過設置了一個 $flag
變量的值實現了 and,當 $flag
值爲 012
時,表示 請求域名爲 demo.com, 並且 路徑爲 /blog 開頭,則設置代碼根目錄爲blog的目錄/data/wwwroot/blog
, 當 $flag
值爲 01
表示,請求域名爲 demo.com
, 路徑不爲 blog
,則設置代碼根目錄爲 cms的目錄 /data/wwwroot/cms
問題二 如何用不同的PHP 版本運行不同的網站?
假如 blog 程序比較老只能運行 PHP5 ,而cms 程序比較新, 只能運行 PHP7 , 這時候要解決在一個 server 塊下 ,多個PHP 版本並行的問題。
我們一般一個 server 塊下只有一個 PHP 處理塊, 例如:
location /{
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.(php)?$ {
fastcgi_pass 127.0.0.1:9000;
if ($request_filename !~* \.php$) {
return 403;
}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
首先要並行多個版本的PHP ,要滿足兩個條件:
- 需要將它們的啓動在不同的服務器,或者同一服務器下的不同的端口上, 例如把 PHP7 啓動在
9000
端口下, 把 PHP5 啓動在9001
端口下。 - 爲了能讓請求進到不同的PHP 處理,兩個處理塊的判斷規則必須不一樣,不能都是
location ~ \.(php)?$
實現代碼如下:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location /blog {
try_files $uri $uri/ /blog_index.php?$query_string;
}
//運行PHP7
location ~ \.(php)?$ {
fastcgi_pass 127.0.0.1:9000;
if ($request_filename !~* \.php$) {
return 403;
}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
//運行PHP5
location ^~ /blog_index.php {
fastcgi_pass 127.0.0.1:9001;
if ($request_filename !~* \.php$) {
return 403;
}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
一般程序的入口文件名都是 index.php
, 在blog的程序根目錄下可能沒有 blog_index.php
這個文件, 但是爲了區分兩個 PHP 處理塊的 location 判斷規則, 我們需要把入口文件強行重名命。
另外 ^~
表示非正則匹配, 匹配到後不繼續進行正則匹配, 所以不會再走到另一個PHP 處理塊中。
總結
Nginx 中 if 、location 、rewrite、變量 很重要, 能夠深刻理解 location 匹配、rewrite地址重寫,並能靈活應用, 基本上絕大多數問題都能找到解決方法。