nginx應用總結(1)-- 基礎知識和應用配置梳理

散盡浮華發表於2016-11-23

 

在linux系統下使用nginx作為web應用服務,用來提升網站訪問速度的經驗已五年多了,今天在此對nginx的使用做一簡單總結。

一、nginx服務簡介
Nginx是一個高效能的HTTP和反向代理伺服器,也是一個 IMAP/POP3/SMTP代理伺服器。Nginx 已經因為它的穩定性、豐富的功能集、示例配置檔案和低系統資源的消耗而聞名了。

使用 Nginx 前必須瞭解的事項:
1)目前官方 Nginx 並不支援 Windows,您只能在包括 Linux、UNIX、BSD 系統下安裝和使用;
2)Nginx 本身只是一個 HTTP 和反向代理伺服器,它無法像 Apache 一樣通過安裝各種模組來支援不同的頁面指令碼,例如 PHP、CGI 等;
3)Nginx 支援簡單的負載均衡和容錯;
4)支援作為基本 HTTP 伺服器的功能,例如日誌、壓縮、Byte ranges、Chunked responses、SSL、虛擬主機等等,應有盡有。

Nginx工作原理:
Nginx由核心和一系列模組組成,核心提供web服務的基本功能,如啟用網路協議,建立執行環境,接收和分配客戶端請求,處理模組之間的互動。Nginx的各種功能和操作都由模組來實現。Nginx的模組從結構上分為核心模組、基礎模組和第三方模組。
1)核心模組: HTTP模組、EVENT模組和MAIL模組
2)基礎模組: HTTP Access模組、HTTP FastCGI模組、HTTP Proxy模組和HTTP Rewrite模組
3)第三方模組: HTTP Upstream Request Hash模組、Notice模組和HTTP Access Key模組及使用者自己開發的模組
這樣的設計使Nginx方便開發和擴充套件,也正因此才使得Nginx功能如此強大。Nginx的模組預設編譯進nginx中,如果需要增加或刪除模組,需要重新編譯Nginx,這一點不如Apache的動態載入模組方便。如果有需要動態載入模組,可以使用由淘寶網發起的web伺服器Tengine,在nginx的基礎上增加了很多高階特性,完全相容Nginx,已被國內很多網站採用。

Nginx處理連線過程:
nginx不會為每個連線派生程式或執行緒,而是由 worker 程式通過監聽共享套接字接受新請求,並且使用高效的迴圈來處理數千個連線。Nginx 不使用仲裁器或分發器來分發連線,這個工作由作業系統核心機制完成。監聽套接字在啟動時就完成初始化,worker 程式通過這些套接字接受、讀取請求和輸出響應。

Nginx的工作模式很簡單,就是採用一個master程式和多個worker工作程式:
其中master程式的作用也是很明確的就是負責管理worker程式,同時監聽連線請求,當連線請求到來之後將連線放入worker程式中去處理具體的業務請求,比如說http請求。 Nginx能夠處理高併發的原因在於對socket的管理方式是非同步非阻塞的,使用select/poll/epoll/kqueue 來實現對大量socket描述符的管理,每個worker程式有一個主執行緒,而沒有其他的執行緒這樣的好處就在於不需要進行執行緒間的切換,這樣就節省了資源。所以總的來說:Nginx能夠實現支援高併發的同時執行效率還很低的關鍵在於整個系統內部只有有限的幾個工作程式和一個監聽程式,而每個程式內部只有一個主執行緒,這樣就不會引起很多的執行緒切換,從而降低了系統開銷,同時每個執行緒內部使用非同步非阻塞的方式來管理描述符這樣就可以管理大量的描述符,當描述符多的時候也只是會佔用較多的記憶體而已,而不會造成佔用大量cpu時間。以上說的就是Nginx的程式模型和事件模型,事件模型中處理的情況主要有三種,分別是網路事件,如HTTP請求等,網路事件使用非同步非阻塞模式就可以很好的解決;還有訊號,定時器,訊號和定時器還不是很明白。Nginx處理程式間爭奪系統資源的方式:也就是程式間存在的驚群現象。

master:
當 nginx 在啟動後,會有一個 master 程式和多個 worker 程式。master程式主要用來管理worker程式,master 要做的就是:接收來自外界的訊號,向各 worker 程式傳送訊號,監控 worker 程式的執行狀態,當 worker 程式退出後(異常情況下),會自動重新啟動新的 worker 程式。
主要完成如下工作:
1)讀取並驗證配置資訊;
2)建立、繫結及關閉套接字;
3)啟動、終止 worker 程式及維護 worker 程式的個數;
4)無須中止服務而重新配置工作;
5)控制非中斷式程式升級,啟用新的二進位制程式並在需要時回滾至老版本;
6)重新開啟日誌檔案;
7)編譯嵌入式perl指令碼

worker:
對於基本的網路事件,則是放在 worker 程式中來處理了。多個 worker 程式之間是對等的,他們同等競爭來自客戶端的請求,各程式互相之間是獨立的。一個請求,只可能在一個 worker 程式中處理,一個 worker 程式,不可能處理其它程式的請求(一對一)。然而 nginx 沒有專門地仲裁或連線分佈的 worker,這項工作是由作業系統核心機制完成的。在啟動時,建立一組初始的監聽套接字,HTTP 請求和響應之時,worker 連續接收、讀取和寫入套接字。
worker 程式主要完成的任務包括:
1)接收、傳入並處理來自客戶端的連線;
2)提供反向代理及過濾功能;
3)nginx任何能完成的其它任務

舉例說明一個完整請求如何通過互相協作來實現的:
既然worker程式之間是平等的,每個程式,處理請求的機會也是一樣的。當我們提供80埠的http服務時,一個連線請求過來,每個程式都有可能處理這個連線。那麼問題來了,到底最後怎樣處理,是由什麼決定的呢?首先,每個 worker 程式都是從 master 程式 fork 過來,在 master 程式裡面,先建立好需要 listen 的 socket(listenfd)之後,然後再 fork 出多個 worker 程式。所有 worker 程式的 listenfd 會在新連線到來時變得可讀,為保證只有一個程式處理該連線,所有 worker 程式會在註冊 listenfd 讀事件前搶 accept_mutex,搶到互斥鎖的那個程式註冊 listenfd 讀事件,然後在讀事件裡呼叫 accept 接受該連線。當一個 worker 程式在 accept 這個連線之後,就開始讀取請求、解析請求、處理請求。產生資料後,再返回給客戶端,最後才斷開連線,這樣一個完整的請求就是這樣的了。我們可以看到:一個請求,完全由 worker 程式來處理,而且只在一個 worker 程式中處理。

也許有個疑問,那就是nginx採用多worker 的方式來處理請求,每個 worker 裡面只有一個主執行緒,那能夠處理的併發數很有限啊,多少個 worker 就能處理多少個併發,何來高併發呢?
然而,這就是 nginx 的高明之處,nginx 採用了非同步非阻塞的方式來處理請求,也就是說,nginx 是可以同時處理成千上萬個請求的。

非同步非阻塞
非同步的概念是和同步相對的,也就是不同事件之間不是同時發生的。非阻塞的概念是和阻塞對應的,阻塞是事件按順序執行,每一事件都要等待上一事件的完成,而非阻塞是如果事件沒有準備好,這個事件可以直接返回,過一段時間再進行處理詢問,這期間可以做其他事情。

二、nginx相對於傳統的apache服務的優缺點
nginx相對比apache,實在有太多的優勢。可以說,現在Nginx才是Web伺服器的首選!!
1)nginx相對於apache的優點:
輕量級,同樣起web 服務,比apache 佔用更少的記憶體及資源;
抗併發,nginx 處理請求是非同步非阻塞的,而apache 則是阻塞型的,在高併發下nginx 能保持低資源低消耗高效能;
高度模組化的設計,編寫模組相對簡單;
社群活躍,各種高效能模組出品迅速;
當然apache相對於nginx也有它自身的優點:rewrite比nginx 的rewrite強大;模組超多,基本想到的都可以找到;少bug,nginx的bug相對較多;超穩定;apache有自帶php解析功能(apache環境部署好後,不需要再啟動php服務,apache自動解析php檔案,機器上只要有php命令即可;但是nginx不行,nginx必須結合php服務才能解析php檔案,兩則服務都要啟動)

存在就是理由,一般來說,需要效能的web 服務,用nginx 。
如果不需要效能只求穩定,那就用apache。
後者的各種功能模組實現得比前者,例如ssl 的模組就比前者好,可配置項多。
這裡要注意一點,epoll(freebsd 上是 kqueue )網路IO 模型是nginx 處理效能高的根本理由,但並不是所有的情況下都是epoll 大獲全勝的,如果本身提供靜態服務的就只有寥寥幾個檔案,apache 的select 模型或許比epoll 更高效能。當然,這只是根據網路IO 模型的原理作的一個假設,真正的應用還是需要實測了再說的。

2)作為 Web 伺服器:相比 Apache,Nginx 使用更少的資源,支援更多的併發連線,體現更高的效率,這點使 Nginx 尤其受到虛擬主機提供商的歡迎。在高連線併發的情況下,Nginx是Apache伺服器不錯的替代品: Nginx在美國是做虛擬主機生意的老闆們經常選擇的軟體平臺之一. 能夠支援高達 50,000 個併發連線數的響應, 感謝Nginx為我們選擇了 epoll and kqueue 作為開發模型.
Nginx作為負載均衡伺服器: Nginx 既可以在內部直接支援 Rails 和 PHP 程式對外進行服務, 也可以支援作為 HTTP代理 伺服器對外進行服務. Nginx採用C進行編寫, 不論是系統資源開銷還是CPU使用效率都比 Perlbal 要好很多.
作為郵件代理伺服器: Nginx 同時也是一個非常優秀的郵件代理伺服器(最早開發這個產品的目的之一也是作為郵件代理伺服器), Last.fm 描述了成功並且美妙的使用經驗.
Nginx 是一個安裝非常的簡單 , 配置檔案非常簡潔(還能夠支援perl語法), Bugs 非常少的伺服器: Nginx 啟動特別容易, 並且幾乎可以做到7*24不間斷執行,即使執行數個月也不需要重新啟動. 你還能夠不間斷服務的情況下進行軟體版本的升級 .
3)Nginx 配置簡潔,Apach複雜;Nginx靜態處理效能比Apache高3倍以上;Apache對PHP支援比較簡單,Nginx需要配合其他後端用;Apache的元件比Nginx多;
4)最核心的區別在於apache是同步多程式模型,一個連線對應一個程式;nginx是非同步的,多個連線(萬級別)可以對應一個程式
5)nginx處理靜態檔案好,耗費記憶體少.但apache目前也有它的優勢,有很多豐富的特性.所以還需要搭配著來.當然如果能確定nginx就適合需求,那麼使用nginx會是更經濟的方式.
6)從個人過往的使用情況來看,nginx的負載能力比apache高很多。最新的伺服器也改用nginx了。而且nginx改完配置能-t測試一下配置有沒有問題,apache重啟的時候發現配置出錯了,會很崩潰,改的時候都會非常小心翼翼現在看有好多叢集站,前端nginx抗併發,後端apache叢集,配合的也不錯。
7)nginx處理動態請求是雞肋,一般動態請求要apache去做,nginx只適合靜態和反向。
8)從個人經驗來看,nginx是很不錯的前端伺服器,負載效能很好,linux伺服器上運營nginx,用webbench模擬10000個個靜態檔案請求毫不吃力。apache對php等語言的支援很好,此外apache有強大的支援網路,反正時間相對nginx更久,bug少,但是apache有先天不支援多核心處理負載雞肋的缺點,所以建議使用nginx做前端,後端用apache。大型網站建議用nginx自代的叢集功能!
9)Nginx優於apache的主要兩點還體現在:Nginx本身就是一個反向代理伺服器;Nginx支援7層負載均衡;其他的當然,Nginx可能會比apache支援更高的併發;Aapche因為其成熟的技術和開發社群,總體來說也有非常不錯的效能,很多大公司而言還比較青睞apache。
10)你對web server的需求決定你的選擇。大部分情況下nginx都優於apache,比如說靜態檔案處理、PHP-CGI的支援、反向代理功能、前端Cache、維持連線等等。在Apache+PHP(prefork)模式下,如果PHP處理慢或者前端壓力很大的情況下,很容易出現Apache程式數飆升,從而拒絕服務的現象。
11)對於nginx,我喜歡它配置檔案寫的很簡潔,正則配置讓很多事情變得簡單執行效率高,佔用資源少,代理功能強大,很適合做前端響應伺服器
12)Apache在處理動態有優勢,Nginx併發性比較好,CPU記憶體佔用低,如果rewrite頻繁,那還是Apache更好。

三、在 Linux 下安裝 Nginx
為了確保能在Nginx中使用正規表示式進行更靈活的配置,安裝之前需要確定系統是否安裝有PCRE(Perl Compatible Regular Expressions)包。
您可以到ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/下載最新的PCR 原始碼包,使用下面命令下載編譯和安裝 PCRE 包:
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.7.tar.gz
# tar zxvf pcre-7.7.tar.gz
# cd pcre-7.7
# ./configure
# make
# make install
接下來安裝 Nginx,Nginx 一般有兩個版本,分別是穩定版和開發版,您可以根據您的目的來選擇這兩個版本的其中一個,下面是把 Nginx 安裝到 /opt/nginx 目錄下的詳細步驟:
# wget http://sysoev.ru/nginx/nginx-0.6.31.tar.gz
# tar zxvf nginx-0.6.31.tar.gz
# cd nginx-0.6.31
# ./configure --with-http_stub_status_module --prefix=/opt/nginx
# make
# make install
其中引數 --with-http_stub_status_module 是為了啟用 nginx 的 NginxStatus 功能,用來監控 Nginx 的當前狀態。
安裝成功後/opt/nginx 目錄下有四個子目錄分別是:conf、html、logs、sbin 。
其中Nginx的配置檔案存放於conf/nginx.conf,Nginx只有一個程式檔案位於sbin目錄下的nginx檔案。
確保系統的80埠沒被其他程式佔用,執行sbin/nginx命令來啟動Nginx,開啟瀏覽器訪問此機器的 IP,如果瀏覽器出現 Welcome to nginx! 則表示 Nginx 已經安裝並執行成功。

