Nginx 一個域名下部署多個網站運行多個PHP 版本

我們可能會遇到需要在一個域名下用幾套程序來構建一個網站,這時候可能需要在在不同的目錄下綁定不同的網站。

比如 根目錄 / 是用 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地址重寫,並能靈活應用, 基本上絕大多數問題都能找到解決方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章