這個(gè)問(wèn)題非常經(jīng)典。您遇到的情況是典型的在HTTPS(SSL/TLS)終止代理場(chǎng)景下,后端服務(wù)器獲取不到真實(shí)客戶端IP的問(wèn)題。
問(wèn)題根源分析
您的配置在純HTTP代理時(shí)工作正常,但切換到HTTPS時(shí)失效,根本原因通常不在于這兩行配置本身,而在于整個(gè)數(shù)據(jù)流的路徑發(fā)生了變化。
HTTP 流量:
客戶端 (真實(shí)IP) -> Nginx (代理) -> 后端服務(wù)器
HTTPS 流量 (SSL Termination):
客戶端 (真實(shí)IP) -> Nginx (代理 & SSL終端) -> 后端服務(wù)器 (HTTP)
在這種情況下,Nginx扮演了SSL終止代理的角色??蛻舳伺cNginx之間是加密的HTTPS連接,而Nginx與后端服務(wù)器之間通常是明文的HTTP連接。
問(wèn)題在于:如果Nginx與后端服務(wù)器之間的連接是新的HTTP請(qǐng)求,它可能沒(méi)有完整地傳遞所有原始客戶端的連接信息。雖然您配置了頭部,但后端服務(wù)器接收到的連接對(duì)象(Socket)的來(lái)源IP變成了Nginx代理服務(wù)器的內(nèi)網(wǎng)IP,而不是讀取您設(shè)置的頭信息。
解決方案
要確保HTTPS模式下也能正確獲取真實(shí)IP,您需要執(zhí)行以下兩個(gè)關(guān)鍵步驟:
步驟一:確保Nginx正確設(shè)置代理頭(您已部分完成)
您的配置是正確的,但為了確保萬(wàn)無(wú)一失,通常還會(huì)設(shè)置Host
和X-Forwarded-Proto
頭,這對(duì)于一些后端應(yīng)用(如WordPress等)正確識(shí)別原始請(qǐng)求的協(xié)議至關(guān)重要。
server {
listen 443 ssl;
server_name your_domain.com;
# SSL證書(shū)配置
ssl_certificate /path/to/your/fullchain.pem;
ssl_certificate_key /path/to/your/privkey.pem;
location / {
# 核心配置:傳遞真實(shí)IP和協(xié)議信息
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-Proto $scheme; # 這個(gè)很重要!告訴后端原始請(qǐng)求是https
# 其他代理設(shè)置
proxy_pass http://your_backend_server; # 指向您的后端服務(wù)器地址
# 例如:proxy_pass http://localhost:8080;
# 例如:proxy_pass http://backend_server_ip:8080;
}
}
步驟二:配置后端服務(wù)器信任并使用這些頭信息
這是最關(guān)鍵且最常被忽略的一步!僅僅在Nginx中發(fā)送頭信息是不夠的,你必須告訴后端服務(wù)器“請(qǐng)不要再去看直接連接的客戶端的IP(這現(xiàn)在是Nginx的IP),而是去讀取 X-Forwarded-For
或 X-Real-IP
頭中的值”。
后端服務(wù)器的配置取決于您運(yùn)行的是什么軟件:
1. 如果后端是另一個(gè)Nginx(例如用于處理PHP-FPM)
您需要修改后端的Nginx配置(通常是nginx.conf
或/etc/nginx/nginx.conf
),在其 http
塊中,設(shè)置 set_real_ip_from
和 real_ip_header
指令。
http {
# 告訴Nginx,來(lái)自我們代理服務(wù)器(192.168.1.10)的請(qǐng)求是可信的
# 將 192.168.1.10 替換為您的前端Nginx代理服務(wù)器的內(nèi)網(wǎng)IP
# 如果有多級(jí)代理,可以多次設(shè)置 set_real_ip_from
set_real_ip_from 192.168.1.10;
set_real_ip_from 127.0.0.1; # 如果代理和后端在同一臺(tái)機(jī)器上
# 告訴Nginx從哪個(gè)頭信息中提取真實(shí)IP
real_ip_header X-Forwarded-For; # 或者 X-Real-IP
# 真實(shí)IP將被覆蓋,$remote_addr 變量現(xiàn)在保存的是客戶端的真實(shí)IP
# 這樣訪問(wèn)日志和應(yīng)用程序獲取到的就是真實(shí)IP了
... 其他配置 ...
}
配置完成后,重啟后端的Nginx服務(wù)。
2. 如果后端是Apache
啟用mod_remoteip
模塊。修改Apache配置文件(例如httpd.conf
或/etc/apache2/apache2.conf
)。
LoadModule remoteip_module modules/mod_remoteip.so
# 指定可信的代理服務(wù)器IP(即前端Nginx的IP)
RemoteIPTrustedProxy 192.168.1.10
RemoteIPTrustedProxy 127.0.0.1
# 告訴Apache用 X-Forwarded-For 頭中的值替換直接連接IP
RemoteIPHeader X-Forwarded-For
配置完成后,重啟Apache服務(wù)。
3. 如果后端是應(yīng)用程序本身(如Node.js, Python Flask/Django, Java Spring等)
應(yīng)用程序代碼不能直接信任remote_addr
,而必須從HTTP頭中讀取客戶端IP。
const clientIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
from flask import request
client_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
重要安全提示:在應(yīng)用程序中處理這些頭時(shí),必須確保只信任來(lái)自已知可信代理(您的Nginx服務(wù)器)的請(qǐng)求,否則用戶可能偽造X-Forwarded-For
頭來(lái)欺騙系統(tǒng)。許多Web框架有內(nèi)置的機(jī)制來(lái)處理可信代理(例如Flask的 ProxyFix
中間件)。
4. 如果后端是IIS的asp程序
代碼如下:
'函數(shù):驗(yàn)證IP格式,是返回1,否則返回0
Function CheckIpResult(paR_strIp)
CheckIpResult=0
if paR_strIp &"CS"="CS" then Exit Function
tmpIPArray=Split(paR_strIp, ".")
if Not isArray(tmpIPArray) then Exit Function
if ubound(tmpIPArray)-3<>0 then Exit Function
For tmpLoop=0 To ubound(tmpIPArray)
If tmpIPArray(tmpLoop) &"CS"="CS" Then Exit Function
If Not isNumeric(tmpIPArray(tmpLoop)) Then Exit Function
If Cint(tmpIPArray(tmpLoop))>255 Or Cint(tmpIPArray(tmpLoop))<0 Then Exit Function
Next
CheckIpResult=1
End Function
Function getIP()
strIPOrig=Request.ServerVariables("HTTP_X_FORWARDED_FOR")
If strIPOrig="" OR InStr(strIPOrig,"unknown")>0 Then
strIPAddr=Request.ServerVariables("REMOTE_ADDR")
ElseIf InStr(strIPOrig,",") > 0 Then
strIPAddr=Mid(strIPOrig,1,InStr(strIPOrig,",")-1)
ElseIf InStr(strIPOrig,";") > 0 Then
strIPAddr=Mid(strIPOrig,1,InStr(strIPOrig,";")-1)
Else
strIPAddr=strIPOrig
End If
getIP=Trim(Mid(strIPAddr,1,30))
if getIP &"CS"="::1CS" then getIP="127.0.0.1" 'localhost's ip
if getIP &"CS"<>"127.0.0.1CS" then
if CheckIpResult(getIP)=0 then
response.write ("<p align=""center""color:#FFFFFF;"">當(dāng)前賬號(hào)IP(“"& getIP &"”)疑似非法攻擊,已被系統(tǒng)攔截,如需繼續(xù)訪問(wèn),請(qǐng)聯(lián)系管理員。</p>")
Response.end
end if
end if
End Function
login_ip=getIP()
總結(jié)
確認(rèn)Nginx代理配置:確保包含了X-Forwarded-Proto $scheme
并正確proxy_pass
。
配置后端服務(wù):這是解決HTTPS下問(wèn)題的關(guān)鍵。根據(jù)您的后端類型(Nginx、Apache或應(yīng)用代碼),進(jìn)行相應(yīng)的配置,讓其信任并使用前端Nginx發(fā)來(lái)的X-Forwarded-For
或X-Real-IP
頭信息。
完成這兩步后,無(wú)論是HTTP還是HTTPS流量,您的后端服務(wù)都應(yīng)該能正確獲取到客戶端的真實(shí)IP地址了。
該文章在 2025/9/19 10:27:25 編輯過(guò)