2015年8月26日 星期三

無痛入手網路界的超跑Nginx+PHP-FPM!

筆者平常開的車是toyota altis,對於超跑可說是忘塵莫及;但身為程式設計師,確每人都可入手一網路界的超跑Nginx + PHP-FPM;Nginx是一款高效能的Web Server近幾年來大幅的成長,用來取代Apache,若您開發的網站具有大流量,而且速度要求快,那麼Nginx應是您的首選!

Wikipedia的說明如下。

『Nginx是一款面向效能設計的HTTP伺服器,相較於Apache、lighttpd具有占有記憶體少,穩定性高等優勢。與舊版本(<=2.2)的Apache不同,nginx不採用每客戶機一執行緒的設計模型,而是充分使用非同步邏輯,削減了上下文排程開銷,所以並行服務能力更強。整體採用模組化設計,有豐富的模組庫和第三方模組庫,配置靈活。 在Linux作業系統下,nginx使用epoll事件模型,得益於此,nginx在Linux作業系統下效率相當高。同時Nginx在OpenBSD或FreeBSD作業系統上採用類似於epoll的高效事件模型kqueue。』

有些教學文件是整套安裝完Nginx、MySQL及PHP再測試,建議是分段安裝,有問題可容易發覺;先安裝Nginx測試成功後再安裝PHP,最後才是安裝MySQL。

基本環境

  • 使用AWS EC2 China,系統為Ubuntu14.04;HVM虛擬技術。
  • 登錄EC2後使用sudo su切換到root權限。
  • 先執行apt-update update。

常用指令

指令
說明
cd /etc/nginx/sites-enabled
虛擬網站設定目錄
cd /usr/share/nginx/html
預設網站的文件存放目錄
cd /home/ubuntu
虛擬網站文件存放目錄
cd /etc/nginx/sites-enabled/default
啟用網站目錄
cd /etc/nginx/sites-available/default
所有網站目錄
vi /etc/nginx/nginx.conf
編輯Nginx設定
vi /var/log/nginx/error.log
查看nginx錯誤訊息,很常用!

安裝Nginx

  • 安裝nginx
apt-get install nginx

  • 修改nginx配置文件
vi /etc/nginx/nginx.conf

  • 將user改為EC2用戶名,預設為ubuntu
user ubuntu;

  • 在events配置加上
use epoll;

  • 修改後設定檔如下。

user ubuntu;
worker_processes 4;
pid /run/nginx.pid;

events {
       worker_connections 768;
       use epoll;
       # multi_accept on;
}



  • 若是預設網站不是使用80 port,需要修改預設網站設定。
vi /etc/nginx/sites-enable/default

將80改為其他port,若是AWS China的ICP未通過,80、8080及443是無法使用的。
listen 80 default_server;

  • 需要注意的是default_server及server_name不需要修改,而是在之後用虛擬方式來新增;先確定Nginx在本機環境能測試運作。

測試Nginx

  • 完成後啟動
service nginx start

  • 測試Nginx是否啟動,在EC2上運行;如果輸出Welcome to nginx!字樣,說明nginx安裝成功。

  • 開放外部80端口訪問;進入安全組頁面。

螢幕快照 2015-08-22 07.57.47.png
  • 從外部網址測試,成功畫面如下。
螢幕快照 2015-08-22 08.00.14.png

安裝並配置PHP

由於要使用Nginx,所以這裡選擇安裝帶fpm版本的php
apt-get install php5-fpm

安裝相應的PHP模塊。
apt-get install php5-mysql php5-curl php5-gd php5-intl php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-ming php5-ps php5-pspell php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl

安裝PHP Command Line模組,可以直接用Command Line確認PHP的運作正常。
apt-get install php5-cli

安裝完成後,配置php-fpm,配置中出現的ubuntu為EC2的登陸用戶。
vi /etc/php5/fpm/pool.d/www.conf

修改或新增如下幾項:
user = ubuntu
group = ubuntu
listen.owner = ubuntu
listen.group = ubuntu
listen.mode = 0660

將檔案的/var/run/php5-fpm.sock所屬用戶及用戶組改為ubuntu,不然會有權限問題。
chown ubuntu:ubuntu /var/run/php5-fpm.sock
chmod 0660 /var/run/php5-fpm.sock

繼續以下操作:

vi /etc/php5/fpm/php.ini

short_open_tag = On
cgi.fix_pathinfo=0

重啟php5-fpm

service php5-fpm restart

測試PHP運作正常

  • 先檢查php5-fpm是否有正常運作。

service php5-fpm status
php5-fpm start/running, process 1084

  • 在default目錄新增phpinfo.php測試檔案。

vi /usr/share/nginx/html/phpinfo.php

<html>
<head><title> PHP Test Script </title></head>
<body>

<?php
phpinfo( );
?>
</body>
</html>

  • 單純用Command Line測試php檔案,以確認php是可以正常執行的。

php5 phpinfo.php

<html>
<head>
<title> PHP Test Script </title>
</head>
<body>

phpinfo()
PHP Version => 5.5.9-1ubuntu4.11


</body>
</html>

結合Nginx與PHP5-FPM

架設Nginx + PHP5-FPM最容易出錯的地方就是在結合兩者處,如何將Nginx的HTTP Request轉發給PHP5-FPM;與Apache不同的是PHP是用內建模組方式,但Nginx則是用轉發方式。

