Nginx的代碼是由一個核心和一系列的模塊組成, 核心主要用於提供Web Server的基本功能,以及Web和Mail反向代理的功能;還用於啟用網絡協議,創建必要的運行時環境以及確保不同的模塊之間平滑地進行交互。不過,大多跟協議相關的功能和某應用特有的功能都是由nginx的模塊實現的。這些功能模塊大致可以分為事件模塊、階段性處理器、輸出過濾器、變量處理器、協議、upstream和負載均衡幾個類別,這些共同組成了nginx的http功能。事件模塊主要用於提供OS獨立的(不同操作系統的事件機制有所不同)事件通知機制如kqueue或epoll等。協議模塊則負責實現nginx通過http、tls/ssl、smtp、pop3以及imap與對應的客戶端建立會話。
Nginx的核心模塊為Main和Events,此外還包括標准HTTP模塊、可選HTTP模塊和郵件模塊,其還可以支持諸多第三方模塊。Main用於配置錯誤日志、進程及權限等相關的參數,Events用於配置IO模型,如epoll、kqueue、select或poll等,它們是必備模塊。
Nginx的主配置文件由幾個段組成,這個段通常也被稱為nginx的上下文,每個段的定義格式如下所示。需要注意的是,其每一個指令都必須使用分號(;)結束,否則為語法錯誤。
<section> {
<directive><parameters>;
}
一,全局塊的配置
user username [groupname]; 指定運行worker進程的用戶和組
worker_processes 4; worker進程的個數;通常其數值應該為CPU的物理核心數減1,默認為4
error_log /path/to/error_log level [ debug | info | notice | warn | error | crit | alert | emerg ]; 錯誤日志文件及其級別,默認為error級別,錯誤日志在全局級別,訪問日志在虛擬主機級別,調試時可以使用debug級別,但要求在編譯時必須使用–with-debug啟用debug功能;
pid /path/to/pidfile_name; 指定nginx的pid文件
nginx安裝完成后,全局塊默認只有這幾個配置。
二,events塊的配置
events {
use epoll;定義使用的事件驅動模型,建議讓nginx自動選擇,默認使用epoll
worker_connections 1024;每個worker能夠並發響應最大請求數,默認為1024
}
nginx 在events只配置此兩個選項;
下面介紹 http 塊的配置,http塊的配置比較多,用法也比較靈活,以下是比較常用的配置。
http {
.....
server{
......
location {
......
}
}
server{
......
location {
......
}
}
}
三,nginx虛擬主機使用
nginx和httpd虛擬主機使用的實現一樣,都有基於端口,IP,域名的虛擬機主機。要為nginx配置虛擬主機,只需在http塊中額外定義一個server塊。
1,配置基於端口的虛擬主機時,只需修改listen中的端口號。
http{
server {
listen80;
server_name a.com;
。。。。。。
}
server {
listen8080;
server_name b.org;
。。。。。。
}
}
2,配置基於域名的虛擬主機
http{
server {
listen80;
server_name a.com;
。。。。。。
}
server {
listen80;
server_name b.org;
。。。。。。
}
}
3,配置基於IP的虛擬主機
http{
server {
listen192.168.1.110:80;
server_name a.com;
。。。。。。
}
server {
listen192.168.1.111:80;
server_name b.org;
。。。。。。
}
}
四、訪問控制access模塊(基於IP)
自上而下進行檢查,可以在 http, server, location, limit_except 中配置,與httpd中的配置類似。
語法:allow|denyaddress | CIDR | unix:| all;
location /{
root /usr/html ;
indexindex.html index.htm;
allow172.16.100.8;
allow 192.168.0.0/16;
allow 10.1.1.0/16;
denyall;
}
五,用戶認證示例
此配置是為了禁止外人訪問特定頁面時進行的限制,需要借助於httpd的htpasswd創建密碼文件。
語法:auth_basic string| off;
auth_basic_user_file file;
例:
location /server {
root/usr/html ;
access_log off; #訪問日志
auth_basic "amdin area";#認證時的說明
auth_basic_user_file /etc/nginx/.htpasswd; #密碼文件所在位置
}
六、建立下載站點autoindex模塊
此模塊為了便於用戶下載站的文件等,類似於ftp的功能,本站的ftp依是如此。
location /{
root html/ftp;
allow all;
autoindex on; #激活/關閉自動索引
autoindex_exact_size on; #設定索引時文件大小的單位(B,KB, MB 或 GB)
autoindex_localtime on; #開啟以本地時間來顯示文件時間的功能。默認為關(GMT時間)
}
七、防盜鏈
防盜鏈是為了防止別的網站盜用自己網站的圖片視頻等資源,並給自己網站的服務器造成額外的負擔。nginx使用valid_referers 指令進行配置防盜鏈規則。
(1) 定義合規的引用
valid_referers none | blocked | server_names | string …;
none : 檢測referer頭域不存在的情況
blocked:檢測referer頭域的值被防火牆或者代理服務器刪除或者偽裝的情況。這種情況下該頭域的值不以http或者https開頭。
server_names : 設置一個或多個URL,可以使用統配符 * 。
(2) 拒絕不合規的引用
if ($invalid_referer){
rewrite ^/.*$ http://www.b.org/403.html
}
示例:
location ~* \.(gif|jpg|png|swf|flv|rar|zip)$
{
root /usr/html/htdocs;
valid_referers none blocked server_names *.yangliheng.com;
if($invalid_referer){
rewrite ^/ http://www.yangliheng.com/wp-content/uploads/2016/01/QQ圖片20160131111643.png;
}
}
八、URL rewrite
rewrite用於實現URI的重寫,需要pcre的支持。
rewrite指令執行順序:
1.執行server塊的rewrite指令(這里的塊指的是server關鍵字后{}包圍的區域,其它xx塊類似)
2.執行location匹配
3.執行選定的location中的rewrite指令
如果其中某步URI被重寫,則重新循環執行1-3,直到找到真實存在的文件
如果循環超過10次,則返回500 Internal Server Error錯誤.
rewrite regex replacement [flag];
location /{
root /www/b.org; #每次被rewrite匹配並結束后,都要重新發送請求並再次到location中進行匹配,若有break則直接響應,不再發送新請求
rewrite ^/images/(.*)$ /imgs/$1 last;
}
請求順序:http://www.b.org/images/a.jpg –> http://www.b.org/imgs/a.jpg
last: 一旦被當前規則匹配並重寫后立即停止檢查后續的其它rewrite的規則,而后通過重寫后的規則重新發起請求;
break: 一旦被當前規則匹配並重寫后立即停止后續的其它rewrite的規則,而后繼續由nginx進行后續操作;
redirect: 返回302臨時重定向;
permanent: 返回301永久重定向;
location /download/ {
rewrite ^(/download/.*)/media/(.*)\..*$ $1/media/$2.mp3 break;
}
此處若為last,則nginx最多循環10次,超出之后會返回500錯誤;
注意:一般將rewrite寫在location中時都使用break標志,或者將rewrite寫在if上下文中;
rewrite_log on|off; 是否把重寫過程記錄在錯誤日志中;默認為notice級別;默認為off;
return code;用於結束rewrite規則,並且為客戶返回狀態碼;可以使用的狀態碼有204, 400, 402-406, 500-504等;
九,啟用server_status
server_status是nginx內建的一個狀態頁,用以了解nginx的狀態。
location /status {
stub_status on;
access_log off;
auth_basic "amdin area";
auth_basic_user_file /etc/nginx/.htpasswd;
allow 192.168.0.0/16;
deny all;
}
Active connections: 2
server accepts handled requests
237811 172308 244762
Reading: 0 Writing: 1 Waiting: 1
其意義分別為:
active connections – 活躍的連接數量
accepts:接受連接數;handled:已經建立的連接數;requests :通過建立的連接處理的請求的總數;
Reading:正在接受的新連接數;Writing:響應數據到客戶端的數量;Waiting:長連接中處於活動狀態的個數
十,壓縮功能
nginx 將響應報文發送至客戶端之前可以啟用壓縮功能,這能夠有效地節約帶寬,並提高響應至客戶端的速度。通常編譯nginx默認會附帶gzip壓縮的功能,因此,可以直接啟用之。
http {
gzip on;
gzip_min_length 1024; #響應也數據上限
gzip_buffers 416k; #緩存空間大小
gzip_comp_level 2; #定義壓縮等級,默認為6,壓縮比越大,效率越低
gzip_types text/plain application/x-javascript application/xml text/css; #壓縮文件類型
gzip_vary on; #啟用壓縮標識
gzip_static on; #靜態壓縮
}
gzip_proxied指令可以定義對客戶端請求哪類對象啟用壓縮功能,如“expired”表示對由於使用了expire首部定義而無法緩存的對象啟用壓縮功能,其它可接受的值還有“no-cache”、“no-store”、“private”、“no_last_modified”、“no_etag”和“auth”等,而“off”則表示關閉壓縮功能。
十一,配置反向代理
Nginx通過proxy模塊實現反向代理功能。在作為web反向代理服務器時,nginx負責接收客戶請求,並能夠根據URI、客戶端參數或其它的處理邏輯將用戶請求調度至上游服務器上(upstream server)。nginx在實現反向代理功能時的最重要指令為proxy_pass,它能夠將location定義的某URI代理至指定的上游服務器(組)上。如下面的示例中,location的/uri將被替換為上游服務器上的/newuri。
location /uri {
proxy_pass http://www.yangliheng.com:8080/newuri;
}
不過,這種處理機制中有兩個例外。一個是如果location的URI是通過模式匹配定義的,其URI將直接被傳遞至上游服務器,而不能為其指定轉換的另一個URI。例如下面示例中的/forum將被代理為http://www.yangliheng.com/forum。
location ~^/forum {
proxy_pass http://www.yangliheng.com;
proxy_set_header X-Real-IP $remote_addr;
}
將URI傳遞給后端服務器后,后端服務器日志中記錄的訪問IP為代理服務器的IP,要在后端服務器中記錄真實IP,需要修改日志記錄格式,將%h改為 %{X-Real-IP}i ,i表示引用某個參數的值
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat"%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
第二個例外是,如果在loation中使用的URL重定向,那么nginx將使用重定向后的URI處理請求,而不再考慮上游服務器上定義的URI。如下面所示的例子中,傳送給上游服務器的URI為/index.php?page=,而不是/index。
location /{
rewrite /(.*)$ /index.php?page=$1 break;
proxy_pass http://localhost:8080/index;
}
proxy模塊的指令
proxy模塊的可用配置指令非常多,它們分別用於定義proxy模塊工作時的諸多屬性,如連接超時時長、代理時使用http協議版本等。下面對常用的指令做一個簡單說明。
proxy_connect_timeout:nginx將一個請求發送至upstream server之前等待的最大時長;
proxy_cookie_domain:將upstream server通過Set-Cookie首部設定的domain屬性修改為指定的值,其值可以為一個字符串、正則表達式的模式或一個引用的變量;
proxy_cookie_path: 將upstream server通過Set-Cookie首部設定的path屬性修改為指定的值,其值可以為一個字符串、正則表達式的模式或一個引用的變量;
proxy_hide_header:設定發送給客戶端的報文中需要隱藏的首部;
proxy_pass:指定將請求代理至upstream server的URL路徑;
proxy_set_header:將發送至upsream server的報文的某首部進行重寫;
proxy_redirect:重寫location並刷新從upstream server收到的報文的首部;
proxy_send_timeout:在連接斷開之前兩次發送至upstream server的寫操作的最大間隔時長;
proxy_read_timeout:在連接斷開之前兩次從接收upstream server接收讀操作的最大間隔時長;
實例1:
server{
......
location /server/{
.......
proxy_pass http://192.168.1.111;
}
}
server{
......
location /server/{
.......
proxy_pass http://192.168.1.111/loc/;
}
}
對於這兩個配置,當客戶端請求http://www.yangliheng.com/server/時,第一個由於proxy_pass的URL中不包含uri,所以請求被轉發到http://192.168.1.111/server/;但是第二個proxy_pass的URL中包含了uri “/loc/”,所以請求會被轉發到http://192.168.1.111/loc/。所以,在使用proxy_pass指令時,如果不想改變原地址中的URI,就不要再URL中配置URI。
實例2:
server{
......
location /server/{
.......
#配置1 proxy_pass http://192.168.1.111;
#配置2 proxy_pass http://192.168.1.111/;
}
}
當客戶端清求URL為http://www.yangliheng.com/server/時,由於配置的URL未包含URI,nginx服務器不會改變原地址URI;當使用配置2時,由於配置的URL包含URI“/”,nginx服務器會將原地址的URI替換為“/”。
十二,upstream模塊
與proxy模塊結合使用的模塊中,最常用的當屬upstream模塊。upstream模塊可定義一個新的上下文,它包含了一組upstream服務器,這些服務器可能被賦予了不同的權重、不同的類型甚至可以基於維護等原因被標記為down。
upstream模塊的負載均衡算法主要有三種,輪調(round-robin)、ip哈希(ip_hash)和最少連接(least_conn)三種。
ip_hash:基於客戶端IP地址完成請求的分發,它可以保證來自於同一個客戶端的請求始終被轉發至同一個upstream服務器;
keepalive:每個worker進程為發送到upstream服務器的連接所緩存的個數;
least_conn:最少連接調度算法;
server:定義一個upstream服務器的地址,還可包括一系列可選參數,如:
weight:權重;
max_fails:最大失敗連接次數,失敗連接的超時時長由fail_timeout指定;
fail_timeout:等待請求的目標服務器發送響應的時長;
backup:用於fallback的目的,所有服務均故障時才啟動此服務器;
down:手動標記其不再處理任何請求;
例,使用upstream並定義error頁面,當upstream中的后端服務器都fail時,則返回到127.0.0.1:8080下。
upstream webservs{
server 192.168.1.116 weight=1 max_fails=2 fail_timeout=2;
server 192.168.1.109 weight=1 max_fails=2 fail_timeout=2;
server 127.0.0.1:8080 backup;
}
server {
listen 8080;
server_name localhost;
location /{
root /web/errorpage;
index index.html;
}
}
為了保持session信息讓同一客戶端定向到同一服務器,使用ip_hash算法,在ip_hash情況下不讓使用backup,也不能定義weight。但是使用ip_hash會破壞負載均衡的效果。
upstream webservs{
ip_hash;
server 192.168.1.116 max_fails=2 fail_timeout=2;
server 192.168.1.109 max_fails=2 fail_timeout=2;
#server 127.0.0.1:8080 backup;
}
此外,upstream模塊也能為非http類的應用實現負載均衡,如下面的示例定義了nginx為memcached服務實現負載均衡之目的。
upstream memcachesrvs {
server 172.16.100.6:11211;
server 172.16.100.7:11211;
}
server {
location /{
set $memcached_key "$uri?$args";
memcached_pass memcachesrvs;
error_page 404=@fallback;
}
location @fallback{
proxy_pass http://127.0.0.1:8080;
}
}
十三,if判斷語句
在location中使用if語句可以實現條件判斷,其通常有一個return語句,且一般與有着last或break標記的rewrite規則一同使用。但其也可以按需要使用在多種場景下,需要注意的是,不當的使用可能會導致不可預料的后果。
location /{
if($request_method ==“PUT”){
proxy_pass http://upload.yangliheng.com:8080;
}
if($request_uri ~"\.(jpg|gif|jpeg|png)$"){
proxy_pass http://imageservers;
break;
}
}
upstream imageservers {
server 172.16.100.8:80 weight 2;
server 172.16.100.9:80 weight 3;
}
if語句中的判斷條件
正則表達式匹配:
==: 等值比較;
~:與指定正則表達式模式匹配時返回“真”,判斷匹配與否時區分字符大小寫;
~*:與指定正則表達式模式匹配時返回“真”,判斷匹配與否時不區分字符大小寫;
!~:與指定正則表達式模式不匹配時返回“真”,判斷匹配與否時區分字符大小寫;
!~*:與指定正則表達式模式不匹配時返回“真”,判斷匹配與否時不區分字符大小寫;
文件及目錄匹配判斷:
-f, !-f:判斷指定的路徑是否為存在且為文件;
-d, !-d:判斷指定的路徑是否為存在且為目錄;
-e, !-e:判斷指定的路徑是否存在,文件或目錄均可;
-x, !-x:判斷指定路徑的文件是否存在且可執行;
十四,啟用緩存
1, 緩沖區設定
nginx在默認情況下在將其響應給客戶端之前會盡可能地接收來upstream服務器的響應報文,它會將這些響應報文存暫存於本地並盡量一次性地響應給客戶端。然而,在來自於客戶端的請求或來自upsteam服務器的響應過多時,nginx會試圖將之存儲於本地磁盤中,這將大大降低nginx的性能。因此,在有着更多可用內存的場景中,應該將用於暫存這些報文的緩沖區調大至一個合理的值。
proxy_buffer_size size:設定用於暫存來自於upsteam服務器的第一個響應報文的緩沖區大小;
proxy_buffering on|off:啟用緩沖upstream服務器的響應報文,否則,如果proxy_max_temp_file_size指令的值為0,來自upstream服務器的響應報文在接收到的那一刻將同步發送至客戶端;一般情況下,啟用proxy_buffering並將proxy_max_temp_file_size設定為0能夠啟用緩存響應報文的功能,並能夠避免將其緩存至磁盤中;
proxy_buffers 8 4k|8k:用於緩沖來自upstream服務器的響應報文的緩沖區大小;
2 ,緩存
nginx做為反向代理時,能夠將來自upstream的響應緩存至本地,並在后續的客戶端請求同樣內容時直接從本地構造響應報文。
proxy_cache zone|off:定義一個用於緩存的共享內存區域,其可被多個地方調用;緩存將遵從upstream服務器的響應報文首部中關於緩存的設定,如 “Expires”、”Cache-Control: no-cache”、 “Cache-Control: max-age=XXX”、”private”和”no-store” 等,但nginx在緩存時不會考慮響應報文的”Vary”首部。為了確保私有信息不被緩存,所有關於用戶的私有信息可以upstream上通過”no-cache” or “max-age=0″來實現,也可在nginx設定
proxy_cache_key:設定在存儲及檢索緩存時用於“鍵”的字符串,可以使用變量為其值,但使用不當時有可能會為同一個內容緩存多次;另外,將用戶私有信息用於鍵可以避免將用戶的私有信息返回給其它用戶;
proxy_cache_lock:啟用此項,可在緩存未命令中阻止多個相同的請求同時發往upstream,其生效范圍為worker級別;
proxy_cache_lock_timeout:proxy_cache_lock功能的鎖定時長;
proxy_cache_min_uses:某響應報文被緩存之前至少應該被請求的次數;
proxy_cache_path:定義一個用於保存緩存響應報文的目錄,及一個保存緩存對象的鍵及響應元數據的共享內存區域(keys_zone=name:size),其可選參數有:
levels:每級子目錄名稱的長度,有效值為1或2,每級之間使用冒號分隔,最多為3級;
inactive:非活動緩存項從緩存中剔除之前的最大緩存時長;
max_size:緩存空間大小的上限,當需要緩存的對象超出此空間限定時,緩存管理器將基於LRU算法對其進行清理;
loader_files:緩存加載器(cache_loader)的每次工作過程最多為多少個文件加載元數據;
loader_sleep:緩存加載器的每次迭代工作之后的睡眠時長;
loader_threashold:緩存加載器的最大睡眠時長;
例如: proxy_cache_path /data/nginx/cache/one levels=1 keys_zone=one:10m;
proxy_cache_use_stale:在無法聯系到upstream服務器時的哪種情形下(如error、timeout或http_500等)讓nginx使用本地緩存的過期的緩存對象直接響應客戶端請求;其格式為:
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_404 | off
proxy_cache_valid [ code …] time:用於為不同的響應設定不同時長的有效緩存時長,例如:proxy_cache_valid 200 302 10m;
proxy_cache_methods [GET HEAD POST]:為哪些請求方法啟用緩存功能;
proxy_cache_bypass string:設定在哪種情形下,nginx將不從緩存中取數據;例如:
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;
例:
http{
。。。。。。
upstream websrvs {
server 172.16.100.11 weight=1;
server 172.16.100.12 weight=1;
server 127.0.0.1:8080 backup;
}
proxy_cache_path /nginx/cache/first levels=1:2 keys_zone=first:20m max_size=1G;
add_header X-Cache"$upstream_cache_status from $server_addr";#顯示緩存從哪個服務器命中
location /{
proxy_pass http://webservs;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache first;
proxy_cache_valid 20010m;
proxy_cache_valid any 1m;
}
}
十五,nginx限速配置
nginx的限速功能通過limit_zone、limit_conn和limit_rate指令進行配置。首先需要在http上下文配置一個limit_zone,然后在需要的地方使用limit_conn和limit_rate 進行限速設置。下面是一個簡單的例子。
http {
limit_conn_zone $binary_remote_addr zone=perip:10m;
server {
location /downloads/{
limit_conn perip1;
limit_rate 50k;
}
}
}
說明:
limit_zone:語法格式“limit_req_zone $variable zone=name:size rate=rate;”,實現針對每個IP定義一個存儲session狀態的容器。這個示例中定義了一個名叫first的10m大小的容器,這個名字會在后面的limit_conn中使用。
limit_conn first 1; 限制在first中記錄狀態的每個IP只能發起一個並發連接。
limit_rate 50k; 對每個連接限速50k. 注意,這里是對連接限速,而不是對IP限速。如果一個IP允許三個並發連接,那么這個IP就是限速為limit_rate×3,在設置的時候要根據自己的需要做設置調整,要不然會達不到自己希望的目的。
限制連接數的配置如下所示。
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
...
limit_conn perip 10;
limit_conn perserver 100;
}
十六,nginx實現讀寫分離
使用nginx實現讀寫分離時,nginx作為代理服務器,將文件上傳至upstream中特定的服務器,upstream 端的服務器使用httpd,並且需要啟用dav功能。
配置nginx端:
http{
......
location /{
proxy_pass http://webservs;
if($request_method ="PUT"){
proxy_pass http://192.168.1.109;
}
}
}
在允許上傳的服務器的Directory中啟用上傳功能:
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so #這兩個模塊需要啟用,默認為啟用
<Directory"/var/www/html">
Dav on #啟用上傳
......
</Directory>
[root@localhost html]# service httpd reload
[root@localhost html]# chown -R apache.apache /var/www/html/
[root@localhost html]# curl -T /etc/issue 192.168.1.117 #上傳文件
%Total %Received%Xferd AverageSpeed Time Time Time Current
Dload Upload Total Spent Left Speed
0 47 0 0 0 0 0 0--:--:----:--:----:--:-- 0<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>201Created</title>
</head><body>
<h1>Created</h1>
<p>Resource /issue has been created.</p>
<hr />
<address>Apache/2.2.15(CentOS)Server at webservs Port80</address>
</body></html>
100 301 127 254 0 47 4527 837--:--:----:--:----:--:-- 4618
然后使用rsync+inotify或者sersync+inotify同步upstream中的其他服務器。