首頁  >  文章  >  後端開發  >  如何在兩層伺服器的第二層Nginx上取得用戶IP

如何在兩層伺服器的第二層Nginx上取得用戶IP

WBOY
WBOY原創
2016-08-08 09:31:041346瀏覽

如何在兩層伺服器的第二層Nginx上取得使用者IP

一.之前在做nginx的伺服器設定的時候遇到了一個問題,在之前伺服器有用到一個限制客戶端最大並發連線的功能,而且這個功能的實作是依靠在伺服器中做

$remote-addr

這樣的設定來達到的。但在增加了前端一層(負載、CDN、防火牆、安全服務)伺服器之後,拿到的客戶端IP就都變成了前端伺服器的IP,但並非真是真是的用戶IP位址。

二.這樣的問題下,我又重新看了幾次nginx官網的介紹,也發現其中另外一個特別重要的變數

$proxy_add_x_forwarded_for

這個變數是客戶端存取請求中的X-forwarded-for 欄位的值,如果請求中不包含這個字段,則自動用這個變數會等價於remote-addr這個變數。這允許我們獲取HTTP請求中通常情況下前端伺服器保存的客戶真實IP位址的字段,通常就是我們說的X_FORWARDED_FOR字段,然後透過這樣的方法,我們就可以實現各種各樣的功能了。

三.下面我來實際為大家做一個簡單示範。諸多不足,歡迎指正。

首先我們先搭建好Nginx的環境,這裡我們使用1.7 系列的最新版本1.7.9為例,(關於版本的問題請參考FAQ 1)

下載、WGET所需網址http://nginx.org/ download/nginx-1.7.9.tar.gz

1.      下載Nginx

[lugt@localhostmysql]$ wget http://nginx.org/download/nginx-1.7.9.g

[lugt@localhostmysql]$ tar zxvf nginx-1.7.9.tar.gz

3.      直接編譯(需考慮是否需要openssl等外掛程式的支援)

[mydft點🕎 9

[lugt@localhost nginx-1.7.9]$ ./configure

[lugt@localhost nginx-1.7.9]$ make

[lugt@localhost nginx-1.7.9]$ su localhostnginx-1.7.9]$ make install

4.      接著接下來修改nginx.conf設定檔

[lugt@localhost nginx-1.7.9]$ su

[lugt@localhost nginx-1.7.9]$ suhost

/usr/local/nginx

[lugt@localhostnginx]$ vi conf/nginx.conf

然後在nginx.conf 中找到這裡,加入來設定負載均衡,模仿CDN

upstream dnsnginx1 {
        server[*.*.*.*/yourhostname]:8080 weight=10000; #填IP、域名
}
server {
        listen       80;
        server_name 
#access_log  logs/host.access.log  main
        location /{
           proxy_pass          http://dnsnginx1;
            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_set_header    HTTP_X_FORWARDED_FOR $remote_addr;
            proxy_redirect      default;
}
}

在設定一個虛擬伺服器在8080端口,


limit_conn_zone $proxy_add_x_forwarded_for zone=addr:10m;  # 并发设置 空间10M
server {
        listen       8080;
        server_name  [*.*.*.*/yourhostname]:8080 weight=10000; #填IP、域名
        limit_conn addr 1; #限制客户端最大并发连接数为 1
            location / {
            root   html;
            index  index.html index.htm;
        }
}
保存。接著測試設定檔語法
    [lugt@localhostnginx]$  ./sbin/nginx –t

啟動伺服器

    [lugt@localhostnginx]$

  使用ab 工具查看效果。

 [lugt@localhost nginx]$ ab –c 10 –n 100 –v 4 http://127.0.0.1/ | grep HTTP/1.1

這行的意思:透過AB測試工具存取位址,並發連線數為30,總測試300次,顯示HTTP返回頭資訊

透過ab 工具可以測出無論同時發送多少連接,最後成功返回200的只有之前限制nginx的最大並發連接數,所以可以證明對於IP的限制功能已經可以使用了。參考資料請見FAQ2

FAQ 1 版本問題

如果目前正在使用的Nginx版本沒有達到1.7.1版本,很可能nginx還不支援這個功能,

這時候就需要透過一段程式碼夾在limit_conn_handler函數中來從request取得x_forwarded_for 的值。

以1.6.1版本為例,程式碼增加如下。 src/http/modules/ngx_http_limit_conn.c  第184行

hash =ngx_crc32_short(key.data, key.len);                                                                              
If(“” == &ctx->key){                                                             
<span style="white-space:pre">	</span>If(NULL!= r->main->headers_in->x_forwarded_for->elts){                       
           key.data= *(char*)r->main->headers_in->x_forwarded_for->elts;             
         key.len = 4;                                                                                                                               
hash =ngx_crc32_short(key.data, key.len);                                                                     
<span style="white-space:pre">	</span>}                                                                                                                                                 }          

                                                                                                                                                    

FAQ 2 參考數據

這裡是一份參考數據, 獲取

