1. 程式人生 > >Nginx常見場景代理轉發配置

Nginx常見場景代理轉發配置

注意:本文出自 “阿飛”的部落格 ,如果要轉載本文章,請與作者聯絡!

在這裡分享的不是nginx的配置檔案說明,而是nginx常用的轉發代理配置(比如線上多域名配置,後端各種轉發代理配置以及較為複雜的代理轉發配置),另外還會對常用的轉發代理引數配置進行說明。

nginx配置檔案說明請參考:

1)http://www.cnblogs.com/hunttown/p/5759959.html

2)http://www.jianshu.com/p/1b44b5142155

一、代理轉發

nginx的代理轉發主要是在server部分進行配置。如果轉向到制定域名或子域名,則需要在godaddy、阿里雲等域名解析中預先配置(子)域名並指定IP。本文中主要描述萬用字元域名的配置,這樣更具有通用性。

server部分配置為:

server {
        listen       80;
        server_name  *.yourdomain.com;
......

如果是https則修改listen部分即可:

listen       443 ssl;

* https配置還需要單獨配置ssl部分的內容,證書不一樣,配置方式也有差異,這裡不做介紹。

一般情況下,我們會有如下常見的幾種需求

1)指向到公司官網或其他產品網(一級域名)
每個域名單獨配置一個server即可,如HTTPS的配置如下:

    server {
        listen          443 ssl;
        server_name     www.yourdomain.com; #修改為需要的一級域名即可

        access_log      logs/ssl.access.log;
        error_log       logs/ssl.error.log crit;

        include ssl_params;

        location / {
                index  index.html index.htm index.php;
                index  proxy_set_header Host $host;
                index  proxy_set_header X-Real-IP $remote_addr;
                index  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://server_cluster; #後端伺服器,具體配置upstream部分即可
        }

    }

2)指向到公司內部管理系統等等(二級域名)

同1)部分的配置,只需要修改server_name部分即可:

server_name	    二級域名.yourdomain.com; #修改為需要的二級域名即可

3)二級域名下多個服務轉發

比如:

http://dev.yourdomain.com/nexus

http://dev.yourdomain.com/zentao

http://dev.yourdomain.com/adminsys

...

而後端服務可能會部署在不同的server容器中,比如tomcat、php-fpm/fastcgi、第三方服務...

server部分需要先配置第2)點部分內容

,然後再配置該server下的location轉發,常見location配置場景如下:

a)轉發到後端Tomcat

      location /location名稱/ {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:8080/服務名/;
      }

tomcat的轉發是很簡單的了,這裡不需要多說。

b)轉發到php-fpm

將所有php頁面的請求轉給php-fpm處理:

      location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
      }


fastcgi_params配置:

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
#fastcgi_param  SERVER_SOFTWARE    nginx;
fastcgi_param  SERVER_SOFTWARE    nginx;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;


注意!

配置不具備通用性,需要根據自己伺服器及實際業務需要進行配置和調整。

這裡的配置僅提供參考。

d)轉發到第三方域名(第三方介面服務)

比如做支付時,內部系統需要通過代理轉發到銀聯支付介面:

location /unionpay/ {
         proxy_set_header Host gateway.銀聯.com;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_pass https://gateway.銀聯.com/;
}


這裡的proxy_set_header Host必須配置。

4)強制http轉https訪問

80埠部分server配置:

server {
        listen  80;
        server_name     api.yourdomain.com;
        location / {
                rewrite ^/(.*) https://api.yourdomain.com/$1 permanent ;
                break;
        }
        error_page 497 https://$host:$server_port$request_uri;
    }

當用戶通過HTTP 80訪問時,nginx將強制轉換為HTTPS 443訪問。
 

443埠部分server配置:

server {
        listen       443 ssl;
        server_name  api.yourdomain.com;

        access_log logs/ssl.api_access.log;
        error_log  logs/ssl.api_error.log crit;

        include ssl_params;

        location / {
                proxy_pass http://tomcat_servers/$2;
                proxy_set_header Host $host:443;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /v1.0/ {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://tomcat_servers/v1.0/;
            proxy_cookie_path /v1.0/ /;
            proxy_redirect off;
        }

}

5)字尾名定向

比如,有URL:www.abc.com/register/user.do,需要將URL定向為uuu.abc.com/register/user.do。則可以在WWW.ABC.COM節點中這樣配置:

location / {
        rewrite ^(/register)/user(.*)\..*$  https://uuu.abc.com/register/user.do break;

        index  index.html index.htm;
        proxy_set_header Host $host:443;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_pass http://localhost:****/;
}

6)在location中通過if-else分支,根據請求引數使用不同的proxy_pass進行轉發。如:

例如url為:http://mail.yourdomain.com/abc/1?n=web01&p=8088,這裡有n和p兩個引數。這裡的目的很簡單,就是想通過n這個引數來轉發到後端不同伺服器的Tomcat中,比如web01轉發到192.168.2.10,web02轉發到192.168.2.11....這種需求,我們不可能為後端每個伺服器配置一個location轉發。

因此,Nginx中可以對location進行if判斷,解決方案如下:

location /test/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        if ($arg_n ~* "web01") {
                  proxy_pass http://192.168.2.10:$arg_p;
                  break;
        }

        if ($arg_n ~* "web02") {
                  proxy_pass http://192.168.2.11:$arg_p;
                  break;
        }

        .......

}

其中,$arg_n表示url中的n引數,$arg_p表示url中的p引數。

最後,尤其要注意的是!proxy_pass 後的url不能有與請求的url後的路徑,如proxy_pass http://192.168.2.10:$arg_p;這裡不能配置為:proxy_pass http://192.168.2.10:$arg_p/abc/1...否則要報錯。必須只配置到埠,並且沒有斜槓/結尾。切記切記。

7)Nginx支援websocket的配置

只需要加上紅色字型部分配置即可:

location /drsws/ {
    proxy_set_header Host $host;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    ........

}

8)支援ttf|woff|woff2字型及圖片檔案防盜鏈的配置

location ~* \.(css|js|jpg|jpeg|png|gif|ico|ttf|woff|woff2|eot|svg)$ {
    root        /usr/share/nginx/html/phpems;
    expires     30d;
    valid_referers *.yourdomain.com www.yourdomain.com dev.yourdomain.com *.baidu.com *.google.com;
    if ($invalid_referer) {
        rewrite ^/ https://www.yourdomain.com;
        #return 404;
    }
}

二、引數說明

1)proxy_set_header    X-real-ip $remote_addr;

在web伺服器端獲得使用者的真實ip。

但是,實際上要獲得使用者的真實ip,不是隻有這一個方法,下面我們繼續看。

2)proxy_set_header           X-Forwarded-For $proxy_add_x_forwarded_for;

我們先看看這裡有個X-Forwarded-For變數,這是一個squid開發的,用於識別通過HTTP代理或負載平衡器原始IP一個連線到Web伺服器的客戶機地址的非rfc標準,如果有做X-Forwarded-For設定的話,每次經過proxy轉發都會有記錄,格式就是client1, proxy1, proxy2,以逗號隔開各個地址,由於他是非rfc標準,所以預設是沒有的,需要強制新增,在預設情況下經過proxy轉發的請求,在後端看來遠端地址都是proxy端的ip 。也就是說在預設情況下我們使用request.getAttribute("X-Forwarded-For")獲取不到使用者的ip,如果我們想要通過這個變數獲得使用者的ip,我們需要自己在nginx新增如下配置:

proxy_set_header            X-Forwarded-For$proxy_add_x_forwarded_for;

意思是增加一個$proxy_add_x_forwarded_for到X-Forwarded-For裡去,注意是增加,而不是覆蓋,當然由於預設的X-Forwarded-For值是空的,所以我們總感覺X-Forwarded-For的值就等於$proxy_add_x_forwarded_for的值,實際上當你搭建兩臺nginx在不同的ip上,並且都使用了這段配置,那你會發現在web伺服器端通過request.getAttribute("X-Forwarded-For")獲得的將會是客戶端ip和第一臺nginx的ip。

那麼$proxy_add_x_forwarded_for又是什麼?

$proxy_add_x_forwarded_for變數包含客戶端請求頭中的"X-Forwarded-For",與$remote_addr兩部分,他們之間用逗號分開。

舉個例子,有一個web應用,在它之前通過了兩個nginx轉發,www.linuxidc.com 即使用者訪問該web通過兩臺nginx。

在第一臺nginx中,使用

proxy_set_header            X-Forwarded-For$proxy_add_x_forwarded_for;

現在的$proxy_add_x_forwarded_for變數的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是使用者的ip,於是賦值以後,X-Forwarded-For變數的值就是使用者的真實的ip地址了。

到了第二臺nginx,使用

proxy_set_header            X-Forwarded-For$proxy_add_x_forwarded_for;

現在的$proxy_add_x_forwarded_for變數,X-Forwarded-For部分包含的是使用者的真實ip,$remote_addr部分的值是上一臺nginx的ip地址,於是通過這個賦值以後現在的X-Forwarded-For的值就變成了“使用者的真實ip,第一臺nginx的ip”,這樣就清楚了吧。

最後我們看到還有一個$http_x_forwarded_for變數,這個變數就是X-Forwarded-For,由於之前我們說了,預設的這個X-Forwarded-For是為空的,所以當我們直接使用proxy_set_header            X-Forwarded-For$http_x_forwarded_for時會發現,web伺服器端使用request.getAttribute("X-Forwarded-For")獲得的值是null。如果想要通過request.getAttribute("X-Forwarded-For")獲得使用者ip,就必須先使用proxy_set_header            X-Forwarded-For$proxy_add_x_forwarded_for;這樣就可以獲得使用者真實ip。

此部分內容來自:http://blog.csdn.net/bao19901210/article/details/52537279(感謝作者分享)

三、小結

1)通過本文,應該比較清楚的描述了一級、二級域名的配置;

2)通過各種場景,應該描述清楚了location各種情況的轉發配置;

3)引用其他文章,講解了部分引數的含義

4)各種複雜的情況,還需要根據具體的業務及需求進行配置,這裡的例子相對都比較簡單。