最簡單也不容易出錯的設定方式是將/etc/nginx/sites-available/default檔案關於PHP部份註解移除。

       vi /etc/nginx/sites-available/default

       # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
       #
       location ~ \.php$ {
              fastcgi_split_path_info ^(.+\.php)(/.+)$;
       #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
       #
              # With php5-cgi alone:
       #       fastcgi_pass 127.0.0.1:9000;
       #       # With php5-fpm:
              fastcgi_pass unix:/var/run/php5-fpm.sock;
              fastcgi_index index.php;
              include fastcgi_params;
       }

前兩行是將副檔名為PHP的檔案會轉到此區段執行。

Nginx將HTTP Request轉給PHP有兩種方式,第一種是用ip,第二種是用socket;建議使用socket的效能會較好,也就是fastcgi_pass unix:/var/run/php5-fpm.sock。

fastcgi_index index.php是定位php首頁,include fastcgi_params是包含fastcgi相關參數,此檔案在/etc/nginx/fastcgi_params。

設定完後使用指令service nginx reload或是service nginx restart指令重新載入設定;接下來使用以下指令確認是否可用網址存取php檔案,若可以則代表Nginx + PHP-FPM成功設定。

curl http://localhost/phpinfo.php
<html>
<head>
<title> PHP Test Script </title>
</head>
<body>

phpinfo()
PHP Version => 5.5.9-1ubuntu4.11

虛擬主機

虛擬主機的備置目錄有兩個。

  • /etc/nginx/sites-available/
  • /etc/nginx/sites-enabled/

將可能會用到的虛擬目錄放在sites-available目錄,而在sites-enabled用連結指向實際要啟用的。

我們嘗試新增一個虛擬目錄,先放在sites-available。


server {
       listen 80;
       root /home/ubuntu/www.v-union.com.cn;
       index index.php index.html index.htm;
       server_name www.v-union.com.cn;

       location / {
               # First attempt to serve request as file, then
               # as directory, then fall back to displaying a 404.
               try_files $uri $uri/ =404;
               # Uncomment to enable naxsi on this location
               # include /etc/nginx/naxsi.rules
       }

       # pass the PHP scripts to FastCGI server listening
       location ~ \.php$ {
               fastcgi_split_path_info ^(.+\.php)(/.+)$;
              # With php5-fpm:
               fastcgi_pass unix:/var/run/php5-fpm.sock;
               fastcgi_index index.php;
               include fastcgi_params;
       }
}

然後在sites-enabled中用連結方式指向此檔案。

cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/www.v-union.com.cn www.v-union.com.cn

需要注意的事網站文件要放在/home/ubuntu,不然權限會不足。

App設定

需要注意的事,我們可能會安裝各種App在網站上,其設定檔可能會不一樣;需要再尋找該App的相關資源進行設定,舉例而言筆者有使用magento電子商務網站,其設定檔如下參考。

server {
   listen 80;
   ## SSL directives might go here
   ## Domain is here twice so server_name_in_redirect will favour the www
   ## Forcibly prepend a www;
   server_name buy.v-union.com.cn;
   root /home/ubuntu/buy.v-union.com.cn/;    ## Forcibly prepend a www;
   location / {
       index index.html index.php;  ## Allow a static html file to be shown first
       try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler
       expires 30d; ## Assume all files are cachable
   }

   ## These locations would be hidden by .htaccess normally
   location ^~ /app/                   { deny all; }
   location ^~ /includes/              { deny all; }
   location ^~ /lib/                   { deny all; }
   location ^~ /media/downloadable/ { deny all; }
   location ^~ /pkginfo/               { deny all; }
   location ^~ /report/config.xml   { deny all; }
   location ^~ /var/                   { deny all; }

   location /var/export/ { ## Allow admins only to view export folder
       auth_basic           "Restricted"; ## Message shown in login window
       auth_basic_user_file htpasswd; ## See /etc/nginx/htpassword
       autoindex               on;
   }

   location  /. { ## Disable .htaccess and other hidden files
       return 404;
   }

   location @handler { ## Magento uses a common front handler
       rewrite / /index.php;
   }

   location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
       rewrite ^(.*.php)/ $1 last;
   }

   location ~ .php$ { ## Execute PHP scripts
       if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss

       expires         off; ## Do not cache dynamic content
       fastcgi_pass   unix:/var/run/php5-fpm.sock;
      # fastcgi_param  HTTPS $fastcgi_https;
       fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
       ## Store code is defined in administration > Configuration > Manage Stores
       ##fastcgi_param  MAGE_RUN_CODE default;
       ##fastcgi_param  MAGE_RUN_TYPE store;
       ## See /etc/nginx/fastcgi_params
       include         fastcgi_params;
   }
}

偵錯

若您在設定過程中遇到問題,可以依以下方式檢查。
  • 單獨測試Nginx或PHP是否成功,也不要先設虛擬目錄,成功後再慢慢加入設定。
  • 錯誤信息可以參考nginx錯誤信息檔案,指令為vi /var/log/nginx/error.log。
  • 先不要架設App,因為App通常是架在Apache上比較多,對於Nginx通常需額外設定。
  • 權限設定,是否有將Nginx執行者改為ubuntu;是否有修改/var/run/php5-fpm.sock的權限。
  • 先用localhost的環境測試是否成功,再用外面的網址測試,可確認是否防火牆沒開。

參考文件