常用的 Nginx 引數和控制
程式執行引數
Nginx 安裝後只有一個程式檔案,本身並不提供各種管理程式,它是使用引數和系統訊號機制對 Nginx 程式本身進行控制的。 Nginx 的引數包括有如下幾個:
-c <path_to_config>:使用指定的配置檔案而不是 conf 目錄下的 nginx.conf 。
-t:測試配置檔案是否正確,在執行時需要重新載入配置的時候,此命令非常重要,用來檢測所修改的配置檔案是否有語法錯誤。
-v:顯示 nginx 版本號。
-V:顯示 nginx 的版本號以及編譯環境資訊以及編譯時的引數。
例如我們要測試某個配置檔案是否書寫正確,我們可以使用以下命令
sbin/nginx – t – c conf/nginx2.conf

---------------------------------------------------------------------------------------------
當一臺伺服器中啟用多個例項的nginx時(即開啟不同埠的nginx),那麼啟動nginx的時候就要根據各自的nginx配置檔案進行啟動了,比如:
/data/nginx/sbin/nginx  -c /data/nginx/conf/nginx.conf
/data/nginx1.9/sbin/nginx -c /data/nginx1.9/conf/nginx.conf
/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf

通過訊號對 Nginx 進行控制
Nginx 支援下表中的訊號:

有兩種方式來通過這些訊號去控制Nginx:
第一是通過logs目錄下的nginx.pid檢視當前執行的Nginx的程式ID,通過 kill – XXX <pid> 來控制 Nginx,其中 XXX 就是上表中列出的訊號名。
如果系統中只有一個Nginx程式,那也可以通過 killall 命令來完成,例如執行 killall – s HUP nginx 來讓 Nginx 重新載入配置。

配置 Nginx
先來看一個實際的配置檔案:

user  nobody;# 工作程式的屬主
 worker_processes  4;# 工作程式數,一般與 CPU 核數等同

 #error_log  logs/error.log; 
 #error_log  logs/error.log  notice; 
 #error_log  logs/error.log  info; 

 #pid        logs/nginx.pid; 

 events { 
    use epoll;#Linux 下效能最好的 event 模式
    worker_connections  2048;# 每個工作程式允許最大的同時連線數
 } 

 http { 
    include       mime.types; 
    default_type  application/octet-stream; 

    #log_format  main  '$remote_addr - $remote_user [$time_local] $request ' 
    #                  '"$status" $body_bytes_sent "$http_referer" ' 
    #                  '"$http_user_agent" "$http_x_forwarded_for"'; 

    #access_log  off; 
    access_log  logs/access.log;# 日誌檔名

    sendfile        on; 
    #tcp_nopush     on; 
    tcp_nodelay     on; 

    keepalive_timeout  65; 

    include 	 gzip.conf; 
    
    # 叢集中的所有後臺伺服器的配置資訊
    upstream tomcats { 
	 server 192.168.0.11:8080 weight=10; 
	 server 192.168.0.11:8081 weight=10; 
	 server 192.168.0.12:8080 weight=10; 
	 server 192.168.0.12:8081 weight=10; 
	 server 192.168.0.13:8080 weight=10; 
	 server 192.168.0.13:8081 weight=10; 
    } 

    server { 
        listen       80;#HTTP 的埠
        server_name  localhost; 

        charset utf-8; 

        #access_log  logs/host.access.log  main; 

	 location ~ ^/NginxStatus/ { 
	    stub_status on; #Nginx 狀態監控配置
	    access_log off; 
	 } 

	 location ~ ^/(WEB-INF)/ { 
	    deny all; 
	 } 
	

	 location ~ \.(htm|html|asp|php|gif|jpg|jpeg|png|bmp|ico|rar|css|js|
	 zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma)$ { 
             root /opt/webapp; 
	    expires 24h; 
        } 

        location / { 
	    proxy_pass http://tomcats;# 反向代理
	    include proxy.conf; 
        } 

        error_page 404 /html/404.html; 

        # redirect server error pages to the static page /50x.html 
        # 
	 error_page 502 503 /html/502.html; 
        error_page 500 504 /50x.html; 
        location = /50x.html { 
            root   html; 
        } 
    } 
 }

Nginx 監控
上面是一個實際網站的配置例項,其中#號後面的文字為配置說明。
上述配置中,首先我們定義了一個 location ~ ^/NginxStatus/,這樣通過 http://localhost/NginxStatus/ 就可以監控到 Nginx 的執行資訊,顯示的內容如下:
Active connections: 70
server accepts handled requests
14553819 14553819 19239266
Reading: 0 Writing: 3 Waiting: 67

NginxStatus 顯示的內容意思如下:
active connections – 當前 Nginx 正處理的活動連線數。
server accepts handled requests -- 總共處理了 14553819 個連線 , 成功建立 14553819 次握手 ( 證明中間沒有失敗的 ), 總共處理了 19239266 個請求 ( 平均每次握手處理了 1.3 個資料請求 )。
reading -- nginx 讀取到客戶端的 Header 資訊數。
writing -- nginx 返回給客戶端的 Header 資訊數。
waiting -- 開啟 keep-alive 的情況下,這個值等於 active - (reading + writing),意思就是 Nginx 已經處理完正在等候下一次請求指令的駐留連線。

靜態檔案處理
通過正規表示式,我們可讓 Nginx 識別出各種靜態檔案,例如 images 路徑下的所有請求可以寫為:
location ~ ^/images/ {
       root /opt/webapp/images;
}
而下面的配置則定義了幾種檔案型別的請求處理方式。
location ~ \.(htm|html|gif|jpg|jpeg|png|bmp|ico|css|js|txt)$ {
      root /opt/webapp;
      expires 24h;
}
對於例如圖片、靜態 HTML 檔案、js 指令碼檔案和 css 樣式檔案等,我們希望 Nginx 直接處理並返回給瀏覽器,這樣可以大大的加快網頁瀏覽時的速度。因此對於這類檔案我們需要通過 root 指令來指定檔案的存放路徑,同時因為這類檔案並不常修改,通過 expires 指令來控制其在瀏覽器的快取,以減少不必要的請求。 expires 指令可以控制 HTTP 應答中的“ Expires ”和“ Cache-Control ”的頭標(起到控制頁面快取的作用)。您可以使用例如以下的格式來書寫 Expires:
expires 1 January, 1970, 00:00:01 GMT;
expires 60s;
expires 30m;
expires 24h;
expires 1d;
expires max;
expires off;

動態頁面請求處理
Nginx 本身並不支援現在流行的 JSP、ASP、PHP、PERL 等動態頁面,但是它可以通過反向代理將請求傳送到後端的伺服器,例如 Tomcat、Apache、IIS 等來完成動態頁面的請求處理。前面的配置示例中,我們首先定義了由 Nginx 直接處理的一些靜態檔案請求後,其他所有的請求通過 proxy_pass 指令傳送給後端的伺服器(在上述例子中是 Tomcat)。最簡單的 proxy_pass 用法如下:
location / {
      proxy_pass http://localhost:8080;
      proxy_set_header X-Real-IP $remote_addr;
}
這裡我們沒有使用到叢集,而是將請求直接送到執行在 8080 埠的 Tomcat 服務上來完成類似 JSP 和 Servlet 的請求處理。
當頁面的訪問量非常大的時候,往往需要多個應用伺服器來共同承擔動態頁面的執行操作,這時我們就需要使用叢集的架構。 Nginx 通過 upstream 指令來定義一個伺服器的叢集,最前面那個完整的例子中我們定義了一個名為 tomcats 的叢集,這個叢集中包括了三臺伺服器共 6 個 Tomcat 服務。而 proxy_pass 指令的寫法變成了:
location / {
     proxy_pass http://tomcats;
     proxy_set_header X-Real-IP $remote_addr;
}
在 Nginx 的叢集配置中,Nginx 使用最簡單的平均分配規則給叢集中的每個節點分配請求。一旦某個節點失效時,或者重新起效時,Nginx 都會非常及時的處理狀態的變化,以保證不會影響到使用者的訪問。

Nginx的location語法規則:location [=|~|~*|^~] /uri/ { … }
=  開頭表示精確匹配
^~  開頭表示uri以某個常規字串開頭,理解為匹配 url路徑即可。nginx不對url做編碼,因此請求為/static/20%/aa,可以被規則^~ /static/ /aa匹配到(注意是空格)。
~  開頭表示區分大小寫的正則匹配
~*  開頭表示不區分大小寫的正則匹配
!~和!~* 分別為區分大小寫不匹配及不區分大小寫不匹配 的正則
/  通用匹配,任何請求都會匹配到。

多個location配置的情況下匹配順序為(參考資料而來,還未實際驗證,試試就知道了,不必拘泥,僅供參考):
首先匹配 =,其次匹配^~, 其次是按檔案中順序的正則匹配,最後是交給 / 通用匹配。當有匹配成功時候,停止匹配,按當前匹配規則處理請求。

示例說明:
有如下匹配規則:
location = / {
#規則A
}
location = /login {
#規則B
}
location ^~ /static/ {
#規則C
}
location ~ \.(gif|jpg|png|js|css)$ {
#規則D
}
location ~* \.png$ {
#規則E
}
location !~ \.xhtml$ {
#規則F
}
location !~* \.xhtml$ {
#規則G
}
location / {
#規則H
}

產生的效果如下
訪問根目錄/, 比如http://localhost/ 將匹配規則A
訪問http://localhost/login 將匹配規則B,http://localhost/register 則匹配規則H
訪問http://localhost/static/a.html 將匹配規則C
訪問http://localhost/a.gif, http://localhost/b.jpg 將匹配規則D和規則E,但是規則D順序優先,規則E不起作用, 而 http://localhost/static/c.png 則優先匹配到 規則C
訪問http://localhost/a.PNG 則匹配規則E, 而不會匹配規則D,因為規則E不區分大小寫。
訪問http://localhost/a.xhtml 不會匹配規則F和規則G,http://localhost/a.XHTML不會匹配規則G,因為不區分大小寫。規則F,規則G屬於排除法,符合匹配規則但是不會匹配到,所以想想看實際應用中哪裡會用到。
訪問http://localhost/category/id/1111 則最終匹配到規則H,因為以上規則都不匹配,這個時候應該是nginx轉發請求給後端應用伺服器,比如FastCGI(php),tomcat(jsp),nginx作為方向代理伺服器存在。

所以實際使用中,至少有三個匹配規則定義,如下:
直接匹配網站根,通過域名訪問網站首頁比較頻繁,使用這個會加速處理,官網如是說。
這裡是直接轉發給後端應用伺服器了,也可以是一個靜態首頁
第一個必選規則
location = / {
proxy_pass http://tomcat:8080/index
}

第二個必選規則是處理靜態檔案請求,這是nginx作為http伺服器的強項
有兩種配置模式,目錄匹配或字尾匹配,任選其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}

第三個規則就是通用規則,用來轉發動態請求到後端應用伺服器
非靜態檔案請求就預設是動態請求,自己根據實際把握
畢竟目前的一些框架的流行,帶.php,.jsp字尾的情況很少了
location / {
proxy_pass http://tomcat:8080/
}

儘管Nginx整個程式包只有500多K,但麻雀雖小、五臟俱全。 Nginx官方提供的各種功能模組應有盡有,結合這些模組可以完整各種各樣的配置要求,例如:壓縮、防盜鏈、叢集、FastCGI、流媒體伺服器、Memcached 支援、URL 重寫等等,更關鍵的是Nginx擁有Apache和其他HTTP伺服器無法比擬的高效能。甚至可以在不改變原有網站的架構上,通過在前端引入Nginx做負載均衡來提升網站的訪問速度。

-------------------------------------------------------下面對Nginx的一些特殊設定做一說明-------------------------------------------------------

nginx的全域性變數
--------------------------------------------------------------------------------
remote_addr              客戶端ip,如:192.168.4.2
binary_remote_addr    客戶端ip(二進位制)
remote_port               客戶端port,如:50472
remote_user               已經經過Auth Basic Module驗證的使用者名稱
host                           請求主機頭欄位,否則為伺服器名稱,如:dwz.stamhe.com
request                      使用者請求資訊,如:GET /?_a=index&_m=show&count=10 HTTP/1.1
request_filename         當前請求的檔案的路徑名,由root或alias和URI request組合而成,如:/webserver/htdocs/dwz/index.php
status                        請求的響應狀態碼,如:200
body_bytes_sent         響應時送出的body位元組數數量。即使連線中斷,這個資料也是精確的,如:40
content_length            請求頭中的Content-length欄位
content_type               請求頭中的Content-Type欄位
http_referer                 引用地址
http_user_agent           客戶端agent資訊,如:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11
args                            如:_a=index&_m=show&count=10
document_uri               與$uri相同,如:/index.php
document_root             針對當前請求的根路徑設定值,如:/webserver/htdocs/dwz
hostname                     如:centos53.localdomain
http_cookie                  客戶端cookie資訊
cookie_COOKIE             cookie   COOKIE變數的值
is_args                         如果有$args引數,這個變數等於”?”,否則等於”",空值,如?
limit_rate                      這個變數可以限制連線速率,0表示不限速
query_string                 與$args相同,如:_a=index&_m=show&count=10
realpath_root                如:/webserver/htdocs/dwz
request_body                記錄POST過來的資料資訊
request_body_file          客戶端請求主體資訊的臨時檔名
request_method            客戶端請求的動作,通常為GET或POST,如:GET
request_uri                   包含請求引數的原始URI,不包含主機名,如:”/foo/bar.php?arg=baz”。不能修改。如:/index.php?_a=index&_m=show&count=10
scheme                         HTTP方法(如http,https),如:http
uri                                如:/index.php
request_completion        如果請求結束,設定為OK. 當請求未結束或如果該請求不是請求鏈串的最後一個時,為空(Empty),如:OK
server_protocol              請求使用的協議,通常是HTTP/1.0或HTTP/1.1,如:HTTP/1.1
server_addr                   伺服器地址,在完成一次系統呼叫後可以確定這個值,如:192.168.4.129
server_name                  伺服器名稱,如:dwz.stamhe.com
server_port                   請求到達伺服器的埠號,如:80

比如訪問https://www.wangshibo.com/HouseGroup/index.html,跳轉到https://www.wangshibo.com/index.php?r=houseGroup/index
rewrite ^/(.*)/index.html https://www.wangshibo.com/index.php?r=$1/index;

if ($request_uri  ~* "/(jkhwpc|jkhw|jkhwadmin).php") {
    rewrite ^/(.*)$ http://www.jikehaiwai.com/$1 last;
    }

if ($request_uri  ~* "/(qjspc|qjsmob|qjsadmin).php") {
    rewrite ^/(.*)$ http://www.qianjins.com/$1 last;
   }

