關於nginx多層uptstream轉發獲取客戶端真實IP的問題


因為公司有個需求需要獲取客戶端的真實IP,前端是haproxy,后面是nginx,本來這個需求不難完成,但是難就難在是https請求也就是ssl

由於個人水平有限,在網上爬了很多資料,剛開始的ha是通過tcp代理443端口的,但是無法轉發7層的X-Forwarded-For到后面的nginx,那么后面的ng肯定拿不到真實IP了

怎么辦呢,網上爬資料

第一在HA上做ssl中斷,中斷后https協議就變成http協議了這樣可以轉發到后面nginx上,后面nginx不需要用ssl,但是問題來了,弄好頁面出了點問題,並且暫時沒法解決,只好暫時作罷

這條路行不通怎么辦,那就用nginx做負載吧,誰讓自己Low呢,nginx總在7層了吧

說干就干,安裝nginx,配置下配置文件,啟動,走起

主配置文件如下:

 1 user  www www;
 2 worker_processes 20;
 3 
 4 error_log  /data/logs/nginx/error.log;
 5 pid        /var/run/nginx.pid;
 6 
 7 #Specifies the value for maximum file descriptors that can be opened by this process.
 8 worker_rlimit_nofile 51200;
 9 
10 events {
11     use epoll;
12     worker_connections 51200;
13 }
14 
15 http
16 {
17     include       mime.types;
18     #include       proxy.conf;
19     default_type  application/octet-stream;
20     
21     server_names_hash_bucket_size 128;
22     client_header_buffer_size 32k;
23     large_client_header_buffers 4 32k;
24     client_max_body_size    300m;
25     #client_max_body_size    32m;
26     
27     #limit_req_zone $baidu_spider zone=baidu_spider:10m rate=15r/m;
28     sendfile on;
29     tcp_nopush     on;
30     
31     keepalive_timeout 30;
32     
33     tcp_nodelay on;
34     #ssi on;
35     #ssi_silent_errors on;
36     #ssi_types text/shtml;
37     
38     fastcgi_connect_timeout 180;
39     fastcgi_send_timeout 180;
40     fastcgi_read_timeout 180;
41     fastcgi_buffer_size 128k;
42     fastcgi_buffers 8 128k;
43     fastcgi_busy_buffers_size 128k;
44     fastcgi_temp_file_write_size 128k;
45     proxy_headers_hash_max_size 51200;
46     proxy_headers_hash_bucket_size 6400; 47     gzip on;
48     gzip_min_length      2k;
49     gzip_buffers         4 16k;
50     gzip_http_version     1.0;
51     gzip_comp_level    6;
52     gzip_types           text/plain application/x-javascript text/css application/xml;
53     gzip_vary         on;
54         log_format  access     '$remote_addr,$proxy_add_x_forwarded_for,$http_x_forwarded_for,$remote_user,$time_local,$host,$request,$status,$http_referer,$HTTP_X_UP_CALLING_LINE_ID,$request_time,$http_user_agent  $upstream_addr  $upstream_response_time  $upstream_cache_status';    
55     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
56         #              '$status $body_bytes_sent "$http_referer" '
57         #              '"$http_x_forwarded_for" "$http_user_agent"';
58 
59     #upstream backend {
60     #    server 127.0.0.1:9000 weight=5  max_fails=3  fail_timeout=30s;
61     #}
62 
63     include conf.d/*;
64 
65 }

然后我們配置子配置文件:

 1 upstream ihouse443{
 2   server 10.0.30.37:443 max_fails=3 fail_timeout=60 weight=1;
 3   server 10.0.30.38:443 max_fails=3 fail_timeout=60 weight=1;
 4   server 10.0.30.39:443 max_fails=3 fail_timeout=60 weight=1;
 5 
 6 }
 7 
 8 
 9 
10 server {
11   listen 443;
12   server_name www.abc.com;
13   access_log /data/logs/nginx/abc_access.log access;
14   error_log  /data/logs/nginx/abc_error.log ;
15   ssl on;
16   ssl_certificate /data/ifengsite/htdocs/abc.sss.com.crt;
17   ssl_certificate_key /data/ifengsite/htdocs/abc.sss.com.key;
18 
19   ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDH:AES:HIGH:!aNULL:!MD5:!ADH:!DH;
20   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
21 
22   #location /stub_status {
23   #  stub_status;
24   #}
25 
26 
27   location / {
28     proxy_pass https://ihouse443;
29     proxy_redirect off;
30     proxy_set_header Host $host;
31     proxy_set_header X-Real-IP $remote_addr;
32     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
33     #proxy_set_header X-Forwarded-For $http_x_forwarded_for;
34     proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
35     proxy_max_temp_file_size 0;
36     proxy_connect_timeout 90;
37     proxy_send_timeout 90;
38     proxy_read_timeout 90;
39     proxy_buffer_size 4k;
40     proxy_buffers 4 32k;
41     proxy_busy_buffers_size 64k;
42     proxy_temp_file_write_size 64k;
43     #include        fastcgi_params;
44   }
45 }
46 
47 server {
48   listen 443;
49   server_name *.abc.def.com;
50   access_log /data/logs/nginx/ihouse_access1.log access;
51   error_log  /data/logs/nginx/ihouse_error.log ;
52   ssl on;
53   ssl_certificate /data/ifengsite/htdocs/_.sss.xxx.com.crt;
54   ssl_certificate_key /data/ifengsite/htdocs/_.sss.xxx.com.key;
55   ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDH:AES:HIGH:!aNULL:!MD5:!ADH:!DH;
56   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
57   location / {
58     proxy_pass https://ihouse443;
59     proxy_redirect off;
60     proxy_set_header Host $host;
61     proxy_set_header X-Real-IP $remote_addr;
62     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
63     #proxy_set_header X-Forwarded-For $http_x_forwarded_for;
64     proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
65     proxy_max_temp_file_size 0;
66     proxy_connect_timeout 90;
67     proxy_send_timeout 90;
68     proxy_read_timeout 90;
69     proxy_buffer_size 4k;
70     proxy_buffers 4 32k;
71     proxy_busy_buffers_size 64k;
72     proxy_temp_file_write_size 64k;
73     #include        fastcgi_params;
74   }
75 }

然后啟動nginx,去后面的ng上一看,哎怎么沒真實IP呢?都是內網IP

后來在網上找了點 資料,如下解釋,這是摘抄的

下面來分析請求頭到達Nginx負載均衡服務器的情況;在默認情況下,Nginx並不會對X-Forwarded-For頭做任何的處理,除非用戶使用proxy_set_header 參數設置:

  1. proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for; 

$proxy_add_x_forwarded_for變量包含客戶端請求頭中的"X-Forwarded-For",與$remote_addr用逗號分開,如果沒有"X-Forwarded-For" 請求頭,則$proxy_add_x_forwarded_for等於$remote_addr。$remote_addr變量的值是客戶端的IP。

當Nginx設置X-Forwarded-For於$proxy_add_x_forwarded_for后會有兩種情況發生:

1、如果從CDN過來的請求沒有設置X-Forwarded-For頭(通常這種事情不會發生),而到了我們這里Nginx設置將其設置為$proxy_add_x_forwarded_for的話,X-Forwarded-For的信息應該為CDN的IP,因為相對於Nginx負載均衡來說客戶端即為CDN,這樣的話,后端的web程序時死活也獲得不了真實用戶的IP的。

2、CDN設置了X-Forwarded-For,我們這里又設置了一次,且值為$proxy_add_x_forwarded_for的話,那么X-Forwarded-For的內容變成 ”客戶端IP,Nginx負載均衡服務器IP“如果是這種情況的話,那后端的程序通過X-Forwarded-For獲得客戶端IP,則取逗號分隔的第一項即可。

    如上兩點所說,如果我們知道了CDN設置了X-Forwarded-For信息,且只有客戶端真實的IP的話,那么我們的Nginx負載均衡服務器可以不必理會該頭,讓它默認即可。

    其實Nginx中還有一個$http_x_forwarded_for變量,這個變量中保存的內容就是請求中的X-Forwarded-For信息。如果后端獲得X-Forwarded-For信息的程序兼容性不好的話(沒有考慮到X-Forwarded-For含有多個IP的情況),最好就不要將X-Forwarded-For設置為 $proxy_add_x_forwarded_for。應該設置為$http_x_forwarded_for或者干脆不設置!

#########################################################################################################

找到了以上內容,然后就測試

首先上面配置文件藍色內容是后來加上去的,紅色內容是原本就有的

藍色的配置加上去后,紅色的注釋掉后,后端的nginx就可以獲取真實IP了,具體原理就是上面所說的但是我還是不太明白,后續還要好好研究下。

附上后端nginx的配置

 1 user  www www;
 2 worker_processes 20;
 3 
 4 error_log  /data/logs/nginx/error.log;
 5 pid        /var/run/nginx.pid;
 6 
 7 #Specifies the value for maximum file descriptors that can be opened by this process.
 8 worker_rlimit_nofile 51200;
 9 
10 events {
11     use epoll;
12     worker_connections 51200;
13 }
14 
15 http
16 {
17     include       mime.types;
18     #include       proxy.conf;
19     default_type  application/octet-stream;
20     
21     server_names_hash_bucket_size 128;
22     client_header_buffer_size 32k;
23     large_client_header_buffers 4 32k;
24     client_max_body_size    300m;
25     #client_max_body_size    32m;
26     
27     #limit_req_zone $baidu_spider zone=baidu_spider:10m rate=15r/m;
28     sendfile on;
29     tcp_nopush     on;
30     
31     keepalive_timeout 30;
32     
33     tcp_nodelay on;
34     #ssi on;
35     #ssi_silent_errors on;
36     #ssi_types text/shtml;
37     
38     fastcgi_connect_timeout 180;
39     fastcgi_send_timeout 180;
40     fastcgi_read_timeout 180;
41     fastcgi_buffer_size 128k;
42     fastcgi_buffers 8 128k;
43     fastcgi_busy_buffers_size 128k;
44     fastcgi_temp_file_write_size 128k;47     gzip on;
48     gzip_min_length      2k;
49     gzip_buffers         4 16k;
50     gzip_http_version     1.0;
51     gzip_comp_level    6;
52     gzip_types           text/plain application/x-javascript text/css application/xml;
53     gzip_vary         on;
54         log_format  access     '$remote_addr,$http_x_forwarded_for,$remote_user,$time_local,$host,$request,$status,$http_referer,$HTTP_X_UP_CALLING_LINE_ID,$request_time,$http_user_agent  $upstream_addr  $upstream_response_time  $upstream_cache_status';    
55     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
56         #              '$status $body_bytes_sent "$http_referer" '
57         #              '"$http_x_forwarded_for" "$http_user_agent"';
58 
59     #upstream backend {
60     #    server 127.0.0.1:9000 weight=5  max_fails=3  fail_timeout=30s;
61     #}
62 
63     include conf.d/*;
64 
65 }

子配置文件

upstream ihouse443{
  server 10.0.30.38:34785 max_fails=3 fail_timeout=60 weight=1;
  server 10.0.30.38:34787 max_fails=3 fail_timeout=60 weight=1;
  server 10.0.10.50:34404 max_fails=3 fail_timeout=60 weight=1;

}

server {
  listen 443;
  server_name www.abc.com;
  access_log /data/logs/nginx/sss_access.log access;
  error_log  /data/logs/nginx/ihouse_error.log ;
  ssl on;
  ssl_certificate /data/ifengsite/htdocs/ss.xx.com.crt;
  ssl_certificate_key /data/ifengsite/htdocs/ssxx.com.key;

  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDH:AES:HIGH:!aNULL:!MD5:!ADH:!DH;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  #location /stub_status {
  #  stub_status;
  #}

  location / {
    proxy_pass https://ihouse443;
    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;
    proxy_set_header X-Forwarded-For $http_x_forwarded_for;
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    proxy_max_temp_file_size 0;
    proxy_connect_timeout 90;
    proxy_send_timeout 90;
    proxy_read_timeout 90;
    proxy_buffer_size 4k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;
    #include        fastcgi_params;
  }
}

 后端nginx不需要配置

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM