1. 程式人生 > 實用技巧 >Tomcat獲取Nginx代理後的真實客戶端IP地址

Tomcat獲取Nginx代理後的真實客戶端IP地址

在傳統的架構中,中小型企業採用Nginx+Tomcat這種架構時,客戶端請求將由Nginx轉發至後端Tomcat,當有需求在Tomcat日誌中也能看到客戶端真實IP地址的情況下,我們就需要使用到Nginx的 proxy_set_header指令來進行協助,而且還需要修改Tomcat對於 localhost_access 的日誌格式,要不然tomcat記錄的訪客IP全都是Nginx的, 這是因為所有的請求都是由Nginx前端伺服器轉發而來的。

Nginx配置日誌格式

Nginx需要先獲取到客戶端的真實IP地址後才能將客戶端真實IP地址傳送到後端Tomcat,所以也需要配置Nginx的日誌格式,在Nginx代理Tomcat的日誌格式中最為重要的配置為 $remote_addr

來獲取到真實客戶端IP地址,我這裡的Nginx日誌格式如下:

   log_format  main  '$remote_addr" "$remote_user" "[$time_local]" "$request"'
                     ' "$status" "$body_bytes_sent" "$http_referer"'
                     ' "$http_user_agent" "$http_x_forwarded_for" "$gzip_ratio"'
                     ' "$upstream_addr" "$request_time" "$upstream_response_time" "$http_host"';

有關更多Nginx日誌格式請見:https://k8sops.cn/nginx_log_module/

Nginx配置轉發IP頭

proxy_set_header指令可以配置到 http, server, location 三個配置段當中,我這裡配置到 location 欄位中。

location ^~ /crm-newm {
         proxy_pass  http://172.26.3.55:8086;
         proxy_http_version 1.1;
         proxy_set_header Host $host;
         proxy_set_header Port $proxy_port;
         proxy_set_header X-Real-IP $remote_addr;
      }

proxy_http_version指令解析:
proxy_http_version指令用於設定代理的HTTP協議版本。預設情況下,使用的是1.0版。建議將版本1.1用於keepalive連線和NTLM身份驗證

Syntax:	proxy_http_version 1.0 | 1.1;
Default:	proxy_http_version 1.0;
Context:	http, server, location

proxy_set_header
proxy_set_header指令用於重新定義header或將欄位附加到代理伺服器的請求頭中。該值可以包含文字、變數、或者文字變數的組合。

proxy_set_header Host $host;
Host為自定義文字,$host變數為Nginx中的內建變數,用於獲取當前主機名

proxy_set_header Port $proxy_port;
Port為自定義文字,$proxy_port變數也是為Nginx中的內建變數,用於獲取nginx代理的主機埠

proxy_set_header X-Real-IP $remote_addr;
X-Real-IP為自定義文字,$remote_addr變數也是Nginx中的內建變數,用於獲取真實客戶端IP地址,與Nginx中的$remote_addr一致

以上配置對於HTTP頭部內容,這些變數是不區分大小寫的

Tomcat日誌格式講解

在tomcat家目錄下的 conf/server.xml 檔案中,定位到 logs 欄位來修改tomcat日誌格式

vim conf/server.xml
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

prefix
prefix用於指定tomcat 訪問日誌的字首

suffix
suffix用於指定tomcat 訪問日誌的字尾

pattern
pattern用於指定tomcat 訪問日誌的輸出格式

訪問日誌支援的格式如下:

%a - 遠端IP地址
%A - 本地IP地址
%b - 傳送的位元組數,不包括HTTP頭,或“ - ”如果沒有傳送位元組
%B - 傳送的位元組數,不包括HTTP頭
%h - 遠端主機名
%H - 請求協議
%l - (小寫的L)- 遠端邏輯從identd的使用者名稱(總是返回' - ')
%m - 請求方法
%p - 本地埠
%q - 查詢字串(在前面加上一個“?”如果它存在,否則是一個空字串
%r - 第一行的要求
%s - 響應的HTTP狀態程式碼
%S - 使用者會話ID
%t - 日期和時間,在通用日誌格式
%u - 遠端使用者身份驗證
%U - 請求的URL路徑
%v - 本地伺服器名(訪問域名)
%D - 處理請求的時間(以毫秒為單位)
%T - 處理請求的時間(以秒為單位)
%I -(大寫的i) - 當前請求的執行緒名稱

另外,還可以將request請求的查詢引數、session會話變數值、cookie值或HTTP請求/響應頭內容的變數值等內容寫入到日誌檔案。
它仿照了apache的語法:

%{XXX}i  xxx代表傳入的頭(HTTP Request)
%{XXX}o  xxx代表傳出​​的響應頭(Http Resonse)
%{XXX}c  xxx代表特定的Cookie名
%{XXX}r  xxx代表ServletRequest屬性名
%{XXX}s  xxx代表HttpSession中的屬性名

配置Tomcat日誌記錄客戶真實IP

此配置需要修改Tomcat的日誌格式來支援記錄客戶端的真實IP地址,預設是不可以的。
在Nginx+Tomcat架構中使用日誌格式中的 %a 是獲取不到真實客戶端IP地址的,如果直接訪問Tomcat那麼 %a 可以獲取到真實客戶端IP地址。
如果要在Nginx+Tomcat架構中記錄真實客戶端IP地址需要在日誌格式中新增 %{X-Real-IP}i 配置來獲取,
%{X-Real-IP}i 是我們在Nginx location 配置段中指定的文字來獲取 $remote_addr 變數值的,在這裡將此值傳送給 Tomcat。
%{Port}i 也是我們在Nginx中定義的文字來獲取後端的轉發埠,這裡也將值轉發至Tomcat。

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%t %{X-Real-IP}i %h:%p %A:%{Port}i %m %s %S %u %H %v %U %b %T %I" />

以上日誌輸出格式預設以空格做為分割的,以上格式我已經做了排版,tomcat輸出訪問日誌如下:

1. %t 日期和時間 
2. %{X-Real-IP}i 客戶端真實IP地址
3. %h:%p 遠端IP(Nginx代理IP),遠端埠(客戶端訪問Nginx的埠)
4. %A:%{Port}i 本地IP地址及訪問的本地埠
5. %m HTTP請求方法
6. %s 請求狀態碼
7. %S 使用者會話ID
8. %u 遠端使用者身份驗證
9. %H HTTP請求協議
10. %v 訪問的域名
11. %U 訪問的URL
12. %b 傳送的位元組數,不包括HTTP頭,或“ - ”如果沒有傳送位元組
13. %T Tomcat處理請求的時間(以秒為單位)
14. %I (大寫的i)當前請求的執行緒名稱

※更多文章和資料|點選後方文字直達 ↓↓↓
100GPython自學資料包
阿里雲K8s實戰手冊
[阿里雲CDN排坑指南]CDN
ECS運維指南
DevOps實踐手冊
Hadoop大資料實戰手冊
Knative雲原生應用開發指南
OSS 運維實戰手冊
雲原生架構白皮書
Zabbix企業級分散式監控系統原始碼文件
雲原生基礎入門手冊
10G大廠面試題戳領