-----------可以參考下面nginx的rewrite偽靜態設定---------
rewrite ^(.*)/equip(d+).html$ $1/index.php?m=content&c=index&a=lists&catid=$2 last; 

# nginx rewrite  rule 
rewrite ^(.*)/archiver/((fid|tid)-[w-]+.html)$ $1/archiver/index.php?$2 last; 
rewrite ^(.*)/forum-([0-9]+)-([0-9]+).html$ $1/forumdisplay.php?fid=$2&page=$3 last; 
rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+).html$ $1/viewthread.php?tid=$2&extra=page%3D$4&page=$3 last; 
rewrite ^(.*)/profile-(username|uid)-(.+).html$ $1/viewpro.php?$2=$3 last; 
rewrite ^(.*)/space-(username|uid)-(.+).html$ $1/space.php?$2=$3 last; 
rewrite ^(.*)/tag-(.+).html$ $1/tag.php?name=$2 last; 

rewrite ^/(.*)\.(asp|aspx|asa|asax|dll|jsp|cgi|fcgi|pl)(.*)$ /404.php last;
rewrite ^/(.*)/(admin|cache|editor|file|include|lang|module|skin|template)/(.*)\.php(.*)$ /404.php last;
rewrite ^/(.*)-htm-(.*)$ /$1.php?$2 last;
rewrite ^/(.*)/show-([0-9]+)([\-])?([0-9]+)?\.html$ /$1/show.php?itemid=$2&page=$4 last;
rewrite ^/(.*)/list-([0-9]+)([\-])?([0-9]+)?\.html$ /$1/list.php?catid=$2&page=$4 last;
rewrite ^/(.*)/show/([0-9]+)/([0-9]+)?([/])?$ /$1/show.php?itemid=$2&page=$3 last;
rewrite ^/(.*)/list/([0-9]+)/([0-9]+)?([/])?$ /$1/list.php?catid=$2&page=$3 last;
rewrite ^/(.*)/([A-za-z0-9_\-]+)-c([0-9]+)-([0-9]+)\.html$ /$1/list.php?catid=$3&page=$4 last;
rewrite ^/(.*)/([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /$1/index.php?moduleid=$2&catid=$3&itemid=$4&page=$5 last;
rewrite ^(.*)/([a-z]+)/(.*)\.shtml$ $1/$2/index.php?rewrite=$3 last;
rewrite ^/(com)/([a-z0-9_\-]+)/([a-z]+)/(.*)\.html$ /index.php?homepage=$2&file=$3&rewrite=$4 last;
rewrite ^/(com)/([a-z0-9_\-]+)/([a-z]+)([/])?$ /index.php?homepage=$2&file=$3 last;
rewrite ^/(com)/([a-z0-9_\-]+)([/])?$ /index.php?homepage=$2 last;

--------------------------------------------------------------------------------

1.rewrite跳轉規則,有以下四種flag標記:
last     基本上都用這個Flag,表示rewrite。
break     中止Rewirte,不在繼續匹配。就是說本條規則匹配完成後,終止匹配,不再匹配後面的規則。
redirect     返回臨時重定向的HTTP狀態302;瀏覽器地址會顯示跳轉後的URL地址。
permanent     返回永久重定向的HTTP狀態301;瀏覽器地址會顯示跳轉後的URL地址。
1)下面是可以用來判斷的表示式:
-f和!-f用來判斷是否存在檔案
-d和!-d用來判斷是否存在目錄
-e和!-e用來判斷是否存在檔案或目錄
-x和!-x用來判斷檔案是否可執行

先來看幾個小例子說明

例如下面這段設定nginx將某個目錄下面的檔案重定向到另一個目錄,$2對應第二個括號(.*)中對應的字串:
location /download/ {
        rewrite ^(/download/.*)/m/(.*)\..*$ $1/nginx-rewrite/$2.gz break;
}
-----------------------------------------------------------------------------------
例如當使用者輸入 www.a.com.cn 自動跳轉到www.a.com 這個域名:
rewrite ^/(.*)$ http://www.a.com/$1 permanent;
-----------------------------------------------------------------------------------
例如下面設定nginx在使用者使用ie的使用重定向到/nginx-ie目錄下:
if ($http_user_agent ~ MSIE) {
        rewrite ^(.*)$ /nginx-ie/$1 break;
}
-----------------------------------------------------------------------------------
例如當使用者訪問testxqsjapi.xqshijie.com域名時跳轉到本機的9501埠
upstream lb-9501 {
   server 127.0.0.1:9501;
}
server {
    listen  80;
    server_name testxqsjapi.xqshijie.com;
    root  /var/www/vhosts/testxqsjapi.xqshijie.com/;
 
    location / {
            proxy_pass http://lb-9501;
        }
}
----------------------------------------------------------------------------------
例如下面一例:nginx rewrite 實現二級域名跳轉
當訪問http://abc.wangshibo.com跳轉到http://www.wangshibo.com/wangshibo/abc/
方法一:這種方法瀏覽器地址會變www.wangshibo.com/wangshibo/abc
server {
        listen 80;
        server_name www.wangshibo.com;
        location / {
                root /data/wangshibo;
                index index.html;
        }
}
 
server {
        listen 80;
        server_name *.wangshibo.com;
        if ( $http_host ~* "^(.*)\.wangshibo\.com$") {
                set $domain $1;
                rewrite ^(.*) http://www.wangshibo.com/wangshibo/$domain/ break;
        }
}

方法二:當訪問http://abc.wangshibo.com/*跳轉到http://www.wangshibo.com/wangshibo/abc/*
server {
        listen 80;
        server_name *.wangshibo.com;
        root /usr/local/www;
        #這是裡可以加多個目錄,如果不加目錄,會無法訪問到abc.wangshibo.com/目錄下的檔案,如圖片目錄/images
        location ~ ^/(wangshibo|images|styles)/
        {
                proxy_redirect        off;
                proxy_set_header    Host   www.wangshibo.com;
                proxy_pass      http://192.168.1.2:8080;
        }
        location / {
                set $domain default;
                if ( $http_host ~* "^(.*)\.wangshibo\.com$") {
                        set $domain $1;
                }
                rewrite ^/(.*)    /wangshibo/$domain/$1 last;
        }
        access_log off;
}

再接著看下面的例項說明

#直接匹配網站根,通過域名訪問網站首頁比較頻繁,使用這個會加速處理,官網如是說。  
#這裡是直接轉發給後端應用伺服器了,也可以是一個靜態首頁  
# 第一個必選規則  
location = / {  
    proxy_pass http://tomcat:8080/index  
}  
   
# 第二個必選規則是處理靜態檔案請求,這是nginx作為http伺服器的強項  
# 有兩種配置模式,目錄匹配或字尾匹配,任選其一或搭配使用  
location ^~ /static/ {  
    root /webroot/static/;  
}  
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {  
    root /webroot/res/;  
}  
   
#第三個規則就是通用規則,用來轉發動態請求到後端應用伺服器  
#非靜態檔案請求就預設是動態請求,自己根據實際把握  
#畢竟目前的一些框架的流行,帶.php,.jsp字尾的情況很少了  
location / {  
    proxy_pass http://tomcat:8080/  
}  

2)例項說明
1)訪問A站跳轉(重定向)到B站
server {
    listen 80;
    server_name www.wangshibo.com ;
    rewrite ^(.*) http://www.huanqiu.com$1 permanent;

    root /var/www/html;
    index index.html index.php index.htm;
    access_log /usr/local/nginx/logs/image.log;
}

================================================================================
訪問一個主域名,自動新增www字首。比如訪問http://kevin.com自動跳轉http://www.kevin.com

1) 首先要保證不加www和加www的域名都要解析出來。
在DNS裡新增kevin.com和www.kevin.com的解析,比如解析到111.110.11.18
@                             IN      A       111.110.11.18
www                         IN      A       111.110.11.18

解釋:
A記錄解析kevin.com到111.110.11.18地址上,前面加@或者留空(留空預設就是@)
A記錄解析www.kevin.com到111.110.11.18地址上,前面加www

2)nginx配置不加www自動跳轉到www的域名訪問(80或443都一樣),有下面兩種方法實現:

方法一:
在conf/vhost/kevin.conf檔案中配置:

server {
        listen       80;
        server_name  www.kevin.com kevin.com;

        index index.jsp index.html index.php index.htm;
        root   /var/www/html;
 
       access_log  /data/nginx/logs/www.kevin.com-access.log main;
       error_log  /data/nginx/logs/www.kevin.com-error.log;
 

        if ($host = "kevin.com") {
             rewrite ^/(.*)$ http://www.kevin.com permanent;
        }

}


方法二(官方推薦這一種nginx的301跳轉方法)
在conf/vhost/kevin.conf檔案中配置:

server {
          listen       80;
          server_name  kevin.com;
          return       301 http://www.kevin.com$request_uri;
}
          
server {
         listen      80;
         server_name www.kevin.com;

        index index.jsp index.html index.php index.htm;
        root   /var/www/html;
 
       access_log  /data/nginx/logs/www.kevin.com-access.log main;
       error_log  /data/nginx/logs/www.kevin.com-error.log;
}

2)多域名繫結一個目錄,並且全部301跳轉到其中一個域名(注意:多域名都要解析到本機ip上)
server {
     listen 80;
     server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com;
     if ($host != 'www.wangshibo.com') {
     rewrite ^/(.*)$ http://www.wangshibo.com/$1 permanent;
     }
     root /var/www/html;
     index index.html index.php index.htm;
     access_log /usr/local/nginx/logs/image.log;
}

上面說明訪問http://web01.wangshibo.com、http://hehe.wangshibo.com、http://wangshibo.com的時候都會自動跳轉到
http://www.wangshibo.com,並且瀏覽器地址會顯示跳轉後的URL地址。

如果是上面多域名訪問後都重定向跳轉到http://hehe.wangshibo.com,則配置修改如下:
server {
    listen 80;
    server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com;
    if ($host != 'hehe.wangshibo.com') {
    rewrite ^/(.*)$ http://hehe.wangshibo.com/$1 permanent;
    }
    root /var/www/html;
    index index.html index.php index.htm;
    access_log /usr/local/nginx/logs/image.log;
}

如下配置:多域名中的某個域名訪問時發生跳轉,其他域名訪問時不跳轉
server {
   listen 80;
   server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com;
   if ($host = 'hehe.wangshibo.com') {
       rewrite ^/(.*)$ http://www.huanqiu.com/$1 permanent;
   }
   root /var/www/html;
   index index.html index.php index.htm;
   access_log /usr/local/nginx/logs/image.log;
}

3)將多級目錄下的檔案轉成一個檔案,增強seo效果
比如將/wang-123-456-789.html指向wang/123/456/wangshow_789.html
[root@test-huanqiu ~]# cat /usr/local/nginx/conf/vhosts/test.conf
server {
     listen 80;
     server_name www.wangshibo.com;
     rewrite ^/wang-([0-9]+)-([0-9]+)-([0-9]+)\.html$ http://www.wangshibo.com/wang/$1/$2/wangshow_$3.html last;
     root /var/www/html;
     index index.html index.php index.htm;
     access_log /usr/local/nginx/logs/image.log;

}

這樣訪問http://www.wangshibo.com/wang-123-456-789.html就會跳轉到http://www.wangshibo.com/wang/123/456/wangshow_789.html

4)訪問的目標檔案和目錄資源不存在的時候重定向跳轉
如下配置,當訪問http://www.wangshibo.com/後面的訪問資源(檔案或目錄)不存在時,統統跳轉到http://www.wangshibo.com/sorry.html頁面
server {
    listen 80;
    server_name www.wangshibo.com;
    if (!-e $request_filename) {
        rewrite ^/ http://www.wangshibo.com/sorry.html ;
    }
    root /var/www/html;
    index index.html index.php index.htm;
    access_log /usr/local/nginx/logs/image.log;
}

5)將站點根目錄下某個目錄指向二級目錄
例如將/huanqiupc/指向/ops/huanqiu/,配置如下:
server {
    listen 80;
    server_name www.wangshibo.com;
    rewrite ^/([0-9a-z]+)pc/(.*)$ http://www.wangshibo.com/ops/$1/$2 last;
    root /var/www/html;
    index index.html index.php index.htm;
    access_log /usr/local/nginx/logs/image.log;
}

這樣,訪問http://www.wangshibo.com/huanqiupc的時候就會跳轉到http://www.wangshibo.com/ops/huanqiu/
注意:上面的配置中的last修改為permanent或redirect都可以

以上的配置也適用於:(前提是這些目錄要真是存在於站點目錄/var/www/html/中,並且許可權要正確)
將/wangshibopc/指向/ops/wangshibo/
將/guohuihuipc/指向/ops/guohuihui/
將/hahapc/指向/ops/haha/
......

6)其他的rewrite跳轉規則的例子:

server {
    listen 80;
    server_name www.wangshibo.com;
    root /var/www/html; 
    index index.html index.htm;

    rewrite ^/site/resource/(.*)$ https://www.wangshibo.com/resource/$1 last;
    rewrite ^/active/Ymf.html$ https://www.wangshibo.com/project/detail.html?project_id=1 last;
    rewrite ^/active/Ysyg.html$ https://www.wangshibo.com/project/detail.html?project_id=7 last;

    if ($host ~* "^wangshibo.com$") {
       rewrite ^/(.*)$ https://www.wangshibo.com/ permanent;
    }

    location / { 
      rewrite /abc http://www.huanqiu.com break;    #本機站點目錄下並不需要真實存在abc這個目錄,對虛擬目錄的訪問都重寫到http://www.huanqiu.com
    }                                               #即訪問http://www.wangshibo.com/abc,跳轉到http://www.huanqiu.com

    location /text { 
      rewrite / http://china.huanqiu.com break;     #本機站點目錄下需要真實存在text目錄,對其的訪問都重寫到http://china.huanqiu.com
    }                                               #即訪問http://www.wangshibo.com/text,跳轉到http://china.huanqiu.com

    }

下面一例:訪問http://www.wangshibo.com/g/4HG45SkZ 實際訪問地址跳轉為 http://110.10.88.99:8081/qun/share/view?code=4HG45SkZ

upstream  g_server {
        keepalive 64;
        server 110.10.88.99:8081 max_fails=2 fail_timeout=5 weight=100;
        }

    server {
        listen       80;
        server_name  www.wangshibo.com;

        rewrite ^/bcloud.(swf|html|js)(.*)$ http://hehe.wangshibo.com/bcloud.$1$2 last;

        root  /home/web/www;
        location ~ \.apk$ {
        max_ranges 0;
          }

        location ^~ /g {
            proxy_redirect off;
            proxy_set_header Host $host;
#           proxy_set_header Host $host:$remote_port;
#           proxy_set_header REMOTE_PORT $remote_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            client_max_body_size 1G;
            client_body_buffer_size 256k;
            proxy_connect_timeout 30;
            proxy_send_timeout 30;
            proxy_read_timeout 600;
            proxy_buffer_size 16k;
            proxy_buffers 4 32k;
            proxy_temp_file_write_size 64k;
            proxy_pass  http://g_server;
            #rewrite "/g/(.*$)"   www.wangshibo.com/qun/share/view?code=$1  break;
            rewrite "/g/(.*$)"   /qun/share/view?code=$1  break;
        }
    }

另外注意:
$1表示第一個變數,即前面rewrite後第一個()內設定的變數
$2表示第二個變數,即前面rewrite後第二個()內設定的變數

再看一例:
訪問http://www.wangshibo.com/thumb/transcode 實際訪問地址為 http://120.170.190.99:28080/transcode/thumb/transcode

upstream  thumb {
        keepalive 64;
        server 120.170.190.99:28080 max_fails=2 fail_timeout=5 weight=100;
    }

server {
        listen       80;
        server_name  www.wangshibo.com ;

        root   /home/web/www;

  location ^~ /thumb {
            proxy_pass  http://thumb;
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
            client_max_body_size 1G;
            client_body_buffer_size 256k;
            proxy_connect_timeout 30;
            proxy_send_timeout 30;
            proxy_read_timeout 60;
            proxy_buffer_size 16k;
            proxy_buffers 4 32k;
            proxy_temp_file_write_size 64k;
            rewrite  "^/(.*)$"  /transcode/$1 break;
        }
}

----------------------------再看一個訪問nginx跳轉後的url不變的例子--------------------------------------

需要特別注意的是:
proxy_pass 反向代理,可以實現只改變跳轉後的內容,而跳轉後的原url保持不變!
rewrite 重寫跳轉後會進行重定向,很難實現跳轉後的原url不變的需求。

看看之前踩過的坑;
要求訪問http://wx2.xqshijie.com/apiwx2/xqsj.php?r=houseGroup%2FgetToken,內容跳轉到http://m.xqshijie.com/xqsj.php?r=houseGroup%2FgetToken,但是跳轉後的url保持不變!
這是根據path路徑進行反向代理的配置,即要求訪問http://wx2.xqshijie.com/apiwx2/$1 跳轉到http://m.xqshijie.com/$1,跳轉後的url不變!

配置如下:
[root@fangfull_web1 vhosts]# cat wx2.xqshijie.com.conf
server {
        listen       80;

        server_name  wx2.xqshijie.com;
        root  /Data/app/xqsj_wx2/dist;
        index index.html;
  
        #if ($http_x_forwarded_for !~ ^(124.65.197.154|103.10.86.28|103.10.86.8)) {
        #   rewrite ^.*$  /maintence.php last;
        #}

        location /apiwx2/ {
        proxy_pass https://m.xqshijie.com/;
        }

        access_log  /var/log/betawx2.log  main;

        location / {
            try_files $uri $uri/ @router;
            index  index.html;
        }
        #rewrite ^(.+)$ /index.html last;
        location @router {
            rewrite ^.*$ /index.html last;
        }
    } 

根據上面配置後,就可以實現訪問http://wx2.xqshijie.com/apiwx2/xqsj.php?r=houseGroup%2FgetToken,實際顯示的是https://m.xqshijie.com/xqsj.php?r=houseGroup%2FgetToken的內容,但是跳轉後的原來的url不變!


如果採用rewrite重寫規則,即將:
        location /apiwx2/ {
        proxy_pass https://m.xqshijie.com/;
        }
改為
        location /apiwx2/ {
        rewrite ^/apiwx2(.*)$ https://m.xqshijie.com.$1 last;
        }
那麼,訪問http://wx2.xqshijie.com/apiwx2/xqsj.php?r=houseGroup%2FgetToken,實際顯示的是https://m.xqshijie.com/xqsj.php?r=houseGroup%2FgetToken的內容,但是跳轉後的url已經變了!


上面碰到過的坑:
由於訪問http://m.xqshijie.com就會自動跳轉到https://m.xqshijie.com,所以如果將上面的配置改為(即將https://m.xqshijie.com改為http://m.xqshijie.com):
        location /apiwx2/ {
        proxy_pass http://m.xqshijie.com/;
        }
這樣,訪問http://wx2.xqshijie.com/apiwx2/xqsj.php?r=houseGroup%2FgetToken,實際顯示的是https://m.xqshijie.com/xqsj.php?r=houseGroup%2FgetToken的內容,但是跳轉後的原來的url已經變了!
原因是因為這裡經過了兩次跳轉,即rewrite->http->https,所以跳轉後的url變了。
解決辦法:就是直接rewrite跳轉到https,即proxy_pass https://m.xqshijie.com/;

----------------------------下面的跳轉規則表示---------------------------------------
訪問http://www.wangshibo.com/wangshibo/ops就會跳轉到http://www.wangshibo.com/ops/wangshibo
訪問http://www.wangshibo.com/wangshibo/beijing就會跳轉到http://www.wangshibo.com/beijing/wangshibo
......
即由"wangshibo/變數"-->"變數/wangshibo"

server {
   listen 80;
   server_name www.wangshibo.com;
   rewrite ^/wangshibo/(.*)$  http://www.wangshibo.com/$1/wangshibo last;
   root /var/www/html;
   index index.html index.php index.htm;
   access_log /usr/local/nginx/logs/image.log;
}

訪問http://www.wangshibo.com/ops/web 跳轉到 http://www.wangshibo.com/web/ops/web/

server {
   listen 80;
   server_name www.wangshibo.com;
   rewrite ^/ops/(.*)$  http://www.wangshibo.com/$1/ops/$1 break;
   root /var/www/html;
   index index.html index.php index.htm;
   access_log /usr/local/nginx/logs/image.log;
}

訪問http://www.wangshibo.com/wang/123 實際訪問地址跳轉為 http://www.hehe.com/qun/share/view?code=123

server {
   listen 80;
   server_name www.wangshibo.com;
   rewrite ^/wang/(.*)$  http://www.hehe.com/qun/share/view?code=$1 last;
   root /var/www/html;
   index index.html index.php index.htm;
   access_log /usr/local/nginx/logs/image.log;
}

其他配置例項

如果nginx在使用者使用IE瀏覽器訪問情況下,則重定向到/nginx-ie目錄下
配置如下:
if ($http_user_agent ~ MSIE) {
   rewrite ^(.*)$ /nginx-ie/$1 break;
}

多目錄轉成引數
abc.domian.com/sort/2 => abc.domian.com/index.php?act=sort&name=abc&id=2
配置如下:
if ($host ~* (.*)\.domain\.com) {
   set $sub_name $1;
   rewrite ^/sort\/(\d+)\/?$ /index.php?act=sort&cid=$sub_name&id=$1 last;
}


目錄自動加"/",前提是訪問目錄存在
配置如下:
if (-d $request_filename){
   rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
}


三級域名跳轉
配置如下:
if ($http_host ~* “^(.*)\.i\.beijing\.com$”) {
rewrite ^(.*) http://www.wangshibo.com$1/;
break;
}


針對站點根目錄下的某個子目錄作鏡向
配置如下:就會把http://www.huanqiu.com的內容(即首頁)映象到/var/www/html下的ops目錄下了
server {
   listen 80;
   server_name www.wangshibo.com;
   root /var/www/html;
   location ^~ /ops {
   rewrite ^.+ http://www.huanqiu.com/ last;
   break;
   }
   index index.html index.php index.htm;
   access_log /usr/local/nginx/logs/image.log;
}


域名映象(其實就是域名跳轉)
server {
   listen 80;
   server_name www.wangshibo.com;
   root /var/www/html;
   rewrite ^/(.*) http://www.huanqiu.com/$1 last;
   index index.html index.php index.htm;
   access_log /usr/local/nginx/logs/image.log;
}

其他:
rewrite ^/(space|network)-(.+)\.html$ /$1.php?rewrite=$2 last;
rewrite ^/(space|network)\.html$ /$1.php last;
rewrite ^/([0-9]+)$ /space.php?uid=$1 last;

rewrite ^(.*)/archiver/((fid|tid)-[\w\-]+\.html)$ $1/archiver/index.php?$2 last;
rewrite ^(.*)/forum-([0-9]+)-([0-9]+)\.html$ $1/forumdisplay.php?fid=$2&page=$3 last;
rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/viewthread.php?tid=$2&extra=page\%3D$4&page=$3 last;
rewrite ^(.*)/profile-(username|uid)-(.+)\.html$ $1/viewpro.php?$2=$3 last;
rewrite ^(.*)/space-(username|uid)-(.+)\.html$ $1/space.php?$2=$3 last;
rewrite ^(.*)/tag-(.+)\.html$ $1/tag.php?name=$2 last;

目錄對換:/1234/xxx ----->xxx?id=1234
配置如下:
[root@test-huanqiu ~]# vim /usr/local/nginx/conf/vhosts/test.conf
server {
    listen 80;
    server_name www.wangshibo.com;
    root /var/www/html;
    rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;
    index index.html index.php index.htm;
    access_log /usr/local/nginx/logs/image.log;
}

[root@test-huanqiu ~]# cat /var/www/html/ops/index.html
nginx的目錄對換的跳轉測試

如上配置後,那麼:
訪問http://www.wangshibo.com/?id=567567567567567 的結果就是http://www.wangshibo.com/的結果
訪問http://www.wangshibo.com/ops/?id=wangshibo 的結果就是http://www.wangshibo.com/ops的結果
訪問http://www.wangshibo.com/wang/?id=123111 的結果就是http://www.wangshibo.com/wang的結果
.......

2.反向代理(proxy_pass)
簡單測試nginx反向代理和負載均衡功能的操作記錄(1)-----http代理
簡單測試nginx反向代理和負載均衡功能的操作記錄(2)-----https代理

3.快取設定
nginx反向代理+快取開啟+url重寫+負載均衡(帶健康探測)的部署記錄
nginx快取配置的操作記錄梳理

4.防盜鏈。關於Nginx防盜鏈具體設定,可參考:Nginx中防盜鏈(下載防盜鏈和圖片防盜鏈)的操作記錄
location ~* \.(gif|jpg|swf)$ {
valid_referers none blocked start.igrow.cn sta.igrow.cn;
if ($invalid_referer) {
rewrite ^/ http://$host/logo.png;
}
}

下面設定檔案反盜鏈並設定過期時間:
location ~*^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
    valid_referers none blocked *.wangshibo.com*.wangshibo.net localhost 218.197.67.14;
    if ($invalid_referer) {
       rewrite ^/ http://img.wangshibo.net/leech.gif;
       return 412;
       break;
      }
   access_log off;
   root /opt/lampp/htdocs/web;
   expires 3d;
   break;
}

這裡的return 412 是自定義的http狀態碼,預設為403,方便找出正確的盜鏈的請求
“rewrite ^/ http://img.wangshibo.net/leech.gif;”顯示一張防盜鏈圖片
“access_log off;”不記錄訪問日誌,減輕壓力
“expires 3d”所有檔案3天的瀏覽器快取

5.根據檔案型別設定過期時間
1)expires起到控制頁面快取的作用,合理的配置expires可以減少很多伺服器的請求;
2)對於站點中不經常修改的靜態內容(如圖片,JS,CSS),可以在伺服器中設定expires過期時間,控制瀏覽器快取,達到有效減小頻寬流量,降低伺服器壓力的目的。
3)Expires是Web伺服器響應訊息頭欄位,在響應http請求時告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器快取取資料,而無需再次請求。
要配置expires,可以在http段中或者server段中或者location段中加入;
如下:控制圖片等過期時間為30天,如果圖片檔案不怎麼更新,過期可以設大一點;如果頻繁更新,則可以設定得小一點,具體視情況而定
location ~ \.(gif|jpg|jpeg|png|bmp|swf|ico)$ {
    root /var/www/img/;
    expires 30d;
}

location ~ .*\.(js|css)$ {
   expires 10d;
}

location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ {
   if (-f $request_filename) {
   expires 1h;
   break;
   }
}

location ~ \.(wma|wmv|asf|mp3|mmf|zip|rar|swf|flv)$ {
   root /var/www/upload/;
   expires max;
}

expires 指令可以控制 HTTP 應答中的“ Expires ”和“ Cache-Control ”的頭標(起到控制頁面快取的作用)
語法:expires [time|epoch|max|off]
預設值:off
expires指令控制HTTP應答中的“Expires”和“Cache-Control”Header頭部資訊,啟動控制頁面快取的作用
time:可以使用正數或負數。“Expires”頭標的值將通過當前系統時間加上設定time值來設定。
time值還控制"Cache-Control"的值:
負數表示no-cache
正數或零表示max-age=time
epoch:指定“Expires”的值為 1 January,1970,00:00:01 GMT
max:指定“Expires”的值為31 December2037 23:59:59GMT,"Cache-Control"的值為10年。(即設定過期時間最最長)
-1:指定“Expires”的值為當前伺服器時間-1s,即永遠過期。
off:不修改“Expires”和"Cache-Control"的值

expires使用了特定的時間,並且要求伺服器和客戶端的是中嚴格同步。
而Cache-Control是用max-age指令指定元件被快取多久。
對於不支援http1.1的瀏覽器,還是需要expires來控制。所以最好能指定兩個響應頭。但HTTP規範規定max-age指令將重寫expires頭。

如何檢測nginx中設定的expires網頁過期時間是否生效?
方法:
開啟webkaka的網站速度診斷工具(http://pagespeed.webkaka.com/),輸入你的網頁地址,檢測後,立即可以看到設定是否生效了。如下圖所示:

上圖可以看到,被檢測網頁的js檔案過期時間為1天(12h)。

6.禁止訪問某個檔案或目錄
1)禁止訪問以txt或doc結尾的檔案
location ~* \.(txt|doc)${
root /data/www/wwwroot/linuxtone/test;
deny all;
}

2)nginx禁止訪問所有.開頭的隱藏檔案設定
location ~* /.* {
deny all;
}

3)nginx禁止訪問目錄
location ^~ /path {
deny all;
}

4)禁止訪問副檔名為bat的檔案
location ~* /.bat {
deny all;
}

