因為公司有個需求需要獲取客戶端的真實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 參數設置:
- 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;