nginx之配置proxy_set_header

wadeson發表於2017-07-18

win10客戶端請求web服務,win10的ip:192.168.223.1

nginx作為反向代理伺服器:192.168.223.136

nginx作為後端web伺服器:192.168.223.137

前提條件:配置nginx轉發到後端伺服器

server {
listen 8080;
server_name 192.168.223.136;
location / {
root "/www/html";
index index.html;
#auth_basic "required auth";
#auth_basic_user_file "/usr/local/nginx/users/.htpasswd";
error_page 404 /404.html;
}
location /images/ {
root "/www";
rewrite ^/images/bbs/(.*\.jpeg)$ /images/$1 break;
rewrite ^/images/www/(.*)$ http://192.168.223.136/$1 redirect;
}
location /basic_status {
stub_status;
}
location ^~/proxy_path/ {
root "/www/html";
index index.html;
proxy_pass http://192.168.223.137/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

location ^~/proxy_path/ {
root "/www/html";
index index.html;
proxy_pass http://192.168.223.137/;

將左側匹配到的/proxy_path/開頭的url全部轉發到後端伺服器192.168.223.137

現在一一測試各個proxy_set_header設定的變數的內容

1、proxy_set_header Host $host;

將136代理伺服器,137後端伺服器的log_format修改為如下:

log_format main '$remote_addr - $remote_user [$time_local] "$request" $http_host '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
proxy_set_header Host $host;這裡的Host變數的值對應的就是日誌中的$http_host 的值
檢視代理伺服器和後端伺服器的地址,可以發現$http_host對應的值為192.168.223.136:8080
192.168.223.1 - - [18/Jul/2017:10:21:25 +0800] "GET /favicon.ico HTTP/1.1" 192.168.223.136:8080 404 24 "http://192.168.223.136:8080/proxy_path/index.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
由於我將後端伺服器關閉了,所以出現502網管錯誤:

然後開啟137後端nginx,檢視日誌:

192.168.223.136 "192.168.223.1" - - [17/Jul/2017:17:06:44 +0800] "GET /index.html HTTP/1.0" "192.168.223.136" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" "192.168.223.1"

即驗證了proxy_set_header Host $host;  $host就是nginx代理伺服器,也就是win10客戶端請求的host

2、proxy_set_header Host $proxy_host;

將設定修改為上述proxy_host然後重啟ngxin代理伺服器136

[root@wadeson nginx]# sbin/nginx -s reload

重新請求代理頁面:http://192.168.223.136:8080/proxy_path/index.html,然後日誌如下:

首先檢視136代理伺服器的日誌:

192.168.223.1 - - [18/Jul/2017:10:30:12 +0800] "GET /proxy_path/index.html HTTP/1.1" 192.168.223.136:8080 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"

因為win10是136的客戶端,請求的host為192.168.223.136:8080,而nginx代理伺服器作為137後端伺服器的客戶端,將請求的報文首部重新封裝,將proxy_host封裝為請求的host

那麼137上面日誌請求的host就是其自身,proxy_host就是代理伺服器請求的host也就是後端伺服器137

192.168.223.136 "192.168.223.1" - - [18/Jul/2017:10:30:12 +0800] "GET /index.html HTTP/1.0" "192.168.223.137" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "192.168.223.1"

3、proxy_set_header Host $host:$proxy_port;

瞭解了上面的知識,那麼此處對應的host就知道代表的啥了,$host代表轉發伺服器,$proxy_port代表136轉發伺服器請求後端伺服器的埠,也就是80

於是觀察136、137的日誌進行驗證:

192.168.223.1 - - [18/Jul/2017:10:38:38 +0800] "GET /proxy_path/index.html HTTP/1.1" 192.168.223.136:8080 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"

192.168.223.136 "192.168.223.1" - - [18/Jul/2017:10:38:38 +0800] "GET /index.html HTTP/1.0" "192.168.223.136:80" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "192.168.223.1"

4、proxy_set_header X-Real-IP $remote_addr;

將$remote_addr的值放進變數X-Real-IP中,此變數名可變,$remote_addr的值為客戶端的ip

nginx轉發136伺服器日誌格式為:

log_format main '$remote_addr - $remote_user [$time_local] "$request" $http_host '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

nginx後端137伺服器的日誌格式:

log_format main '$remote_addr "$http_x_real_ip" - $remote_user [$time_local] "$request" "$http_host" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

兩者區別在於"$http_x_real_ip",新增了這個變數的值

重新請求需要訪問的地址http://192.168.223.136:8080/proxy_path/index.html

136的日誌:

192.168.223.1 - - [18/Jul/2017:10:45:07 +0800] "GET /proxy_path/index.html HTTP/1.1" 192.168.223.136:8080 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"

137的日誌:

192.168.223.136 "192.168.223.1" - - [18/Jul/2017:10:45:07 +0800] "GET /index.html HTTP/1.0" "192.168.223.136:80" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "192.168.223.1"

紅色標記的就是"$http_x_real_ip"的值,即可以看見使用者真實的ip,也就是客戶端的真實ip

5、proxy_set_header X-Forwarded-For $remote_addr;

理解了上面的含義那麼這個封裝報文的意思也就請求了

首先還是比對136和137的日誌格式:

136代理伺服器的日誌格式:

log_format main '$remote_addr - $remote_user [$time_local] "$request" $http_host '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

137後端伺服器的日誌格式:

log_format main '$remote_addr "$http_x_real_ip" - $remote_user [$time_local] "$request" "$http_host" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

重新請求需要訪問的地址http://192.168.223.136:8080/proxy_path/index.html

136的日誌顯示:

192.168.223.1 - - [18/Jul/2017:10:51:25 +0800] "GET /proxy_path/index.html HTTP/1.1" 192.168.223.136:8080 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-",最後一個欄位"$http_x_forwarded_for"對應的為空值

137的日誌顯示:

192.168.223.136 "192.168.223.1" - - [18/Jul/2017:10:51:25 +0800] "GET /index.html HTTP/1.0" "192.168.223.136:80" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "192.168.223.1"

可以看出137後端伺服器成功的顯示了真實客戶端的ip

6、proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

5、6兩者的區別:

在只有一個代理伺服器的轉發的情況下,兩者的效果貌似差不多,都可以真實的顯示出客戶端原始ip

但是區別在於:

 

$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”,這樣就清楚了吧。

 

相關文章