5)禁止訪問configs目錄,以及其下所有子目錄或檔案
location ^~ /configs/ {
deny all;
}
注意上述configs後面的斜槓不能少,否則所有以configs開頭的目錄或檔案都將禁止訪問。

6)禁止訪問多個目錄
location ~ ^/(cron|templates)/ {
deny all;
break;
}

7)禁止訪問以/data開頭的檔案
location ~ ^/data {
deny all;
}

8)禁止訪問以.sh,.flv,.mp3為檔案字尾名的檔案
location ~ .*\.(sh|flv|mp3)$ {
return 403;
}

9)或者以=符號形式
location = /config/ {
return 404;
}
location =/config.ini{
return 404;
}

10)禁止htaccess
location ~/\.ht {
deny all;
}

return指令
語法:returncode ;
使用環境:server,location,if;
該指令用於結束規則的執行並返回狀態碼給客戶端。

例如:訪問的URL以".sh"或".bash"結尾,則返回403狀態碼
location ~ .*\.(sh|bash)?$ {
return 403;
}

7.禁止IP訪問 只允許域名訪問
當別人通過ip或者未知域名訪問你的網站的時候,你希望禁止顯示任何有效內容,可以給他返回500.
目前國內很多機房都要求網站主關閉空主機頭,防止未備案的域名指向過來造成麻煩。
為了避免網站遭受惡意IP攻擊,需要禁止IP訪問,只能使用域名訪問站點!

listen行加上default(或default_server)引數,表示這個是預設虛擬主機。
所以,禁止ip訪問,只能使用域名訪問的正確配置是:
server {
     listen 80 default;
     server_name _;
     return 500;
}

server {
    listen 80;
    server_name web01.wangshibo.cn;
    root /var/www/html;
    index index.html index.php index.htm;
    access_log /usr/local/nginx/logs/image.log;
}

注意:
如果在上面的server_name配置中指定域名的同時,也指明瞭ip訪問,比如server_name 103.110.186.17 web01.wangshibo.cn
那麼儘管上面已經做了返回500設定,也禁止不了ip訪問!也就是說,只要server_name一行指明瞭ip訪問,那麼就禁止不了了

以上設定,可以將ip訪問禁用,這樣的話,使用ip訪問的流量就會丟失。
如果想把這部分流量收集起來,匯入到自己的網站,只要做以下跳轉設定就可以:
server {
    listen 80 default;
    rewrite ^(.*) http://www.wangshibo.com permanent;
}

server {
    listen 80;
    server_name web01.wangshibo.cn;
    root /var/www/html;
    index index.html index.php index.htm;
    access_log /usr/local/nginx/logs/image.log;
}

下面列出其他的一些細節導致的不同效果:
1)將ip和域名訪問統統禁止,返回403(或者配置return 500)錯誤頁
server {
listen 80 default;
server_name _;
return 403;

root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}

2)下面的配置:
指明瞭只能使用域名,即http://web01.wangshibo.cn訪問配置中的站點(/var/www/html)
不能使用ip,即http://103.110.186.17訪問配置中的站點。但是可以使用ip方式訪問nginx預設的根目錄下的內容(比如/usr/local/nginx/html)
server {
listen 80 ;
server_name web01.wangshibo.cn;

root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}

下面的配置,指明瞭使用域名或ip都可以訪問配置中的站點。(使用ip訪問只限於只有一個vhost虛擬主機配置的情況,如果是多個,那麼指明ip訪問就會混淆)
server {
listen 80 ;
server_name 103.110.186.17 web01.wangshibo.cn;

root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}

3)下面兩個的配置後,都能使用域名或ip訪問配置中的站點。
server {
listen 80 default;
server_name web01.wangshibo.cn;

root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}

server {
listen 80 default;
server_name 103.110.186.17 web01.wangshibo.cn;                        

root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}

======================================================================
nginx配置只能通過域名禁止ip訪問

為什麼要禁止ip訪問頁面呢,這樣做是為了避免其他人把未備案的域名解析到自己的伺服器IP,而導致伺服器被斷網,
可以通過禁止使用ip訪問的方法,防止此類事情的發生。

Nginx的預設虛擬主機在使用者通過IP訪問,或者通過未設定的域名訪問(比如有人把他自己的域名指向了你的ip)的時候
生效最關鍵的一點是,在server的設定裡面新增這一行:
listen 80 default;

後面的default參數列示這個是預設虛擬主機。這個設定非常有用。

比如別人通過ip或者未知域名訪問你的網站的時候,你希望禁止顯示任何有效內容,可以給他返回500。
網站主關閉空主機頭,防止未備案的域名指向過來造成麻煩。就可以這樣設定:
server { 
listen 80 default; 
return 500; 
}

也可以把這些流量收集起來,匯入到自己的網站,只要做以下跳轉設定就可以:
server { 
listen 80 default; 
rewrite ^(.*) http://www.xxx.com permanent; 
}

-----------------特別注意-------------------
按照如上設定後,確實不能通過IP訪問伺服器了,但是在應該用中出現當server_name後跟多個域名時,
其中一個域名怎麼都無法訪問:

設定如下:
沒更改之前,通過server_name 中的www.xxx.com kevin.com均可訪問伺服器,加入禁止IP訪問的設定後,通過kevin.com無法訪問伺服器了,www.xxx.com可以訪問
用 nginx -t 檢測配置檔案會提示warning:

最後通過在listen 80 default;後再加server_name _;解決,形式如下:
#禁止IP訪問(如果vhosts下面有很多域名的conf配置,那麼只需要建立建立一個檔案,比如deny.ip.conf,輸入下面五行內容,這樣就全域性禁止了ip訪問,只能使用域名訪問了!)
server{ 
listen 80 default;            //如果是禁止ip的8080埠訪問,則將此處的80修改為8080
server_name _; 
return 500; 
}

或者
server { 
listen 80 dufault; 
server_name _; 
rewrite ^(.*) http://www.xxx.com permanent; 
}

這樣,通過xxx.com就能訪問伺服器了,問題解決了。
=====================================================================
也可以使用如下設定:即在server段裡插入如下內容即可

if ($host != 'www.kevin.com' ) {
return 403;
}
=====================================================================

8.流量限制
對於提供下載的網站,肯定是要進行流量控制的,例如BBS、視訊服務,還是其它專門提供下載的網站。在nginx中我們完全可以做到限流,由Nginx模組中的Core模組提供了limit_rate、limit_rate_after命令,我們只需要呼叫命令實現流量限制就行。
實現流量限制由兩個指令limit_rate和limit_rate_after共同完成
limit_rate
語法: limit_rate rate;
預設值: limit_rate 0;
作用域: http, server, location, location中的if欄位
命令概述:限制向客戶端傳送響應的速率限制。引數 rate 的單位是位元組/秒,設定為 0 將關閉限速。 nginx 按連線限速,需要明白的一點是該限制只是針對一個連線的設定,所以如果某個客戶端同時開啟了兩個連線,那麼客戶端的整體速率是這條指令設定值的2倍。

limit_rate_after
語法: limit_rate_after size;
預設值: limit_rate_after 0;
作用域:http, server, location,location中的if欄位
設定不限速傳輸的響應大小。當傳輸量大於此值時,超出部分將限速傳送。

示例說明:
server {
       listen 80;
       server_name ops.wangshibo.com;
       location /ops/{
            root /home/www/html;
            limit_rate_after 5m;
            limit_rate 20k;
      }
}

測試:
[root@test-huanqiu ~]# wget http://ops.wangshibo.com/ops/seven.mp4

修改配置之前,速率沒有限制:

修改配置之後,可見由於傳輸量大於5m,超出部分的傳輸速率已經被限制在20k/s:

可以發現配置之後,剛開始的時候傳輸速度很高,因為,傳輸量大於設定值的部分才會受到限制。這就說明,我們兩個命令都發揮了作用!

9.併發連線數限制
這個配置是基於ngx_http_limit_zone_module模組的,要簡單完成併發限制,我們要涉及到limit_conn_zone和limit_conn 這兩個指令:
limit_conn_zone
語法:limit_conn_zone zone_name $variable the_size
預設值:no
作用域:http
本指令定義了一個資料區,裡面記錄會話狀態資訊。 variable 定義判斷會話的變數;the_size 定義記錄區的總容量。

limit_conn
語法:limit_conn zone_name the_size
預設值:no
作用域:http, server, location
指定一個會話最大的併發連線數。 當超過指定的最發併發連線數時,伺服器將返回 "Service unavailable" (503)。

示例說明:
http {
       limit_conn_zone $binary_remote_addr zone=one:10m;
       .......
       .......
       server {
             listen 80;
             server_name ops.wangshibo.com;
             location /ops/ {
             limit_conn one 1;
             }
示例解釋:
1)定義一個叫“one”的記錄區,總容量為 10M,以變數$binary_remote_addr作為會話的判斷基準(即一個地址一個會話)。
限制/ops/目錄下,一個會話只能進行一個連線;簡單來說,就是限制/ops/目錄下,一個IP只能發起一個連線,多過一個,一律報錯503。
2)這裡使用的是$binary_remote_addr而不是 $remote_addr。$remote_addr的長度為7至15 bytes,會話資訊的長度為32或64bytes;而 $binary_remote_addr的長度為4bytes,會話資訊的長度為32bytes;$binary_remote_addr是限制同一客戶端ip地址;當 zone 的大小為 1M 的時候,大約可以記錄 32000 個會話資訊(一個會話佔用 32 bytes)。

下面分享一個限制流量和併傳送的配置:
現象描述:
中間一段時間,網站訪問有點慢,初步懷疑是機房交換機問題(之前出現過網站訪問很慢,熱插拔網路卡/重啟網路卡就好了)
最後檢視,發現機房流量很大!主要是論壇流量大,主站流量很小,應該是論壇人數訪問一多,就把頻寬佔滿了。

解決辦法:
在論壇伺服器上修改:
1)首先限制併發數
[root@server_web ~]# vim /etc/sysconfig/iptables
.....
-A INPUT -p tcp --dport 80 -m limit --limit 6/s -j ACCEPT
[root@server_web ~]# /etc/init.d/iptables restart

上面將每個使用者限制在每秒6個請求,但效果不明顯。

2)設定nginx的流量請求
[root@server_web ~]# vim /usr/local/nginx/conf/nginx.conf
http{
     limit_conn_zone $binary_remote_addr zone=perip:10m;
    # limit_req_zone $binary_remote_addr zone=one2:10m rate=5r/s;
    # limit_req zone=one2 burst=5;
    ..........
    ..........
}

[root@server_web ~]# vim /usr/local/nginx/conf/vhost/forum.conf
      server {
            listen 80;
            server_name forum.wangshibo.com;
            root /var/www/html;
                limit_conn perip 10;                           //這裡呼叫上面的perip,需要寫在server裡面;即每個ip最多有10個併發連線
                limit_rate 10k;                                  //限制每個連線的頻寬,可以單獨寫這條,與連線數無關;
           }
}

[root@server_web ~]# /usr/local/nginx/sbin/nginx -s reload

======================Nginx下的限流配置=====================
limit_req_zone      用來限制單位時間內的請求數,即速率限制,採用的漏桶演算法 "leaky bucket"     #點選前面超連結可檢視對應模組官方介紹
limit_req_conn      用來限制同一時間連線數,即併發限制

其中limit_req_conn模組可以根據源IP限制單使用者併發訪問的連線數或連線到該服務的總併發連線數

什麼是漏桶演算法?
我們假設系統是一個漏桶,當請求到達時,就是往漏桶裡"加水",而當請求被處理掉,就是水從漏桶的底部漏出。水漏出的速度是固定的,當"加水"太快,
桶就會溢位,也就是"拒絕請求"。從而使得桶裡的水的體積不可能超出桶的容量。​主要目的是控制資料注入到網路的速率,平滑網路上的突發流量。漏桶算
法提供了一種機制,通過它,突發流量可以被整形以便為網路提供一個穩定的流量。

示例一:
http {
limit_conn_log_level error;
limit_conn_status 503;
limit_conn_zone $binary_remote_addr zone=one:10m;
limit_conn_zone $server_name zone=perserver:10m;
limit_req_zone $binary_remote_addr zone=allips:100m   rate=10r/s;   #其中$binary_remote_addr有時需要根據自己已有的log_format變數配置進行替換

server {
........
limit_conn  one  100;                                              
limit_conn perserver 1000;
limit_req   zone=allips  burst=5  nodelay;
.......
}
}

引數解釋:
Zone=one或allips 表示設定了名為"one"或"allips"的儲存區,大小為10兆位元組
rate=10r/s 意思是允許1秒鐘不超過10個請求
burst=5 表示最大延遲請求數量不大於5。  如果太過多的請求被限制延遲是不需要的 ,這時需要使用nodelay引數,伺服器會立刻返回503狀態碼。
limit_conn  one  100表示最大併發連線數100
limit_conn perserver 1000表示該服務提供的總連線數不得超過1000,超過請求的會被拒絕

示例二:   
http {
limit_req_zone $binary_remote_addr zone=one:100m   rate=10r/m;

server {
.......
limit_req   zone=one  burst=1  nodelay;
......
}
}

解釋:
rate=10r/m 
意思是允許1秒鐘不超過1個請求,最大延遲請求數量不大於5。
如果請求不需要被延遲,新增nodelay引數,伺服器會立刻返回503狀態碼。如果沒有該欄位會造成大量的tcp連線請求等待。

http{
limit_zone one  $binary_remote_addr  10m;
server
{
......
limit_conn  one  1;
......
}
}

這裡的 one 是宣告一個 limit_zone 的名字,$binary_remote_addr是替代 $remore_addr 的變數,10m是會話狀態儲存的空間。
limit_conn one 1 ,限制客戶端併發連線數量為1,allow only one connection per an IP address at a time(每次)。

按照字面的理解,lit_req_zone的功能是通過漏桶原理來限制使用者的連線頻率,(這個模組允許你去限制單個地址指定會話或特殊需要的請求數 )
而 limit_zone 功能是限制一個客戶端的併發連線數。(這個模組可以限制單個地址的指定會話或者特殊情況的併發連線數)
一個是限制併發連線一個是限制連線頻率,表面上似乎看不出來有什麼區別,那就看看實際的效果吧~~~
在我的測試機上面加上這兩個引數下面是我的部分配置檔案

http{
limit_zone one  $binary_remote_addr  10m;
#limit_req_zone  $binary_remote_addr  zone=req_one:10m rate=1r/s;
server
{
......
limit_conn   one  1;
#limit_req   zone=req_one  burst=120;
......
}
}