[lugt@localhost~]$ ab -c 10 -n 100 -v 4 http://127.0.0.1/ | grep HTTP/1.1

HTTP/1.1503 Service Temporarily Unavailable


HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

503 Service Temporarily Unavailable

HTTP/1.1 200 OK

HTTP/ 1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1 200 OK

<… repeated 往下均为重复8次HTTP/503 与1次HTTP/200 交替出现>

English Version

How to retrievethe true ip of the client user if there are two layers of servers

Days before, wehave been faced such a difficulty which is we can’t use the variable $remote_addr for gathering the clients’ip address. This problem surfaces when we used a proxy server between the trueserver and client, which is actually a cdn. And that makes our functions oflimiting the maximum connections a client can make to a server at a time. Thissituation can also found if the load balance or any anti-spam service are inuse. So that’s why we can’t use remote_addr variable further.

After I did someresearch on the documentation and the code , I found out that this problem canbe solved by replacing the  

 $remote_addr 

 variable with the  
$proxy_add_x_forwarded_for
  variable. As this variable allows to retrievethe data from the column X_forwarded_for from the request, we can use thisvariable functioning in many ways.

And now I shall makean easy example to practically use this method.

First of all,build up a Nginx server.

Here, I will usethe 1.7.9 version (latest to the written time) for instance, therefore, thereexist some differences between older versions than 1.7.1 (see FAQ 1)

1.      Download A Nginx Copy:

[lugt@localhostmysql]$ wget http://nginx.org/download/nginx-1.7.9.tar.gz

2.      Decompress the file

[lugt@localhostmysql]$ tar zxvf nginx-1.7.9.tar.gz

3.      Compile The Code

[lugt@localhostmysql]$ cd nginx-1.7.9

[lugt@localhostnginx-1.7.9]$ ./configure

[lugt@localhostnginx-1.7.9]$ make

[lugt@localhostnginx-1.7.9]$ su

[lugt@localhostnginx-1.7.9]$ make install

4.      And edit the config file nginx.conf

[lugt@localhost nginx-1.7.9]$ su

[lugt@localhostnginx-1.7.9]$ cd /usr/local/nginx

[lugt@localhostnginx]$ vi conf/nginx.conf

There add suchdirectives to the server1 for emulate for an CDN server

upstream dnsnginx1 {
        server[*.*.*.*/yourhostname]:8080 weight=1000; #fill in your ip/hostname
}
server {
        listen       80;
        server_name  [hostname]   #fill your ip/ hostname here
#access_log  logs/host.access.log  main
        location /{
           proxy_pass          http://dnsnginx1;
            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_set_header    HTTP_X_FORWARDED_FOR $remote_addr;
            proxy_redirect      default;
}
}
 
 

After the end ofone server directive, and in the http directive, add so to function the sever2

limit_conn_zone $proxy_add_x_forwarded_for zone=addr:10m;  # sample setting
server {
        listen       8080;
        server_name  [*.*.*.*/hostname]:8080 weight=10000; #fill in ip/hostname here
        limit_conn addr 1; # Enablethe limitation of connection per ip at a time to 1.
 
            location / {
            root   html;
            index  index.html index.htm;
        }
}

And then you cansave , test the config file and run nginx

Test your configfile:

    [lugt@localhostnginx]$  ./sbin/nginx –t

Start the nginx server

    [lugt@localhostnginx]$  ./sbin/nginx

Now, the serverhas been set and you can run a test at instance.

/* This CommandMeans to run a tool to connect to server as 10conn/once and 10 conns in total*/

[lugt@localhost~]$ ab -c 10 -n 100 -v 4 http://127.0.0.1/ | grep HTTP/1.1

FAQ 1

There is actuallysome little malfunctions when using elder versions than 1.7.1 (Probably the newversion has it for a new feature).So to use this directive in earlier versions,some code need to be added.

As a Example inthe version 1.6.1

In filesrc/http/modules/ngx_http_limit_conn.c Line around 184

hash =ngx_crc32_short(key.data, key.len);                                                                             
If("" == &ctx->key){                                                             
    If(NULL!= r->main->headers_in->x_forwarded_for->elts){                       
           key.data= *(char*)r->main->headers_in->x_forwarded_for->elts;             
         key.len = 4;                                                                                                                               
hash =ngx_crc32_short(key.data, key.len);                                                                     
    }
}<span style="font-family: Arial, Helvetica, sans-serif;">           </span>

                                                                                                                                                    

FAQ 2 TestingResults

[lugt@localhost~]$ ab -c 10 -n 100 -v 4 http://127.0.0.1/ | grep HTTP/1.1

 

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1 200 OK

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP /1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1.1503 Service Temporarily Unavailable

HTTP/1。 time of HTTP/200 and so on>

以上就介紹如何在兩層伺服器的第二層Nginx上取得使用者IP,包含了方面的內容,希望對PHP教學有興趣的朋友有所幫助。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:php DOM 解析下一篇:php DOM 解析