環(huán)境:nginx做反向代理,apache做后端服務(wù)器
nginx部分配置代碼:
upstream apache{
server 127.0.0.1:8080; # 后端真實(shí)服務(wù)器地址及端口
}
server {
listen 80;
server_name www.a.com;
root /usr/share/nginx/html;
location / {
proxy_pass http://apache;
proxy_set_header ClientIpGetFromNginx $remote_addr;
}
首先先去看一下nginx內置的變量:http://blog.csdn.net/iinel/article/details/4321383
變量 $remote_addr 代表客戶(hù)端ip地址
通常來(lái)說(shuō)nginx反向代理會(huì )添加一個(gè)請求頭
proxy_set_header X-Forwarded-For $remote_addr;
以此傳遞客戶(hù)端ip到后端服務(wù)器。
為了方便理解,我這里改一下頭的名稱(chēng):
proxy_set_headerClientIpGetFromNginx$remote_addr;
此時(shí)用瀏覽器訪(fǎng)問(wèn)一下,去查看后端服務(wù)器的訪(fǎng)問(wèn)日志如下
127.0.0.1 – - [01/Sep/2017:10:31:10 +0800] 后面內容省略···
可以看到客戶(hù)端ip為127.0.0.1也就是nginx的ip,(我nginx和后端服務(wù)器在一起)
這樣一來(lái)獲取的ip是錯誤的,那怎樣獲取正確ip呢?
先來(lái)看一下apache日志格式。
LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”' combined LogFormat “%h %l %u %t \”%r\” %>s %b” common LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\” %I %O” combinedio CustomLog “l(fā)ogs/access_log” combined
combined、common、combinedio是apache的3中日志格式,默認用 combined 方式
就需要修改
LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”' combined
為
LogFormat “%{ClientIpGetFromNginx}i%l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”' combined
這樣一來(lái),就等于從nginx的請求頭中取 ClientIpGetFromNginx 變量做為日志開(kāi)頭的ip,即客戶(hù)端ip
(上面i的意思就是從請求頭中取ClientIpGetFromNginx,i就代表請求頭)
可以參考apache日志格式:http://blog.sina.com.cn/s/blog_672c5a470100xj7z.html
保存配置,再訪(fǎng)問(wèn)一次,再查看apache的訪(fǎng)問(wèn)日志:
192.168.10.105 – - [01/Sep/2017:11:50:41 +0800] 后面內容省略···
可以看到ip是192.168.10.105,這才是客戶(hù)端的真實(shí)ip。
總結:
nginx獲取客戶(hù)端ip是用$remote_addr變量,這個(gè)ip是真實(shí)的。
后端服務(wù)器如果用$remote_addr獲取,那么這個(gè)ip其實(shí)是nginx的ip。
如果nginx設置了傳遞變量X-Forwarded-For $remote_addr,那么后端用X-Forwarded-For取真實(shí)ip
在沒(méi)有反向代理或CDN的情況下,是不能用X-Forwarded-For獲取客戶(hù)端ip的。因為瀏覽器是不會(huì )發(fā)送這個(gè)字段的,如果用程序模擬一個(gè)訪(fǎng)問(wèn),這個(gè)值是可以被偽造的。
可能會(huì )有個(gè)想法,如果設置ip傳遞為
proxy_set_header remote_addr $remote_addr;
是不是就可以不用修改日志格式或者修改代碼了?
結果是不行的,會(huì )出現一條這樣的日志:
127.0.0.1 – - [01/Sep/2017:13:53:42 +0800] 后面內容省略···
ip是127.0.0.1,是nginx的ip地址。表明$remote_addr是不能偽造的。
在上面的設置,通過(guò)php中一個(gè)數組 $_SERVER 可以獲取到:
$_SERVER 是一個(gè)包含了諸如頭信息(header)、路徑(path)、以及腳本位置(script locations)等等信息的數組。
通過(guò)以下php代碼可以看到:
<>
foreach ($_SERVER as $k => $v)
{
echo $k . “============” . $v . “
”;
}
保存為1.php,然后去訪(fǎng)問(wèn)這個(gè)頁(yè)面(當然必須有php運行環(huán)境)。結果如下
在阿里云官方網(wǎng)站文檔中 https://help.aliyun.com/knowledge_detail/40535.html 也可以看到關(guān)于ecs獲取客戶(hù)端ip的方法。是一樣的。
知識點(diǎn):
為啥叫 X-Forwarded-For 而不是別的呢?
這是因為當時(shí)的squid之類(lèi)的緩存軟件用的比較廣,軟件官方文檔里就用這個(gè)名作為標準了。時(shí)間一久,大家都遵守這個(gè)習慣了。
在標準請求頭中是沒(méi)有這個(gè)變量名的。
聯(lián)系客服