入門Nginx

1、正向代理和反向代理

正向代理舉例:翻越萬里長城去遊覽牆外的景色
反向代理舉例:負載均衡php

正向代理和反向代理涉及三個主體:css

  • 請求方
  • 代理
  • 被請求方

正向代理中,代理跟請求方是一家子,請求方說要啥,代理就給他啥。
反向代理中,代理跟被請求方是一家子,代理統籌規劃讓哪個被請求方來處理請求,對於請求方來講,代理就是處理請求的人。大多數狀況下,反向代理和被請求方在同一個服務器上。Nginx就是最經常使用的反向代理服務器。html

這裏也提一下:動態代理和靜態代理
正向代理和反向代理是代理服務器的兩種類型
動態代理和靜態代理是Java中的設計模式:代理模式。
Spring的兩大核心:java

  • IOC控制反轉依賴注入
  • AOP面向切面編程

面向切面編程中大量使用動態代理,在每個方法調用前、調用後、拋異常時進行處理,跟裝飾器模式很像。linux

2、nginx配置體系

nginx主要配置位於/etc/nginx目錄下,nginx不只僅能夠用於負載均衡HTTP請求,也能夠用於基於TCP的其它協議的負載均衡。/etc/nginx/nginx.conf是nginx的跟配置,一切配置都是這個配置的子孫。nginx

/etc/nginx/nginx.confweb

users www-data;定義當前用戶
worker_prosesses 4;定義worker數
pid /run/nginx.pid;定義pid文件

events{......}
http{...
    http協議的相關配置
    include xxx路徑下的conf.d/*.conf;  可使用文件通配符來描述文件,可是必定是文件而非文件夾
}
mail{
    ....mail相關的一些配置
    server{
        listen localhost:xx;
        protocol pop3;
        proxy on;
    }
    server{
        listen localhost:xxxx;
        protocol imap;
        proxy on;
    }
}

能夠發現,最外層是協議,協議內部有若干個server組成,每一個server監聽一個端口,根據路徑能夠轉發到本地的其它端口進行處理。include是簡單的複製粘貼。正則表達式

3、用Nginx反向代理Tomcat服務器和Gunicorn服務器

需求說明:Tomcat和Gunicorn分別運行在8080端口和8000端口,如今要讓它們共用80端口。
當使用:localhost/tomcat/myapp時,至關於localhost:8080/myapp
當使用:localhost/gunicorn/myapp時,至關於localhost:8000/myappsql

server {
    listen  80;
    server_name www.haha.com;
    access_log  /var/log/nginx/reverse.log;
    location /tomcat {
        proxy_pass  http://127.0.0.1:8080/;
        proxy_set_header Host $host;  
        proxy_set_header X-Real-IP $remote_addr;  
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    }
    location /gunicorn {
        proxy_pass  http://127.0.0.1:8000/;
        proxy_set_header Host $host;  
        proxy_set_header X-Real-IP $remote_addr;  
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    }
}

server_name描述了服務器地址部分,既能夠是域名,也能夠是IP地址。這一項不可省略。
設置proxy_set_header部分是將請求者的真實信息告知後臺服務器shell

須要注意的是:

  • 配置nginx時,每一句後面都帶有一個分號,不帶分號會出錯,這是conf文件的語法;
  • 配置proxy_pass時,只能精確到端口號,不能轉發到再下一級,好比proxy_pass http://127.0.0.1:8000/myweb/這樣是錯誤的;
  • 配置proxy_pass時,端口號後面必須加上反斜槓/,不然路徑拼接時會由於少一個反斜槓而沒法解析,致使404錯誤。

4、瞭解負載均衡

負載均衡必然要用到反向代理,讓Nginx做爲大管家凌駕於處理請求的服務器之上,Nginx能夠動態決定讓哪一個服務器來處理請求。負載均衡問題源遠流長:兩臺相同的處理機處理若干任務,怎麼處理可以使得任務儘早完成?這是「雙塔」問題;兩臺不一樣的處理機處理若干任務,不一樣處理機處理不一樣任務花費時間不一樣,怎樣分配任務才能使得任務儘早完成?

負載均衡的核心問題就是:創建用戶請求和服務器之間的映射。有以下幾種方式:

  • 輪詢
    server=counter++%server_size
    用於後臺服務器性能差很少的狀況
  • 輪盤賭
    每一個服務器有一個權重weight,表示選中這個服務器做爲請求處理者的機率。
    用於後臺服務器性能有差別的狀況
  • IP-Hash
    創建用戶IP地址和後臺服務器之間的映射表。
    用於解決Session問題,避免了Session共享帶來的IO壓力。
  • URL-Hash
    創建用戶請求URL和後臺服務器之間的映射表。
    用於解決服務器緩存分佈分散,讓某個服務器專門負責某類請求,這樣可以更專業地處理請求。
    這種方式其實就至關於新建了一個Web程序,這時Nginx的做用更像是正向代理而不是反向代理。
  • Fair:按照響應時間
    Nginx知道每一個後端服務器處理請求的時間,誰處理時間短就讓誰來處理請求。
    在輪盤賭方法中,須要明確知道各個後臺服務器的性能好壞。使用Fair方法能夠自動檢測出後臺服務器性能好壞,從而動態分配。

輪盤賭的方式進行以下配置,首先定義一個upstream,它是多個server的集合。而後在location中就能夠直接使用這個upstream。

upstream your_host_or_ip {     
    server 127.0.0.3:8000 weight=5;     
    server 127.0.0.3:8001 weight=5;     
    server 192.168.0.1:8000;     
    server 192.168.0.1:8001;     
}     

server {     
    listen          80;     
    server_name     your_host_or_ip;     
    access_log      /var/log/nginx/my_access.log main;     

    location / {     
            proxy_pass      http://your_host_or_ip;     
    }     
}

須要注意的是,一臺服務器有兩種訪問方式:ip地址和域名方式。ip地址方式確定只能有一種方式進行訪問,由於ip地址是全網惟一的。而一臺服務器能夠綁定多個域名,這樣就能夠經過多個域名訪問同一個服務器了。
當配置了upstream以後,upstream的名稱確定跟服務器的名稱(IP或者域名)相同,因此一個域名只能進行一個負載均衡,一個IP也只能進行一個負載均衡,而一臺服務器能夠進行多個負載均衡。

5、地址匹配

location配置:
直接寫一個字符串,常規字符串匹配
~ 表示執行一個正則匹配,區分大小寫
~* 表示執行一個正則匹配,不區分大小寫
^~ 表示普通字符匹配。使用前綴匹配。若是匹配成功,則再也不匹配其餘location。
= 進行普通字符精確匹配。也就是徹底匹配。

location配置的優先級:
在Nginx的location和配置中location的順序沒有太大關係。正location表達式的類型有關。相同類型的表達式,字符串長的會優先匹配。
如下是按優先級排列說明:
第一優先級:等號類型(=)的優先級最高。一旦匹配成功,則再也不查找其餘匹配項。
第二優先級:^~類型表達式。一旦匹配成功,則再也不查找其餘匹配項。
第三優先級:正則表達式類型(~ ~*)的優先級次之。若是有多個location的正則能匹配的話,則使用正則表達式最長的那個。
第四優先級:常規字符串匹配類型。按前綴匹配。

下面示例一下四種地址類型:

location = / {
    # 僅僅匹配請求 /
    [ configuration A ]
}
location / {
    # 匹配全部以 / 開頭的請求。可是若是有更長的同類型的表達式,則選擇更長的表達式。若是有正則表達式能夠匹配,則優先匹配正則表達式。
    [ configuration B ]
}
location /documents/ {
    # 匹配全部以 /documents/ 開頭的請求。可是若是有更長的同類型的表達式,則選擇更長的表達式。
    #若是有正則表達式能夠匹配,則優先匹配正則表達式。
    [ configuration C ]
}
location ^~ /images/ {
    # 匹配全部以 /images/ 開頭的表達式,若是匹配成功,則中止匹配查找。因此,即使有符合的正則表達式location,也
    # 不會被使用
    [ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
    # 匹配全部以 gif jpg jpeg結尾的請求。可是 以 /images/開頭的請求,將使用 Configuration D
    [ configuration E ]
}

請求匹配實例:

/ -> configuration A
/index.html -> configuration B
/documents/document.html -> configuration C
/images/1.gif -> configuration D
/documents/1.jpg -> configuration E

應用舉例:隱藏內在的地址

server {
    # 用 xxoo_admin 來掩飾 admin
    location / {
        # 使用break拿一旦匹配成功則忽略後續location
        rewrite /xxoo_admin /admin break;
    }

    # 訪問真實地址直接報沒權限
    location /admin {
        return 403;
    }
}

6、重寫

Nginx的反向代理像一個URL函數,輸入是一個URL,輸出也是一個URL。運行過程多是這樣的:

用戶發起請求url0
url1=f(url0)
url2=f(url1)
...直到url再也不被重寫,被路由到合適的請求處理結點

語法

在配置文件的server塊中寫,如:

server {
    rewrite 規則 定向路徑 重寫類型;
}
  • 規則:能夠是字符串或者正則來表示想匹配的目標url
  • 定向路徑:表示匹配到規則後要定向的路徑,若是規則裏有正則,則可使用$index來表示正則裏的捕獲分組
  • 重寫類型:
  • last :瀏覽器地址欄URL地址不變,本條規則完成後,會對重寫後的URL進行從新匹配。
  • break:瀏覽器地址欄URL地址不變。本條規則匹配完成後,終止匹配,再也不匹配後面的規則,
  • redirect:返回302臨時重定向,瀏覽器地址會顯示跳轉後的URL地址
  • permanent:返回301永久重定向,瀏覽器地址欄會顯示跳轉後的URL地址

須要注意:

  • 重寫表達式只對相對路徑有效。若是想配對主機名,應該使用if語句。
  • rewrite只是會改寫路徑部分的東東,不會改動用戶的輸入參數,所以這裏的if規則裏面,你無需關心用戶在瀏覽器裏輸入的參數,rewrite後會自動添加的

下面舉例說明4種重寫類型

server {
    # 訪問 /last.html 的時候,頁面內容重寫到 /index.html 中
    rewrite /last.html /index.html last;

    # 訪問 /break.html 的時候,頁面內容重寫到 /index.html 中,並中止後續的匹配
    rewrite /break.html /index.html break;

    # 訪問 /redirect.html 的時候,頁面直接302定向到 /index.html中
    rewrite /redirect.html /index.html redirect;

    # 訪問 /permanent.html 的時候,頁面直接301定向到 /index.html中
    rewrite /permanent.html /index.html permanent;

    # 把 /html/*.html => /post/*.html ,301定向
    rewrite ^/html/(.+?).html$ /post/$1.html permanent;

    # 把 /search/key => /search.html?keyword=key
    rewrite ^/search\/([^\/]+?)(\/|$) /search.html?keyword=$1 permanent;
}

7、Nginx內置的全局變量

在/etc/nginx/fastcgi.conf中能夠看到所有定義。

$args :這個變量等於請求行中的參數,同$query_string
$content_length : 請求頭中的Content-length字段。
$content_type : 請求頭中的Content-Type字段。
$document_root : 當前請求在root指令中指定的值。
$host : 請求主機頭字段,不然爲服務器名稱。
$http_user_agent : 客戶端agent信息
$http_cookie : 客戶端cookie信息
$limit_rate : 這個變量能夠限制鏈接速率。
$request_method : 客戶端請求的動做,一般爲GET或POST。
$remote_addr : 客戶端的IP地址。
$remote_port : 客戶端的端口。
$remote_user : 已經通過Auth Basic Module驗證的用戶名。
$request_filename : 當前請求的文件路徑,由root或alias指令與URI請求生成。
$scheme : HTTP方法(如http,https)。
$server_protocol : 請求使用的協議,一般是HTTP/1.0或HTTP/1.1。
$server_addr : 服務器地址,在完成一次系統調用後能夠肯定這個值。
$server_name : 服務器名稱。
$server_port : 請求到達服務器的端口號。
$request_uri : 包含請求參數的原始URI,不包含主機名,如:」/foo/bar.php?arg=baz」。
$uri : 不帶請求參數的當前URI,$uri不包含主機名,如」/foo/bar.html」。
$document_uri : 與$uri相同。

如:

訪問連接是:http://localhost:88/test1/test2/test.php
網站路徑是:/var/www/html

$host:localhost
$server_port:88
$request_uri:http://localhost:88/test1/test2/test.php
$document_uri:/test1/test2/test.php
$document_root:/var/www/html
$request_filename:/var/www/html/test1/test2/test.php

8、使用if語句

if (表達式) {
}

表達式的寫法有不少:

  • 當表達式只是一個變量時,若是值爲空或任何以0開頭的字符串都會當作false
  • 直接比較變量和內容時,使用=或!=
  • ~正則表達式匹配,~*不區分大小寫的匹配,!~區分大小寫的不匹配

表達式中可使用shell經常使用運算符:

  • -f和!-f用來判斷是否存在文件
  • -d和!-d用來判斷是否存在目錄
  • -e和!-e用來判斷是否存在文件或目錄
  • -x和!-x用來判斷文件是否可執行

下面看幾個if語句的例子:
例子一:簡單的if語句

# 若是文件不存在則返回400
if (!-f $request_filename) {
    return 400;
}

# 若是host不是xuexb.com,則301到xuexb.com中
if ( $host != 'xuexb.com' ){
    rewrite ^/(.*)$ https://xuexb.com/$1 permanent;
}

# 若是請求類型不是POST則返回405
if ($request_method = POST) {
    return 405;
}

# 若是參數中有 a=1 則301到指定域名
if ($args ~ a=1) {
    rewrite ^ http://example.com/ permanent;
}

例子二:在重寫中使用if語句

# 訪問 /test.html 時
location = /test.html {
    # 默認值爲xiaowu
    set $name xiaowu;

    # 若是參數中有 name=xx 則使用該值
    if ($args ~* name=(\w+?)(&|$)) {
        set $name $1;
    }

    # 301
    rewrite ^ /$name.html permanent;
}

舉例說明運行結果:

/test.html => /xiaowu.html
/test.html?name=ok => /ok.html?name=ok

9、經常使用命令

service nginx configtest 用來檢測配置是否正確
service nginx reload 從新加載配置

使用sudo service nginx命令能夠查看可用參數.

10、root和alias

root

location /request_path/image/ {
    root /local_path/image/;
}

這樣配置的結果就是當客戶端請求 /request_path/image/cat.png 的時候,
Nginx把請求映射爲/local_path/image/request_path/image/cat.png

alias

location /request_path/image/ {
    alias /local_path/image/;
}

這時候,當客戶端請求 /request_path/image/cat.png 的時候,
Nginx把請求映射爲/local_path/image/cat.png

下面舉一個例子,當訪問myip/poem/authorImage/libai.jpg的時候會自動去文件夾/home/USER_NAME/authorImage/下去尋找libai.jpg。

location /poem/authorImage/ {
    alias /home/USER_NAME/authorImage/;
    autoindex on;
}

須要注意的是,必須保證authorImage這個文件夾權限足夠,不然Nginx沒有權力訪問這個文件夾。最簡單可是不夠安全的方式就是把/etc/nginx.conf文件開頭的user www-data改成user root,這樣把管理員權限賦予Nginx,Nginx就可以訪問任意文件了。這樣作的缺點就是,一旦Nginx被攻破,整個系統的文件資源可能都會受到威脅。

11、例子集合

一、訪問http://IP:端口/myf_test/in_ftp/ftp/space_1/111.jpg

實際訪問/var/ftp/in_ftp/ftp/space_1/111.jpg

location /myf_test/ {  
           root /;  
           rewrite ^/myf_test/(.*)$ /var/ftp/$1 break;  
        }

二、把www.ikscher.com/index.PHP?route=product/product&product_id=123 重定向到

www.ikscher.com/product/product&product_id=123

if ($request_uri ~* "(.*)index\.php\?route=(.*)"){  
    set $host_ $1;  
    set $last_ $2;  
    rewrite (.*)  $host_$last_? permanent; #這裏的.*表明的是url的原先地址,即要轉向的url地址。  
}

注意:

  • 這段規則直接下到server裏面,if後面必須有空格,不然報語法錯誤。
    正則表達式的 點和問號都須要\斜槓轉義。
  • nginx的問號處理,假如如今我要重定向到www.ikscher.com/?route=product/product&product_id=123,nginx在進行rewrite的正則表達式中只會將url中?前面的部分拿出來匹配,匹配完成後,?後面的內容將自動追加到url中(包含?),若是不讓後面的內容追加上去,請在最後加上?便可。若是想要?後面的內容時請使用$query_string
  • 在這裏提醒一點,調試的時候在rewrite的最後一個配置項中不要使用break last這些,使用redirect能夠看到轉換後的地址。綜合以上幾點,使用的配置項爲

    rewrite (.)index.php(.) $1$query_string? permanent;

三、多目錄轉成參數

要求: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; 
}

四、目錄對換

要求:/123456/xxxx -> /xxxx?id=123456
規則配置:rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;

五、特殊瀏覽器特殊處理

設定nginx在用戶使用ie的使用重定向到/nginx-ie目錄

規則以下:

if ($http_user_agent ~ MSIE) {
     rewrite ^(.*)$ /nginx-ie/$1 break; 
}

六、請求目錄自動加/

目錄自動加「/」 ,這個功能通常瀏覽器自動完成

if (-d $request_filename){ 
    rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent; 
}

七、禁止某些URL

禁止多個目錄 
location ~ ^/(cron|templates)/ { 
    deny all; break; 
} 
禁止以/data開頭的文件,能夠禁止/data/下多級目錄下.log.txt等請求
location ~ ^/data { 
    deny all; 
} 

禁止單個文件 
location ~ /data/sql/data.sql { 
    deny all; 
}

八、讓瀏覽器緩存靜態數據,避免頻繁請求靜態數據

給favicon.ico和robots.txt設置過時時間; 這裏爲favicon.ico爲99天,robots.txt爲7天並不記錄404錯誤日誌

location ~(favicon.ico) { 
    log_not_found off; 
    expires 99d; 
    break; 
} 
location ~(robots.txt) { 
    log_not_found off; 
    expires 7d; 
    break; 
}

設定某個文件的瀏覽器緩存過時時間;這裏爲600秒,並不記錄訪問日誌

location ^~ /html/scripts/loadhead_1.js { 
    access_log off; 
    expires 600; 
    break; 
}

Nginx還能夠自定義某一類型的文件的保質期時間,具體寫法看下文的代碼:

location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ {
    if (-f $request_filename) {
       expires    1h;
       break;
      }
}
//上段代碼就將js|css|jpg|jpeg|gif|png|swf這類文件的保質期設置爲一小時。

九、防盜鏈的設置

防盜鏈:若是你的網站是個下載網站,下載步驟應該是先通過你的主頁找到下載地址,才能下載,爲了防止某些網友直接訪問下載地址徹底不經過主頁下載,咱們就可使用防盜鏈的方式,具體代碼以下:

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 *.jjonline.cn *.jjonline.com.cn *.lanwei.org *.jjonline.org localhost  42.121.107.189; 
    if ($invalid_referer) { 
        rewrite ^/ http://img.jjonline.cn/forbid.gif; 
        return 417; 
        break; 
    } 
    access_log off; 
    break; 
}

說明:
這裏的return 417爲自定義的http狀態碼,默認爲403,方便經過nginx的log文件找出正確的盜鏈的請求地址
rewrite ^/ http://img.jjonline.cn/forbid.gif;顯示一張防盜鏈圖片
「access_log off;」不記錄訪問日誌,減輕壓力
「expires 3d」全部文件3天的瀏覽器緩存

十、只容許固定ip訪問網站,並加上密碼;這個對有權限認證的應用比較在行

location \ { 
    allow 22.27.164.25; #容許的ipd
    deny all; 
    auth_basic 「KEY」; #認證的一些設置
    auth_basic_user_file htpasswd; 
}

十一、文件和目錄不存在的時重定向

if (!-e $request_filename) { 
    #proxy_pass http://127.0.0.1; #這裏是跳轉到代理ip,這個代理ip上有一個監聽的web服務器
    rewrite ^/ http://www.jjonline.cn/none.html;  #跳轉到這個網頁去
    #return 404; #直接返回404碼,而後會尋找root指定的404.html文件
}

十二、域名跳轉

域名跳轉

server { 
    listen 80; 
    server_name jump.jjonline.cn ;#須要跳轉的多級域名
    index index.html index.htm index.php; #入口索引文件的名字
    root /var/www/public_html/; #這個站點的根目錄
    rewrite ^/ http://www.jjonline.cn/; 
    #rewrite到這個地址,功能表現:在瀏覽器上輸入jump.jjonline.cn並回車,不會有任何提示直接變成www.jjonline.cn
    access_log off; 
}

多域名轉向

server { 
    listen 80; 
    server_name www.jjonline.cn www.jjonline.org;
    index index.html index.htm index.php; 
    root /var/www/public_html/; 
    if ($host ~ 「jjonline\.org」) { 
        rewrite ^(.*) http://www.jjonline.cn$1 permanent; 
    } 
}

三級域名跳轉

if ($http_host ~* 「^(.*)\.i\.jjonline\.cn$」) { 
    rewrite ^(.*) http://demo.jjonline.cn$1; 
    break; 
}

1三、域名鏡像

server { 
    listen 80; 
    server_name mirror.jjonline.cn; 
    index index.html index.htm index.php; 
    root /var/www/public_html; 
    rewrite ^/(.*) http://www.jjonline.cn/$1 last; 
    access_log off; 
}

12、Nginx的其餘功能

  • 壓縮
    使用gzip壓縮的方式來傳遞HTML文件可以減小傳輸量。
  • 緩存
    對於經常使用的請求,能夠設置緩存時間。

最後、參考資料

java靜態代理和動態代理
Nginx location在配置中的優先級
nginx配置url重寫
nginx 重寫 rewrite 基礎及實例

相關文章
相關標籤/搜索