解釋一下 limit_zone one  $binary_remote_addr  10m;
這裡的 one 是宣告一個 limit_zone 的名字,$binary_remote_addr是替代 $remore_addr 的變數,10m是會話狀態儲存的空間
limit_conn one 1 ,限制客戶端併發連線數量為1

============================================================================
limit_zone兩種工作情況

a)limit_reqzone=one burst=10 ;
預設情況下是這樣配置的,這樣每個請求就會有一個delay時間,
limit_req_zone$binary_remote_addr zone=one:100m rate=10r/m;
就是每分鐘有10個令牌供使用者使用,按照a的配置情況,就會有一個delay,每個請求時間就是60/10,那每個請求時間就是6s。

b)limit_reqzone=one burst=10 nodelay;
- 新增nodelay配置,這樣就是根據你的網路狀況訪問,一分鐘訪問夠10次後,伺服器直接返回503。
- limit_req_zone$binary_remote_addr zone=one:100m rate=10r/m;
就是每分鐘有10個令牌供使用者使用,按照b的配置情況,就會根據網路情況訪問url,如果一分鐘超過10個令牌,伺服器返回503,
等待下一個一分鐘領取訪問令牌。

rate=10r/m 的意思是每個地址每分鐘只能請求10次,也就是說根據漏桶原理burst=1 一共有1塊令牌,並且每分鐘只新增10塊
令牌,1塊令牌發完後多出來的那些請求就會返回503。

加上nodelay之後超過 burst大小的請求就會直接返回503,如果沒有該欄位會造成大量的tcp連線請求等待。

例如:
http{
    ...
    #定義一個名為allips的limit_req_zone用來儲存session,大小是10M記憶體,
    #以$binary_remote_addr 為key,限制平均每秒的請求為20個,
    #1M能儲存16000個狀態,rete的值必須為整數,
    #如果限制兩秒鐘一個請求,可以設定成30r/m
    limit_req_zone $binary_remote_addr zone=allips:10m rate=20r/s;
    ...
    server{
        ...
        location {
            ...
            #限制每ip每秒不超過20個請求,漏桶數burst為5
            #brust的意思就是,如果第1秒、2,3,4秒請求為19個,
            #第5秒的請求為25個是被允許的。
            #但是如果你第1秒就25個請求,第2秒超過20的請求返回503錯誤。
            #nodelay,如果不設定該選項,嚴格使用平均速率限制請求數,
            #第1秒25個請求時,5個請求放到第2秒執行,
            #設定nodelay,25個請求將在第1秒執行。
            limit_req zone=allips burst=5 nodelay;
            ...
        }
        ...
    }
    ...
}

限制下載速度:
location /download { 
    limit_rate 128k; 
  } 

#如果想設定使用者下載檔案的前10m大小時不限速,大於10m後再以128kb/s限速可以增加以下配內容,修改nginx.conf檔案
location /download { 
       limit_rate_after 10m; 
       limit_rate 128k; 
 }  

====================================================================
nginx流量限制的使用場景
大家都知道伺服器資源有限的,但是客戶端來的請求是無限的(不排除惡意攻擊), 為了保證大部分的請求能夠正常響應,不得不放棄一些客戶端來的請求,
所以我們會採用Nginx的限流操作, 這種操作可以很大程度上緩解伺服器的壓力, 使其他正常的請求能夠得到正常響應。
如何使用Nginx實現基本的限流,比如單個IP限制每秒訪問50次。通過Nginx限流模組,我們可以設定一旦併發連線數超過我們的設定,將返回503錯誤給客戶端。
這樣可以非常有效的防止CC攻擊。再配合 iptables防火牆,基本上CC攻擊就可以無視了。

配置例項:
#統一在http域中進行配置
#限制請求
limit_req_zone $binary_remote_addr $uri zone=api_read:20m rate=50r/s;
#按ip配置一個連線 zone
limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
#按server配置一個連線 zone
limit_conn_zone $server_name zone=perserver_conn:100m;
server {
  listen  80;
  server_name report.52itstyle.com;
  index login.jsp;
  location / {
    #請求限流排隊通過 burst預設是0
    limit_req zone=api_read burst=5;
    #連線數限制,每個IP併發請求為2
    limit_conn perip_conn 2;
    #服務所限制的連線數(即限制了該server併發連線數量)
    limit_conn perserver_conn 1000;
    #連線限速
    limit_rate 100k;
    proxy_pass  http://report;
  }
}
upstream report {
  fair;
  server 192.168.10.12:8882 weight=1 max_fails=2 fail_timeout=30s;
  server 192.168.10.12:8881 weight=1 max_fails=2 fail_timeout=30s;
}

配置503錯誤
預設情況,超出限制額度,將會報503錯誤,提示:
503 Service Temporarily Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later. Sorry for the inconvenience.
Please report this message and include the following information to us.
Thank you very much!

這樣顯示沒毛病,但是不夠友好,這裡我們自定義503錯誤。
error_page 500 502 503 504 /50x.html;
location = /50x.html {
 root html;                 #自定義50X錯誤
}

配置說明
limit_conn_zone
是針對每個IP定義一個儲存session狀態的容器。這個示例中定義了一個100m的容器,按照32bytes/session,可以處理3200000個session。

limit_rate 300k;
對每個連線限速300k. 注意,這裡是對連線限速,而不是對IP限速。如果一個IP允許兩個併發連線,那麼這個IP就是限速limit_rate×2。

burst=5;
這相當於在檢查站req旁邊放5個座位。如果某個請求當時超過速度限制被攔了,請他在空座位上坐著,等排隊,如果檢查站空了,就可以通過。
如果連座位都坐滿了,那就抱歉了,請求直接退回,客戶端得到一個伺服器忙的響應。所以說burst跟request_rate一點關係都沒有,設成10000,
就是1萬個請求可以等著排隊,而檢查站還是1秒鐘放行5個請求(龜速)。而且也不能一直排隊,所以nginx還設了超時,排隊超過一定時間,
也是直接退回,返回伺服器忙的響應。

以上配置Nginx需要配置以下模組:
ngx_http_limit_conn_module (static)
ngx_http_limit_req_module (static)

執行命令"nginx -V"就可以檢查到是否有安裝。

===================================================================
電商平臺營銷時候,經常會碰到的大流量問題,除了做流量分流處理,可能還要做使用者黑白名單、信譽分析,進而根據使用者ip信譽權重做相應的流量攔截、限制流量。
Nginx自身有的請求限制模組ngx_http_limit_req_module、流量限制模組ngx_stream_limit_conn_module基於令牌桶演算法,可以方便的控制令牌速率,自定義
調節限流,實現基本的限流控制。

對於提供下載的網站,肯定是要進行流量控制的,例如軟體下載站、視訊服務等。它也可以減少一些爬蟲程式或者DDOS的攻擊。

limit_zone指令可以用limit_conn_zone替換

如何Nginx限制同一個ip的連線數,限制併發數目?

限流
1) 新增limit_zone和limit_req_zone
這個變數只能在http區域使用 :
http {
limit_zone one $binary_remote_addr 20m;
limit_req_zone $binary_remote_addr zone=req_one:20m rate=12r/s;
......
}

2) 新增limit_conn 和limit_req
這個變數可以在http, server, location使用。如果限制nginx上的所有服務,就新增到http裡面;如果限制部分服務,就新增到相應的server或者location裡。
http {
limit_zone one $binary_remote_addr 20m;
limit_req_zone $binary_remote_addr zone=req_one:20m rate=12r/s;
limit_conn one 10;
limit_req zone=req_one burst=120;
......
}

引數詳解(數值按具體需要和伺服器承載能力設定):
limit_zone,是針對每個變數(這裡指IP,即$binary_remote_addr)定義一個儲存session狀態的容器。這個示例中定義了一個20m的容器,按照32bytes/session,可以處理640000個session。
limit_req_zone 與limit_zone類似。rate是請求頻率. 每秒允許12個請求。
limit_conn one 10 : 表示一個IP能發起10個併發連線數
limit_req: 與limit_req_zone對應。burst表示快取住的請求數。

配置範例:
http
{
limit_zone one $binary_remote_addr 20m;
limit_req_zone $binary_remote_addr zone=req_one:20m rate=12r/s;
limit_conn one 10;
limit_req zone=req_one burst=120;
server {
listen 80;
server_name status.test.kevin.com ;
location / {
stub_status on;
access_log off;
}
}
}

++++++++++++++++++++++++++++++++++++++++++++++++++++++
nginx白名單設定
以上配置會對所有的ip都進行限制,有些時候我們不希望對搜尋引擎的蜘蛛或者某些自己的代理機過來的請求進行限制, 
對於特定的白名單ip我們可以藉助geo指令實現。

先在nginx的請求日誌進行統計,檢視那個ip的訪問量比較大,執行:
# cat access.log | grep "03/Jun" |awk '{print $1}'|sort |uniq -c|sort -nrk 1|head -n 10
#列出訪問日誌裡面在6月3號這天前10個訪問量最大的ip.

接下來就可以對這些IP進行分析了。看哪些需要進行白名單設定。
http{
geo $limited {                          # the variable created is $limited
default 1;
127.0.0.1/32 0;
10.12.212.63 0;
}
map $limited $limit {
1 $binary_remote_addr;
0 "";
}
limit_zone one $binary_remote_addr 20m;
limit_req_zone $limit zone=req_one:20m rate=20r/s;
limit_conn one 10;
limit_req zone=req_one burst=120;
}

上面兩個需要用到map和geo模組,這是nginx自帶的模組,有的運維喜歡把他們關閉,自己./sbin/nginx -V 留意一下。
把配置的--whithout-XXX-module 去掉重新編譯一下就可以了。 上面這段配置的意思是:
a)geo指令定義了一個白名單limited變數,預設值為1,如果客戶端ip在上面的範圍內,limited變數,預設值為1,如果客戶端ip在上面的範圍內,
limited的值為0
b)使用map指令對映搜尋引擎客戶端的ip為空串,如果不是搜尋引擎就顯示本身真實的ip,這樣搜尋引擎ip就不能存到limit_req_zone記憶體session中,
所以不會限制搜尋引擎的ip訪問

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
獲取客戶端的真實IP?

順帶一提,為了獲取客戶端的真實IP。該模組需要安裝read_ip模組,運維應該預設有安裝。沒有的話也可自行安裝: 
配置方式相當簡單,重新編譯Nginx 加上 --with-http_realip_module 引數,如:
# ./configure --prefix=/opt/nginx --with-http_stub_status_module --with-pcre=../pcre-6.6 --with-http_realip_module
# make
# make install

在server中增加:
set_real_ip_from 192.168.1.0/24;
set_real_ip_from 192.168.2.1;
real_ip_header [X-Real-IP|X-Forwarded-For];

需要說明的地方就是設定IP源的時候可以設定單個IP,也可以設定IP段,另外是使用X-Real-IP還是X-Forwarded-For,取決於前面的伺服器有哪個頭。
set_real_ip_from 設定的IP端可以讓運維檢視日誌,看下你的請求是來自哪些ip段。
重新載入一下服務,差不多就OK了。
再檢視日誌的話,應該可以看到客戶端的真實IP了。

注意:如果未安裝該模組的話你的獲取到的IP端可能是來自前端代理(如squid)的IP,結果就是多個使用者被當成單個使用者對待,導致應用不能響應。

------自測: 有條件的自己可以用ab或者webben自測一下--------
未安裝前壓測的話,因為有大量請求,所以access.log會有大量日誌,而error.log日誌沒有變化。
[root@kevin ~]# webbench -c 30 -t 30 http://test.kevin.com
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://test.kevin.com
30 clients, running 30 sec.
Speed=193468 pages/min, 1254317 bytes/sec.
Requests: 96734 susceed, 0 failed.

安裝後會發現很多超出的請求會返回503,所以access.log日誌變化不快,error.log有大量記錄,提示limit_reque緩住了多少請求。
kevin ~ webbench -c 30 -t 30 http://test.kevin.com
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://test.kevin.com
30 clients, running 30 sec.
Speed=120 pages/min, 778 bytes/sec.
Requests: 60 susceed, 0 failed.

10.nginx的訪問控制及DDOS預防
1)訪問控制配置
基於各種原因,Ningx有時要進行訪問控制。
比如說,一般網站的後臺都不能讓外部訪問,所以要新增 IP 限制,通常只允許公司的IP訪問。
訪問控制就是指只有符合條件的IP才能訪問到這個網站的某個區域。
涉及模組:ngx_http_access_module
模組概述:允許限制某些 IP 地址的客戶端訪問。
對應指令:
allow
語法: allow address | CIDR | unix: | all;
預設值: —
作用域: http, server, location, limit_except
允許某個 IP 或者某個 IP 段訪問。如果指定 unix,那將允許 socket 的訪問。注意:unix 在 1.5.1 中新加入的功能,如果你的版本比這個低,請不要使用這個方法。

deny
語法: deny address | CIDR | unix: | all;
預設值: —
作用域: http, server, location, limit_except
禁止某個 IP 或者一個 IP 段訪問。如果指定 unix,那將禁止 socket 的訪問。注意:unix 在 1.5.1 中新加入的功能,如果你的版本比這個低,請不要使用這個方法。

示例說明:
server {
      listen 80;
     server_name forum.wangshibo.com;
     root /var/www/html;
     location / {
       deny 192.168.1.1;
       allow 192.168.1.0/24;
       allow 10.1.1.0/16;
       allow 103.10.67.56;
       deny all;
       }
}
規則按照順序依次檢測,直到匹配到第一條規則。
在這個例子裡,只有 10.1.1.0/16 、192.168.1.0/24和103.10.67.56允許訪問,但 192.168.1.1 除外。

如下例項:
1)先是多域名繫結一個目錄後的301跳轉至同一個域名
2)針對網站訪問做來源ip白名單設定,並加上密碼。(即使用者認證配置)
[root@test-huanqiu vhosts]# cat test.conf

server {
     listen 80;
     server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com;
     if ($host != 'www.wangshibo.com') {
     rewrite ^/(.*)$ http://www.wangshibo.com/$1 permanent;
     }
     root /var/www/html;
     index index.html index.php index.htm;
     access_log /usr/local/nginx/logs/image.log;

     allow  192.168.1.0/24; 
     allow  124.65.197.154; 
     deny  all;
     auth_basic "C1G_ADMID";
     auth_basic_user_file /usr/local/nginx/htpasswd;
}

[root@test-huanqiu vhosts]# htpasswd -c /usr/local/nginx/htpasswd wangshibo
New password:
Re-type new password:
Adding password for user wangshibo
訪問站點http://www.wangshibo.com,效果如下:

ngx_http_access_module 配置允許的地址能訪問,禁止的地址被拒絕。這只是很簡單的訪問控制,而在規則很多的情況下,使用 ngx_http_geo_module 模組變數更合適。
這個模組大家下來可以瞭解 : ngx_http_geo_module

-------------------------------------------------------------------------------------------------------
上面也用到了nginx的使用者認證的配置,其中:
auth_basic 認證時的提示資訊
auth_basic_user_file 認證時存放使用者名稱和密碼的檔案

# htpasswd -c /usr/local/nginx/htpasswd wangshibo       //第一次設定認證的使用者
# htpasswd /usr/local/nginx/htpasswd guohuihui           //追加認證的使用者,後面再次追加認證使用者時,不要加-c引數,否則就會覆蓋之前新增的使用者!

下面順便看幾個認證部分的配置:

location /admin/ { 
auth_basic "Admin Auth."; 
auth_basic_user_file /usr/local/nginx/htpasswd; 
} 


location /wangshibo/ { 
proxy_pass http://www.guohuihui.com/heng/; 
auth_basic "Test Auth."; 
auth_basic_user_file /usr/local/nginx/htpasswd; 
} 

location ^~ /auth/ { 
location ~ .*.(php|php5)?$ { 
fastcgi_pass 127.0.0.1:9000; 
fastcgi_index index.php; 
include fcgi.conf; 
} 
auth_basic "Authorized users only"; 
auth_basic_user_file /usr/local/nginx/htpasswd;
} 

2)DDOS預防配置
DDOS的特點是分散式,針對頻寬和服務攻擊,也就是四層流量攻擊和七層應用攻擊,相應的防禦瓶頸四層在頻寬,七層的多在架構的吞吐量。
對於七層的應用攻擊,還是可以做一些配置來防禦的,使用nginx的http_limit_conn和http_limit_req模組通過限制連線數和請求數能相對有效的防禦。
其中:
ngx_http_limit_conn_module    可以限制單個 IP 的連線數
ngx_http_limit_req_module      可以限制單個 IP 每秒請求數
配置方法:
(1)限制每秒請求數,即ip訪問頻率限制 
涉及模組:ngx_http_limit_req_module
通過漏桶原理來限制單位時間內的請求數,一旦單位時間內請求數超過限制,就會返回 503 錯誤。
配置範例:
http {
       limit_req_zone $binary_remote_addr zone=one:10m rate=20r/s;
...
       server {
...
      location ~ \.php$ {
          limit_req zone=one burst=5 nodelay;
          }
      }
}

配置說明(上一部分解釋過的就不再解釋):
定義一個名為one的limit_req_zone用來儲存session,大小是10M記憶體,
以$binary_remote_addr 為key,限制平均每秒的請求為20個,
1M能儲存16000個狀態,rete的值必須為整數,
rate=20r/s表示限制頻率為每秒20個請求;如果限制兩秒鐘一個請求,可以設定成30r/m。
限制每ip每秒不超過20個請求,漏桶數burst為5
brust的意思就是,如果第1秒、2,3,4秒請求為19個,
第5秒的請求為25個是被允許的。
但是如果你第1秒就25個請求,第2秒超過20的請求返回503錯誤。
nodelay,如果不設定該選項,嚴格使用平均速率限制請求數,
第1秒25個請求時,5個請求放到第2秒執行,
設定nodelay,25個請求將在第1秒執行。

(2)限制IP連線數(上面已經說明,這裡直接寫配置)
http {
       limit_conn_zone $binary_remote_addr zone=addr:10m;               //上面講過
...
      server {
...
      location /ops/ {
      limit_conn addr 1;
         }
     }
}

總的來說:如何設定能限制某個IP某一時間段的訪問次數是一個讓人頭疼的問題,特別面對惡意的ddos攻擊的時候。其中CC攻擊(Challenge Collapsar)是DDOS(分散式拒絕服務)的一種,也是一種常見的網站攻擊方法,攻擊者通過代理伺服器或者肉雞向向受害主機不停地發大量資料包, 造成對方伺服器資源耗盡,一直到當機崩潰。
cc攻擊一般就是使用有限的ip數對伺服器頻繁傳送資料來達到攻擊的目的。

nginx可以通過Http LimitReq Modul和Http LimitZone Module配置來限制ip在同一時間段的訪問次數來防cc攻擊。
1)Http LimitReq Modul用來限制連單位時間內連線數的模組,使用limit_req_zone和limit_req指令配合使用來達到限制。一旦併發連線超過指定數量,就會返回503錯誤。
2)Http LimitConn Modul用來限制單個ip的併發連線數,使用limit_zone和limit_conn指令

配置示例:
Http LimitReq Modul限制某一段時間內同一ip訪問數
http{
......
      limit_req_zone $binary_remote_addr zone=allips:10m rate=20r/s;
......
     server{
...
     location {
......
       limit_req zone=allips burst=5 nodelay;
......
    }
......
   }
......
}

Http LimitZone Module 限制併發連線數例項
limit_zone只能定義在http作用域,limit_conn可以定義在http server location作用域
http{
...
    limit_conn_zone one $binary_remote_addr 10m;
......
    server{
......
    location {
......
      limit_conn one 20;
      limit_rate 500k;
......
     }
......
     }
......
}

(3)限速白名單設定(可參考:nginx利用geo模組做限速白名單以及geo實現全域性負載均衡的操作記錄
http_limit_conn和 http_limit_req模組限制了單IP單位時間內的連線和請求數,但是如果Nginx前面有lvs或者haproxy之類的負載均衡或者反向代理,nginx 獲取的都是來自負載均衡的連線或請求,這時不應該限制負載均衡的連線和請求,就需要 geo 和 map 模組設定白名單:
geo $whiteiplist {
     default 1;
     10.11.15.1610;
}
map $whiteiplist$limit {
     1 $binary_remote_addr;
     0 "";
}
limit_req_zone $limit zone=one:10m rate=10r/s;
limit_conn_zone $limit zone=addr:10m;

geo 模組定義了一個預設值是 1 的變數 whiteiplist,當在 ip 在白名單中,變數 whiteiplist 的值為 0,反之為1.
對上面設定的邏輯關係解釋:
如果在白名單中--> whiteiplist=0 --> $limit="" --> 不會儲存到 10m 的會話狀態(one 或者 addr)中 --> 不受限制;
反之,不在白名單中 --> whiteiplist=1 --> $limit=二進位制遠端地址 -->儲存進 10m 的會話狀態中 --> 受到限制。

(4)動手測試DDOS預防配置
下面來測一下上面說到的配置是否起到了作用。
安裝nginx+php環境
寫一個測試的PHP檔案,修改nginx配置檔案,使其能正常訪問。
在/home/shiyanlou目錄下寫一個test.php,內容如下:
[root@server_web1 ~]# vim /home/shiyanlou/test.php
<?php
phpinfo ();
?>

nginx 配置檔案修改:

 

最後展示:

使ab命令進行測試,比較修改nginx配置檔案前後(連線數和請求數分開測試)的測試結果。

修改之前:

測試結果為:

對nginx配置做修改(新增http和php配置如下的紅線內容),重啟,然後再進行測試

 

 

測試結果為:

11.訪問白名單
參考:nginx訪問白名單設定以及根據$remote_addr分發

12.nginx的上傳下載設定
參考:nginx限制上傳大小和超時時間設定說明/php限制上傳大小

13.nginx目錄瀏覽及其驗證功能
參考:nginx下目錄瀏覽及其驗證功能配置記錄

14.Nginx下禁止指定目錄執行php指令碼檔案

非常簡單,直接通過location條件匹配定位後進行許可權禁止。

在server配置段中增加下面的的配置:

1)如果是單個目錄
location ~* ^/uploads/.*\.(php|php5)$ {  
    deny all; 
}  

2)如果是多個目錄
location ~* ^/(attachments|uploads)/.*\.(php|php5)$ { 
   deny all; 
}  

注意:這段配置檔案一定要放在下面配置的前面才可以生效。
location ~ \.php$ { 
fastcgi_pass 127.0.0.1:9000; 
fastcgi_index index.php; 
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 
include fastcgi_params; 
} 

配置完後記得重啟Nginx生效。

------------------------------------------------------------------------------
如果是Apache下禁止指定目錄執行PHP指令碼,在虛擬主機配置檔案中增加php_flag engine off指令即可,配置如下
"/website/uploads">  
  Options FollowSymLinks  
  AllowOverride None  
  Order allow,deny  
  Allow from all   
  php_flag engine off  

15.Nginx下開啟gzip壓縮功能,大幅提高頁面載入速度

如果發現如上配置後,訪問頁面時,gzip壓縮沒有生效。一般原因就是該頁面的相應的gzip_type型別沒有加進去。
 
檢查一個頁面的gzip是否生效:
[root@uatinner-lb01 ~]# curl -I -H "Accept-Encoding: gzip, deflate" "http://www.kevin.com/blog/plugins/bo-coolings/bo-coolings.css"
HTTP/1.1 200 OK
Date: Fri, 14 Sep 2018 09:10:38 GMT
Content-Type: text/html
Connection: keep-alive
Set-Cookie: __cfduid=da2267d06a7d8364c8d4c9193627d56f91536916238; expires=Sat, 14-Sep-19 09:10:38 GMT; path=/; domain=.slyar.com; HttpOnly
CF-Cache-Status: EXPIRED
Expires: Tue, 19 Mar 2019 09:10:38 GMT
Cache-Control: public, max-age=16070400
Vary: Accept-Encoding
Server: cloudflare
CF-RAY: 45a1b8bb26712132-LAX
Content-Encoding: gzip
 
如果發現訪問如上的http://www.kevin.com/blog/plugins/bo-coolings/bo-coolings.css頁面時,gzip沒有生效。
就注意檢視下上面結果中的Content-Type型別的內容(如上是text/html)是否加到了nginx.conf檔案中gzip配置區域裡。如果沒有,就加上,並reload nginx服務即可!

16.Nginx使用非root使用者啟動

在linux系統裡, 監聽埠在1024以下的服務必須使用root使用者啟動, 1024以上埠的應用服務可以使用非root使用者啟動.

比如, nginx預設埠是80, 必須使用root使用者啟動. 考慮到安全問題, 採用非root使用者啟動, 比如app使用者.
[root@web ~]# cat /data/nginx/conf/nginx.conf
user  app;
 
然後切換到app使用者下啟動
[root@web ~]# su - app
[app@web ~]$ /data/nginx/sbin/nginx

非root使用者在檢查nginx配置檔案或啟動nginx的時候,會出現告警資訊:
nginx: [warn] the "app" directive makes sense only if the master process runs with super-user privileges, ignored in 
/data/nginx/conf/nginx.conf:2

這是因為:
- 在非root賬戶下啟動時,nignx的master和worker程式的owner都將是這個賬戶(這裡是app使用者),
- 在root賬戶下啟動時 nignx的master程式是的owner是rootworker的owner在conf已配置使用者的情況下,owner是配置的使用者,否則將是nobody,
  而且也可能導致nginx的一些檔案的owner也是nobody

所以出現了上面那個warn告警資訊, 可以忽略, 不影響

[app@web ~]$ ps -ef|grep nginx
app       8837     1  0 16:02 ?        00:00:00 nginx: master process /data/nginx/sbin/nginx
app       8838  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8839  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8840  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8841  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8842  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8843  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8844  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8845  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8846  8837  0 16:02 ?        00:00:00 nginx: cache manager process

17. Nginx實現404錯誤頁面跳轉的幾種方法

Nginx作為常用網站的web伺服器, 出現404錯誤頁面的跳轉實現方式主要有以下幾種: 

