4.1 啟動 Nginx
# 安裝 Nginx
sudo yum update
sudo yum install epel-release
sudo yum install nginx
# 啟動
systemctl start nginx
# 開機時啟動
systemctl enable nginx
# 查看狀態
systemctl status nginx
假如你有依照 2.1 節的設定,現在打開本機的瀏覽器,連到 http://192.168.8.8
應該可以看到 Nginx 的預設首頁。
4.2 Nginx 文件目錄的權限設定
Nginx 預設的文件目錄在 /usr/share/nginx/html
。在開始加入自己的網頁之前,要先做幾個動作來確保 Nginx 在讀取網頁時能夠順利。
# 將 nginx 群組加入成為 tony 帳號的次要群組
sudo usermod -aG nginx tony
# 查看 tony 帳號的群組
groups tony
# 結果 tony : tony nginx # <-- 多了一個 nginx
# 將 /usr/share/nginx 之下的目錄及檔案擁有者改為 nginx:nginx
cd /usr/share/nginx
sudo chown -R nginx:nginx *
# 將 /usr/share/nginx/html 目錄及其下的子目錄加入群組寫入的權限
cd /usr/share/nginx
sudo chmod -R g+w html
# 設定 SELinux 權限
chcon -Rv --type=httpd_sys_content_t /usr/share/nginx
# 檢查 html 及其下檔案及目錄是否有 httpd_sys_content_t 這個權限
ls -Z /usr/share/nginx
我們將自己的帳號加入 nginx 群組,並將群組指定為有寫入的權限,可以避免在新增網頁時出現問題。
CentOS 的 SELinux 有時候會造成 Nginx 沒有讀取的權限,這時當你在瀏覽器開啟網頁時可能會出現 502 Bad Gateway 的錯誤。SELinux 是 Security Enhanced Linux 的縮寫,目的就是對 Linux 做安全強化,對 SELinux 來說,檔案或目錄必須有 httpd_sys_content_t
這個權限,Nginx 才能正常讀取。
SELinux 是針對程式做權限控管而非使用者,所以即使是以 root 身分操作某支程式去執行某個動作,只要該程式沒有對該目錄或行為有權限,就無法執行。例如只要該目錄或檔案沒有 httpd_sys_content_t
的權限,Nginx 程式便無法讀取,這樣可以防止 Nginx 這個程式隨意讀取其他系統上的目錄或檔案,形成保護的機制。
4.3 啟動 PHP-FPM
4.3.1 安裝
CentOS 內建的套件庫所提供的 PHP 版本有點舊,只有到第 5 版,我們必須安裝額外的套件庫才能安裝最新版本的 PHP。首先要安裝 EPEL,接著安裝其他有提供最新 PHP 版本的倉庫,例如 Webtatic 或 IUS。
# 先安裝 EPEL
sudo yum install epel-release
# 或以 rpm 檔的方式安裝
# CentOS 7
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# CentOS 6
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
# 接著選擇一個倉庫來安裝
# 安裝 Webtatic 倉庫
# CentOS 7
sudo yum install https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
# CentOS 6
sudo yum install https://mirror.webtatic.com/yum/el6/latest.rpm
# 或安裝 IUS 倉庫
# CentOS 7
sudo yum install https://centos7.iuscommunity.org/ius-release.rpm
# CentOS 6
sudo yum install https://centos6.iuscommunity.org/ius-release.rpm
安裝完成後,就可以來安裝 php-fpm 了。這裡要說明一下套件名稱,Webtatic 的套件名稱會以 w
結尾,IUS 則是以 u
結尾。
# 列出所有版本的 php-fpm
yum list php*-fpm
# 可能的結果如下
好吧,我們先來移除舊版本的再安裝 IUS 提供的新版本:
# 套件會有關聯性,所以這兩個套件必須同時移除
sudo yum remove php72w-fpm php72w-common
# 安裝套件
sudo yum install php72u-fpm
# php72u-fpm 套件依賴 php72u-common,所以它也會被要求安裝
# 啟動 php-fpm 伺服器
sudo systemctl start php-fpm
# 開機時啟動
sudo systemctl enable php-fpm
# 都安裝好之後,來查看安裝了哪些 PHP 套件
yum list installed | grep php
其他和 PHP 相關的套件:
mod_php72u
:Apache HTTP 伺服器的模組,如果你使用 Apache 的話,必須安裝此套件。
php72u-cli
:可以執行 PHP 腳本程式的命令列工具。
php72u-pdo
:提供存取 MySQL、PostgreSQL 等資料庫的抽象層介面。
php72u-mysqlnd
:提供原生 MySQL 存取驅動程式。
php72u-opcache
:快取功能。
php72u-mbstring
:支援雙位元的字串。
註:mcrypt
套件在 PHP 7.1.0 版開始被棄用,因為有安全上的問題,建議改用 Sodium (PHP 7.2.0 之後) 或 OpenSSL。
你可以一次安裝全部的套件:
sudo yum -y install php72u-fpm php72u-cli php72u-mbstring php72u-mysqlnd php72u-pdo php72u-opcache php72u-sodium
4.3.2 關於 cgi.fix_pathinfo 的問題
在較舊版本的 Nginx 和 php-fpm 搭配使用時,會有個 cgi.fix_pathinfo
的漏洞引起安全上的問題,現在可以透過使用新版本加上設定來避免。
Nginx 會有許多以 $
開頭的環境變數,在它接收到請求時,URI 會被 $fastcgi_script_name 環境變數取出成為 SCRIPT_FILENAME
及 PATH_TRANSLATED
兩個參數,然後傳遞給 php-fpm 來使用。
PHP 的配置檔中,cgi.fix_pathinfo
選項預設是開啟的 (值為 1) ,它可以用來取出 Nginx 所傳過來的 SCRIPT_FILENAME
中的腳本名稱。
漏洞是這麼發生的,Nginx 將它所解析的 SCRIPT_FILENAME
傳給 php-fpm,而 php-fpm 全然接受 Nginx 所傳過來的結果,但是 Nginx 不知道其實它被騙了,就傳了個有問題的腳本名稱給 php-fpm,而 php-fpm 找到這個腳本執行後,就出問題了。
舉例:當你的網站允許上傳圖檔 (或其他類型的檔案),某人將 bad.php 改名成 bad.jpg 後上傳,於是它可以這樣連入網址 http://myweb.com/bad.jpg/a.php,實際上並沒有 a.php ,是故意亂打的,在 cgi.fix_pathinfo
啟用的情況下,因為找不到 a.php,會往前找 bad.jpg,發現有找到於是執行,如果它是一張正常的圖片就會直接顯示,但是因為它是 bad.php 的偽裝,於是就執行了其中的 php 程式碼。
這是個存在很久的問題,早期的解法是將 cgi.fix_pathinfo
禁用來解決,例如:
# 編輯 php.ini
sudo vim /etc/php.ini
# 搜尋 cgi.fix_pathinfo
/cgi.fix_pathinfo
# 預設是啟用的,將其註解取消並改為 0
# 將 ;cgi.fix_pathinfo=1
# 改成 cgi.fix_pathinfo=0
現在己經不推薦這個做法,因為它會讓 PHP_SELF
這個全域變數壞掉,有用到此變數的系統就無法正常運作。
Nginx 上有提到正確的做法,請在使用到 PHP 的虛擬主機加上以下設定:
server {
# ...略
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
# 如果你的 php-fpm 使用 socket 請使用下面這行
# fastcgi_pass unix:/var/run/php-fpm.sock;
# 如果使用 TCP 則使用下面這行,2 選 1
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
# 加入 fastcgi_param 檔案的設定
include fastcgi_params;
# 假如 fastcgi_params 中沒有以下內容,請額外加入
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
在 /etc/nginx
目錄下可以找到 fastcgi_params
這個檔案。
4.3.3 調整 php-fpm 設定
php-fpm 的設定檔在 /etc/php-fpm.d/www.conf
它使用 ;
當註解,我們要針對 Nginx 做一些調整:
sudo vim /etc/php-fpm.d/www.conf
# 程序的使用者及群組
# 23, 24 行,改成
user = nginx
group = nginx
# 如何接受 FastCGI 請求
# 36, 40 行,2 選 1
listen = 127.0.0.1:9000 # TCP
listen = /var/run/php-fpm/php-fpm.sock # Socket
# 這裡的選擇會影響到 Nginx 中虛擬主機的 fastcgi 設定
# 對照設定如下
# fastcgi_pass 127.0.0.1:9000; # TCP
# fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # Socket
# 如果你前面選擇使用 Socket 接受請求的方式,才須做以下設定
# 如果沒有,預設會使用當前使用者的權限
# 設定 socket 的權限
# 50 ~ 52 行
listen.owner = nginx # 設定為 nobody 也可以
listen.group = nginx # 設定為 nobody 也可以
listen.mode = 0660
# 存檔離開
# 重新啟動 PHP-FPM
sudo systemctl restart php-fpm
# 重新啟動 Nginx
sudo systemctl restart nginx
註:在 vim 中顯示行號的方法:esc -> :set nu
,行號可能會略有不同,但是方便你大概知道在文件的哪個位置。
使用 TCP 或 Socket 接受 FastCGI 請求有什麼差別?使用 Socket 必須讓 Nginx 和 php-fpm 處於同一台機器,兩者視為一體,機器上的 CPU 和 RAM 會共享,當要橫向擴充時,也是一起被複製到新的機器上;使用 TCP 則是兩者解耦,一台機器上的 Nginx 可以將資料傳遞給多台機器上的 php-fpm,形成 php-fpm 叢集。
繼續閱讀:動手學 VPS 架站:使用 CentOS 7 + Nginx + PHP-FPM + MariaDB (8) - 使用 Nginx
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
我要留言
留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。