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