第一種情況: Nginx自己的錯誤頁面
Nginx訪問一個靜態的html 頁面,當這個頁面沒有的時候,Nginx丟擲404,那麼如何返回給客戶端404呢?
看下面的配置,這種情況下不需要修改任何引數,就能實現這個功能。
[root@localhost ~]# cat /data/nginx/conf/nginx.conf
.........
http {
    proxy_intercept_errors on;                          //如果nginx不做代理, 不代理到後面的tomcat伺服器, 只是自己的靜態頁訪問, 則這一行加不加都可以實現;

[root@localhost ~]# cat /data/nginx/conf/test.conf
server {
      listen      80;
      server_name localhost;
    
      access_log  /data/nginx/logs/access.log main;
      error_log  /data/nginx/logs/error.log;
    
   location / {
        root /data/web;
        index index.php index.html index.htm; 
        }

       #定義錯誤頁面碼,如果出現相應的錯誤頁面碼,轉發到那裡。
       error_page  404 403 500 502 503 504  /404.html;
   
       #承接上面的location。
       location = /404.html {
       #放錯誤頁面的目錄路徑。
           root /data/web;
        }
}

------------------------------------------------------------------------------------------
需要注意:
如果是跳轉到其他url, 則配置改為:
       #定義錯誤頁面碼,如果出現相應的錯誤頁面碼,轉發到那裡。
       error_page  404 403 500 504  http://www.haha.com;
------------------------------------------------------------------------------------------
需要注意:
或是可以設定多種型別的錯誤頁面
      # 這裡的錯誤碼可以是多個
      error_page   500 502 503 504  /50x.html;
      location = /50x.html {
            root   /data/web;
        }
        
     error_page   404  /404.html;
     location = /404.html {
            root   /data/web;
        }

然後在定義的/data/web目錄下編寫50x.html和404.html錯誤頁面內容
-----------------------------------------------------------------------------------------

到定義的錯誤頁面存放目錄下編輯404錯誤頁面內容:
[root@localhost vhosts]# ll /data/web/
total 8
-rw-r--r-- 1 root root 50 Dec 19 16:04 404.html
-rw-r--r-- 1 root root 21 Dec 19 15:59 index.html

[root@localhost vhosts]# cat /data/web/404.html 
Sorry, sir, this page does not exist! Excuse me ~

重啟nginx服務
[root@localhost vhosts]# /data/nginx/sbin/nginx -t
nginx: the configuration file /data/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /data/nginx/conf/nginx.conf test is successful
[root@localhost vhosts]# /data/nginx/sbin/nginx -s reload

然後訪問nginx的地址, 當訪問一個錯誤頁面時, 就會出現定義的404錯誤頁面內容: "Sorry, sir, this page does not exist! Excuse me ~"

============================================
第二種:反向代理的錯誤頁面 (nginx代理的後端是tomcat頁面, 使用proxy_intercept_errors on引數, 該引數可以放在http區域, 也可以訪問server或location區域)

如果後臺Tomcat處理報錯丟擲404,想把這個狀態叫Nginx反饋給客戶端或者重定向到某個連線.
比如在自己的Linux伺服器上部署了tomcat的一個專案,使用Nginx進行的代理,訪問專案不存在的頁面時,出現的是Nginx預設的404頁面,
現在要配置自己定義的404頁面進行提示

配置如下:
[root@localhost ~]# cat /data/nginx/conf/vhost/test.conf
upstream tomcat {
ip_hash;
server 127.0.0.1:8080  weight=20 max_fails=2 fail_timeout=30s;
}

server {
      listen      80;
      server_name www.test.com;
    
      access_log  /data/nginx/logs/access.log main;
      error_log  /data/nginx/logs/error.log;
 

     location / {

        # 即把www.test.com的首頁設定為index.html (預設情況下tomcat的首頁是index.jsp, 這裡在tomcat下的webapp/ROOT下加了index.html)
         if ($request_uri ~* '^/$') {
             rewrite .*   http://www.test.com/index.html redirect;
        }

        #關鍵引數(比如加下面這一行的引數配置):這個變數開啟後,我們才能自定義錯誤頁面,當後端返回404,nginx攔截錯誤定義錯誤頁面
        proxy_intercept_errors on;

       proxy_pass      http://tomcat;
       proxy_set_header HOST   $host;
       proxy_set_header X-Real-IP      $remote_addr;
       proxy_set_header X-Forwarded-FOR $proxy_add_x_forwarded_for;
       }

       error_page    404  /404.html;
       location = /404.html {
       root   /mnt/error;
       }
}

配置解釋:
if ($request_uri ~* "^/$")   表示url中只有域名,後面不跟任何東西,比如www.test.com。
if ($request_uri ~* "test")   表示域名後面那串兒只要包含test這個關鍵詞,就可匹配成功。比如www.test.com/pan/beta/test3

上面的配置表示:
當訪問http://www.test.com 時(即url只有一個完整的域名) 時, 頁面跳轉到tomcat跟下的index.html (即tomcat的webapp/ROOT/index.html, tomcat的預設首頁一般是webapp/ROOT/index.jsp)
也就是訪問http://www.test.com, 顯示為http://www.test.com/index.html, 這個index.html是tomcat的webapp/ROOT/index.html
當訪問http://www.test.com/* 時, 跳轉到http://127.0.0.1:8080/*  , 比如訪問 http://www.test.com/index.jsp, 跳轉到http://127.0.0.1:8080/index.jsp,
當訪問http://www.test.com/* 的頁面時, 頁面不存在, 則顯示404錯誤頁面, 錯誤頁面檔案為/mnt/error/404.html

[root@localhost ~]# ll /usr/local/tomcat8/webapps/ROOT/index.html 
-rw-r--r-- 1 root root 21 Dec 19 16:32 /usr/local/tomcat8/webapps/ROOT/index.html

[root@localhost ~]# ll /usr/local/tomcat8/webapps/ROOT/index.jsp 
-rw-r--r-- 1 root root 12513 Jun 29 10:44 /usr/local/tomcat8/webapps/ROOT/index.jsp

[root@localhost ~]# ll /mnt/error/404.html 
-rw-r--r-- 1 root root 31 Dec 19 17:12 /mnt/error/404.html

[root@localhost ~]# /data/nginx/sbin/nginx -s reload

-------------------------------------------------------------------------------------------------------------------
這裡注意下: 看下面這個情況的錯誤頁面本地跳轉配置
[root@localhost ~]# cat /data/nginx/conf/nginx.conf
..........
http {
    proxy_intercept_errors on;

[root@localhost ~]# cat /data/nginx/conf/vhosts/test.conf
  server {
      listen      80;
      server_name www.test.com;

      access_log  /data/nginx/logs/access.log main;
      error_log  /data/nginx/logs/error.log;

      location / {
          proxy_pass http://127.0.0.1:8080;
          proxy_set_header   REMOTE-HOST $remote_addr;
          proxy_set_header   Host $host; 
          proxy_set_header   X-Real-IP $remote_addr; 
          proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
          client_max_body_size    20m; 
          }

      location /upload {
            root   /data/web;
            index  index.html index.htm;
        }

    #error_page  404  /404.html;
    error_page   500 502 503 504  /404.html;
    error_page   404  /404.html;
    location = /404.html {
            root  /data/web/error;
        }
}


[root@localhost ~]# cat /data/web/error/404.html 
Sorry, sir, this page does not exist! Excuse me ~

[root@localhost ~]# /data/nginx/sbin/nginx -s reload

當8080埠的tomcat服務沒有開啟時, 訪問http://www.test.com , 則會出現定義在/data/web/error/404.html錯誤頁面內容
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

================================================
第三種:反向代理的錯誤頁面 (nginx代理的後端是php解析的頁面, 使用fastcgi_intercept_errors on引數, 該引數可以放在http區域, 也可以訪問server或location區域)
Nginx解析php程式碼的錯誤頁面, 如果後端是php解析的,需要加一個變數fastcgi_intercept_errors on進行錯誤頁面提示, 否則php頁面則顯示為空白頁!
在http段中加一個變數 fastcgi_intercept_errors on 就可以了。
[root@localhost ~]# vim /data/nginx/conf/nginx.conf
.........
http {
    fastcgi_intercept_errors on;

接著指定一個錯誤頁面
[root@localhost ~]# vim /data/nginx/conf/vhosts/test.conf
........
    error_page    404  /404.html;
    location = /404.html {
    root   /mnt/error;
}

錯誤頁面404.html 放在/mnt/error下面

如果指定404錯誤時跳轉到其他的一個錯誤頁面, 配置為
[root@localhost ~]# vim /data/nginx/conf/vhosts/test.conf
........
     error_page 404  /404.html;
     error_page 404 = http://www.test.com/error.html;

=================================================================
溫馨提示:
配置proxy_intercept_errors on時, 配置的錯誤頁面表示的是當伺服器返回的狀態碼為我們配置的狀態碼時,才進行的頁面跳轉。
如:伺服器中沒有xxxx.do介面時,訪問了這個介面,配置了proxy_intercept_errors on則也會進行頁面跳轉

如果伺服器中沒有開啟服務,則配置proxy_intercept_errors on無用,則需要再新增fastcgi_intercept_errors on配置, 
這樣的話,出現頁面錯誤時也會進行跳轉

總結:
=====什麼是404頁面======
如果碰巧網站出了問題,或者使用者試圖訪問一個並不存在的頁面時,此時伺服器會返回程式碼為404的錯誤資訊,此時對應頁面就是404頁面。
404頁面的預設內容和具體的伺服器有關。如果後臺用的是NGINX伺服器,那麼404頁面的內容則為:404 Not Found 

NGINX下如何自定義404頁面
1) 更改nginx.conf在http定義區域加入: proxy_intercept_errors或者fastcgi_intercept_errors
2) 更改nginx.conf,在server 區域加入: error_page 404  /404.html  或者 error_page 404 =http://www.xxx.com/404.html
3) 更改後重啟nginx,,測試nginx.conf正確性

#502 等錯誤可以用同樣的方法來配置。  配置如下:

error_page  500 502 503 504  /50x.html;
       location = /50x.html {
       root   /mnt/error;
       }

或是
error_page 500 501 502 503 504 @errpage;
    location @errpage {
      access_log logs/access.log maintry;
      proxy_pass url;
}

注意事項:
1) 要新增:fastcgi_intercept_errors on  或者  proxy_intercept_errors
預設: fastcgi_intercept_errors off
新增位置: http, server, location
預設情況下,nginx不支援自定義404錯誤頁面,只有這個指令被設定為on,nginx才支援將404錯誤重定向
這個指令指定是否傳遞4xx和5xx錯誤資訊到客戶端,或者允許nginx使用error_page處理錯誤資訊。你必須明確的在error_page中指定處理方法使這個引數有效

2) 不要出於省事或者提高首頁權重的目的將首頁指定為404錯誤頁面,也不要用其它方法跳轉到首頁

3) 自定義的404頁面必須大於512位元組,否則可能會出現IE預設的404頁面。例如,假設自定義了404.html,大小隻有11個位元組(內容為:404錯誤)

===== fastcgi_intercept_errors 引數===== 
語法:fastcgi_intercept_errors on|off 
預設值:fastcgi_intercept_errors off 
使用欄位:http, server, location 
這個指令指定是否傳遞4xx和5xx錯誤資訊到客戶端,或者允許nginx使用error_page處理錯誤資訊。
你必須明確的在error_page中指定處理方法使這個引數有效,正如Igor所說“如果沒有適當的處理方法,nginx不會攔截一個錯誤,這個錯誤不會顯示自己的預設頁面,這裡允許通過某些方法攔截錯誤。

===== f注意搞清楚下面情況===== f
404.html:上游伺服器提供的特定404頁面內容,當nginx:80訪問上游伺服器資源不存在(返回404),要求顯示的內容頁面。
404_default.html:上游伺服器預設404頁面。

配置如下:
       error_page    404  /404.html;
       location = /404.html {
       root   /mnt/error;
       }

       或者
       error_page    404  /404_default.html;
       location = /404_default.html {
       root   /mnt/error;
       }

50x.html:上游伺服器提供的特定50x頁面內容,當nginx:80訪問上游伺服器出現50x錯誤(包含500, 502, 503和504),要求顯示的內容頁面。
50x_default.html:上游伺服器提供的處理50x的預設頁面

配置如下:
       error_page    50x  /50x.html;
       location = /50x.html {
       root   /mnt/error;
       }

       或者
       error_page    50x  /50x_default.html;
       location = /50x_default.html {
       root   /mnt/error;
       }

18. nginx實現動靜分離

將靜態資源放在 A 主機的一個目錄上,將動態程式放在 B 主機上,同時在 A 上安裝 Nginx 並且在 B 上安裝 Tomcat。配置 Nginx,當請求的是 html、jpg 等靜態資源時,就訪問 A 主機上的靜態資源目錄;當使用者提出動態資源的請求時,則將請求轉發到後端的 B 伺服器上,交由 Tomcat 處理,再由 Nginx 將結果返回給請求端。

提到這,可能會有疑問,動態請求要先訪問 A,A 轉發訪問 B,再由 B 返回結果給 A,A 最後又將結果返回給客戶端,這是不是有點多餘。初看的確多餘,但是這樣做至少有 2 點好處。第一,為負載均衡做準備,因為隨著系統的發展壯大,只用一臺 B 來處理動態請求顯然是是不夠的,要有 B1,B2 等等才行。那麼基於圖 2 的結構,就可以直接擴充套件 B1,B2,再修改 Nginx 的配置就可以實現 B1 和 B2 的負載均衡。第二,對於程式開發而言,這種結構的程式撰寫和單臺主機沒有區別。我們假設只用一臺 Tomcat 作為伺服器,那麼凡是靜態資源,如圖片、CSS 程式碼,就需要編寫類似這樣的訪問程式碼:<img src=”{address of A}/a.jpg”>,當靜態資源過多,需要擴充套件出其他的伺服器來安放靜態資源時,訪問這些資源就可能要編寫這樣的程式碼:<img src=”{address of C}/a.jpg”>、<img src=”{address of D}/a.jpg”>。可以看到,當伺服器進行變更或擴充套件時,程式碼也要隨之做出修改,對於程式開發和維護來說非常困難。而基於上面的結構,程式都只 要 <img src=”a.jpg”>,無需關心具體放置資源的伺服器地址,因為具體的地址 Nginx 為幫您繫結和選擇。

動靜分離的nginx配置如下:

 # 轉發的伺服器,upstream 為負載均衡做準備
 upstream tomcat_server{ 
        server 172.16.50.60:8080 weight=1 max_fails=2  fail_timeout=2;
 } 

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   /data/web;
            index  index.html index.htm;
        }

        # 靜態請求直接讀取
       location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css)$ {
          root   /data/web;
          expires    30d;          #快取時間,即有效時間
       }

       # 動態請求的轉發
        location ~ .*.jsp$ { 
            proxy_pass http://tomcat_server; 
            proxy_set_header Host $host; 
        } 
}


=============================================================
如果還有php檔案, 則配置新增如下:
upstream php {
    server  172.16.50.15 weight=1 max_fails=2  fail_timeout=2;
    server  172.16.50.16 weight=1 max_fails=2  fail_timeout=2;
} 

.......

location ~* \.php$ {
    fastcgi_proxy  http://php;
    }
==================================================================

18. nginx配置中關於url的幾個變數的區別 (如$request_uri , $uri 和 $document_uri )

$request_uri 
這個變數等於從客戶端傳送來的原生請求URI,包括引數。它不可以進行修改。$uri變數反映的是重寫後/改變的URI。不包括主機名。
其實這個$request_uri變數指的就是完整url中刨去最前面$host剩下的部分.
比如http://www.baidu.com/pan/beta/test1?fid=3這個url地址,去掉www.baidu.com剩下的就是了,日誌裡會看到列印出來的$request_uri,
$request_uri其實指的就是/pan/beta/test1?fid=3

如下匹配規則:
if ($request_uri ~* "^/$") 表示url中只有域名,後面不跟任何東西,比如www.baidu.com。
if ($request_uri ~* "test") 表示域名後面那串兒只要包含test這個關鍵詞,就可匹配成功。比如www.baidu.com/pan/beta/test3

$uri
這個變數指當前的請求URI,不包括任何引數。這個變數反映任何內部重定向或index模組所做的修改。
注意,這和request_uri不同,因$request_uri是瀏覽器發起的不做任何修改的原生URI。不包括協議及主機名。
比如http://www.baidu.com/pan/beta/test1?fid=3這個url地址,日誌裡會看到列印出來的$uri其實指的就是/pan/beta/test1

$document_uri
這個變數等同於$uri.
例如:"/pan/beta/test1"

總而言之:
$request_uri變數指的則是請求的整個字串,包含了後面的query_string的。
$uri變數:  指的是請求的檔案和路徑,不包括"?"或者"#"之後的東西

例如, 訪問http://www.kevin.com/stat.php?id=1585378&web_id=1585378
則這三個變數分別指的是:
$request_uri:     /stat.php?id=1585378&web_id=1585378
$uri:             /stat.php
$document_uri:    /stat.php

相關文章