Nginx配置文件詳解
1、location 的匹配規則
location 的語法規則:
location [=|~|~*|^~|@] /uri/ {
...
}
- = :表示精確匹配后面的url
- ~ :表示正則匹配,但是區分大小寫(注意~ ^ 和^~的區別 ,~ ^ /xxx/ 意思是匹配以 /xxx/ 開頭的資源)
- ~* :正則匹配,不區分大小寫
- ^~ :表示普通字符匹配,如果該選項匹配,只匹配該選項,不匹配別的選項,一般用來匹配目錄
- @ :"@" 定義一個命名的 location,使用在內部定向時,例如 error_page
當有多條 location 規則時,nginx 有一套比較復雜的規則,優先級如下:
- 精確匹配 =
- ^~ 前綴匹配 (立刻停止后續的正則搜索)
- 按文件中順序的正則匹配 ~或~*
- 匹配不帶任何修飾的前綴匹配。
這個規則大體的思路是:先精確匹配,沒有則查找帶有 ^~的前綴匹配,沒有則進行正則匹配,最后才返回前綴匹配的結果(如果有的話)。
示例:
location = / { #規則A } location = /login { #規則B } location ^~ /static/ { #規則C } location ~ \.(gif|jpg|png|js|css)$ { #規則D } location ~* \.png$ { #規則E } location / { #規則F }
效果:
訪問根目錄 /, 比如 http://localhost/ 將匹配規則 A 訪問 http://localhost/login 將匹配規則 B,http://localhost/register 則匹配規則 F 訪問 http://localhost/static/a.html 將匹配規則 C 訪問 http://localhost/a.gif, http://localhost/b.jpg 將匹配規則 D和規則 E,但是規則 D 順序優先,規則 E不起作用,而 http://localhost/static/c.png則優先匹配到規則 C 訪問 http://localhost/a.PNG 則匹配規則 E,而不會匹配規則 D,因為規則 E 不區分大小寫 訪問 http://localhost/category/id/1111 則最終匹配到規則 F,因為以上規則都不匹配。這個時候一般可以配置 nginx 轉發請求給后端應用服務器,比如 FastCGI(PHP),tomcat(jsp),nginx 作為反向代理服務器存在
1.1、實際使用示例
在實際使用中,一般會至少配置三個匹配規則,如下:
# 直接匹配網站根,通過域名訪問網站首頁比較頻繁,使用這個會加速處理,官網如是說。 # 這里匹配我們的靜態首頁,也可以轉發給后端應用服務器 # 第一個必選規則 location = / { root /usr/appname; index index.html; #proxy_pass http://tomcat:8080/index } # 第二個必選規則是處理靜態文件請求,這是 nginx 作為 http 服務器的強項 # 有兩種配置模式,目錄匹配或后綴匹配,任選其一或搭配使用 location ~* \.(html|gif|jpg|jpeg|png|css|js|ico)$ { root /usr/appname; expires 1m; } location ^~ /static/ { root /webroot/static/; } # 第三個規則就是通用規則,用來轉發動態請求到后端應用服務器 # 非靜態文件請求就默認是動態請求,自己根據實際把握 location / { proxy_pass http://tomcat:8080/ }
一個推薦可供參考的配置文件:
upstream myserver { hash $http_x_forwarded_for; #hash $remote_addr; #sticky; #server 192.168.118.128:9080; server 192.168.118.129:9080; check_interval=3000 rise=2 fall=5 timeout=1000 type=http; check_http_send "GET / HTTP/1.1\r\nConnection:keep-alive\r\n\r\n"; check_http_expect_alive http_2xx http_3xx http_4xx; keepalive 100; } server { listen 8090; sever_name localhost; if($request_method !~ ^(GET|POST)) { return 444; } location =/ { root /root/myweb; index login/index.html; } location ~* \.(html|gif|jpg|jpeg|css|js|png|ico|eot|ttf|woff|svg)$ { root /root/myweb; expires 1m; } location / { proxy_pass http://myserver; real_ip_header X-http_x_forwarded_for; proxy_set_header Connection ""; proxy_set_header X-Real-IP $remote_addr; } }
1.2、精準匹配出現的問題
當配置的 location 的 URI 是目錄而不是資源文件時,并且命中該 location 最后實際會訪問資源文件,此時 Nginx 會再次接收到一個獲取資源文件的請求,Nginx 會再次根據資源文件的請求的路徑來匹配 location 并作出相應。
比如:
server { listen 80; server_name localhost; location = /abc/ { root /usr/webProjects/webFirst; index abc.html; } }
假設 Nginx 服務器上的 ip 為 192.168.118.128,我們通過瀏覽器請求 http://192.168.118.128/abc/,此時首先會命中 “location = /abc/” 規則,但你會發現瀏覽器可能會報 404,查看 Nginx 日志可以看到實際上并沒有訪問到 /usr/webProjects/webFirst/abc/abc.html 資源,而實際上是訪問了 "/usr/local/nginx/html/abc/abc.html" 下的資源。報錯日志如下:

這是因為上面的配置中當命中 /abc/ 路徑時,最后會訪問到 abc.html ,Nginx 會再次接收到一個訪問 /abc/abc.html 的請求,此時會再次根據 /abc/abc.html 來進行匹配。但是上面我們并沒有配置該路徑,所以最后會匹配到一個默認配置,即路徑是 /,root 是 Nginx 安裝目錄下的 /usr/local/nginx/html 目錄,所以最后訪問了 "/usr/local/nginx/html/abc/abc.html" 下的資源而導致報錯。
所以我們最好要加上一個匹配 /abc/abc.html 的配置,以便最后能訪問到我們希望訪問的資源:
server { listen 80; server_name localhost; location = /abc/ { root /usr/webProjects/webFirst; index abc.html; } location = /abc/abc.html { #上面的配置最后會命中到這里 alias /usr/webProjects/webFirst/user/user.html; } location = /abc/index.html { #當上面的location=/abc/沒有配置index時,最后會匹配到這里 alias /usr/webProjects/webFirst/user/user.html; } location ~* \.(html|gif|jpg|jpeg|png|css|js|ico)$ { #這里取代Nginx中的默認配置,即location路徑為 /,root 為Nginx安裝目錄下的html文件夾 root /usr/webProjects/web01; expires 1m; } }
1.3、正則匹配
Nginx 常見正則符合:
^:匹配字符串的開始位置$:匹配字符串的結束位置.*: .匹配任意字符,*匹配數量0到正無窮\. 斜杠用來轉義,\. 表示匹配點符號 "."(值1|值2|值3|值4):表示或匹配。例:(jpg|gif|png|bmp)匹配jpg或gif或png或bmp
2、root(服務器資源路徑)
Nginx 中的 root 可以在 location 或者直接在 server 中配置,root 指定的是資源存放在服務器中的路徑。root 既可以是絕對路徑,也可以是相對路徑,以 / 開頭即為絕對路徑。比如 location 中的 root 指定的是這個 location 規則所匹配的資源所存放的資源路徑。
相對路徑使用示例:
server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } }
上面 location 中 root 所指向的 html 就是一個相對路徑,相對的是當前這個配置文件的路徑。假設此配置文件的位置是 /etc/nginx/conf.d,那么這個 html 的絕對路徑就是 /etc/nginx/conf.d/html/。因此為避免出現不必要的麻煩,在配置 root 路徑的過程中最好用絕對路徑。
絕對路徑使用示例:
server { listen 80; server_name localhost; location / { root /usr/local/nginx/html; index index.html index.htm; } location /webTestProject/ { root /usr/myTestData/; index index.html index.htm; } }
請注意,上面當我們訪問 http://ip/webTestProject 時,實際上是訪問了服務器中的 /usr/myTestData/webTestProject 路徑。也就是說,當配置 root 時,最后訪問到的資源路徑會加上 location 中匹配到的 url。
Nginx中, 如果瀏覽器訪問的 URI 最后帶斜杠,比如:http://localhost/product/ ,則默認查找 product下的index頁面,存在就返回;不存在且未開啟自動索引目錄選項(指令是:autoindex on),則報403錯。如果瀏覽器訪問的 URI 最后不帶斜杠,比如:http://localhost/product,則會查找 product 文件,存在就返回。否則會自動將 uri 補全為 http://localhost/product/ ,瀏覽器自動發生 301 重定向跳轉。
2.1、server中的root和location的root的區別
如果我們同時在 server 和 location 中都設置了 root 路徑,例如:
server { listen 80; server_name localhost; root /usr/local/nginx2/html; location / { root /usr/local/nginx/html; index index.html index.htm; } }
當我們訪問服務器命中了 location 的配置時,nginx 的 location 會優先匹配到此代碼塊,會指向 location 中所配置的 root , server 中的 root 不會生效。當 nginx 找不到匹配到的 location 或者 location 中沒有配置 root 時,此時才會使用 server 中的 root 配置。
3、alias
如下:
3.1、root 和 alias 的區別
root 和 alias 的區別在于 nginx 如何解釋 location 后面的 uri,這會使兩者分別以不同的方式將請求映射到服務器文件上。
- root 的處理結果是:root路徑 + location路徑
- alias 的處理結果是:使用 alias 路徑替換 location 路徑
alias是一個目錄別名的定義,root則是最上層目錄的定義。還有一個重要的區別是 alias 后面必須要用 “/” 結束,否則會找不到文件的,而 root 則可有可無。
當我們使用 root 指定資源的路徑時,root 會將 location 后代的路徑完整保留,映射進文件路徑中。而 alias 會先過濾掉 location 后面的路徑,然后再將 alias 路徑 + 訪問資源路徑,就是最后所訪問的資源路徑。
比如:
# root 配置如下。如果此時一個請求的URI是 /t/a.html 時,web服務器將會返回服務器上的/www/root/html/t/a.html的文件。 location ^~ /t/ { root /www/root/html/; } # alias 配置如下。如果此時一個請求的URI是/t/a.html時,web服務器將會返回服務器上的/www/root/html/new_t/a.html的文件。 # 注意這里是new_t,因為alias會把location后面配置的路徑丟棄掉,把當前匹配到的目錄指向到指定的目錄。 location ^~ /t/ { alias /www/root/html/new_t/; }
使用alias時,目錄名后面必須要加 "/"。alias只能位于location塊中,root可以不放在 location 中。
alias 在使用正則匹配時,必須捕捉要匹配的內容并在指定的內容處使用。比如:
location ~ /mytest/(.*) { alias /usr/local/nginx/html/$1; }
3、index(默認頁面)
Nginx 可以在 location 中配置 index,index 配置的是網站初始頁,也就是默認頁面。該指令擁有默認值,index index.html ,即如果沒有給出index,默認初始頁為index.html
比如配置如下:
server { listen 80; server_name localhost; location /webTestProject/ { root /usr/myTestData/; index index.html index.htm; } }
我們可以直接訪問 http://ip//webTestProject/,會默認命中服務器中的 /usr/myTestData/webTestProject/index.html 資源。
4、proxy_pass
語法規則:
proxy_pass URL; #URL必須以http://或者https://開頭
proxy_pass 的作用域在 location。特點如下:
- 不影響瀏覽器地址欄的url
- 設置被代理server的協議和地址
- 協議可以為http或https
- 地址可以為域名或IP
4.1、proxy_pass 后面的路徑帶 / 和不帶的區別
在 proxy_pass 中的代理 url 后加上 /,代理轉發的 url 中就不會帶上 location 中匹配路徑(注意,只是不帶location中匹配的,即只是截取掉location中指定的,剩下的還是會帶到代理轉發的 url 中)。如果后面沒有/,代理轉發的 url 中就會帶上 location 中的匹配路徑。
示例如下:
# url 后帶 /(則不會加上location中的匹配路徑)
# 下面我們訪問 http://ip/proxy/home.html,最終會訪問到 http://myIp/home.html location /proxy/ { proxy_pass http://myIp/; } # url中不帶 /(則會加上location中的匹配路徑)
# 下面我們訪問 http://ip/proxy/home.html,最終會訪問到http://myIp/proxy/home.html。這里會將 location 中匹配的 proxy 也自動加到代理轉發的地址后面 location /proxy/ { proxy_pass http://myIp; }
代理轉發的地址后面如果還帶目錄,此時最后面有沒有 "/" 也不一樣。
詳情如下:
# 代理轉發的地址后面帶目錄和 / # 此時我們訪問 http://ip/proxy/index.html,最終會訪問到http://myIp/myFolder/index.html location /proxy/ { proxy_pass http://myIp/myFolder/; } # 代理轉發的地址后面帶目錄但沒有 / # 此時我們訪問 http://ip/proxy/index.html,最終會訪問到http://myIp/myFolderindex.html,比較奇怪 location /proxy/ { proxy_pass http://myIp/myFolder; }
可參考:http://www.rzrgm.cn/bigberg/p/7651197.html
4.2、proxy_cookie_path(修改cookie作用域)
語法結構:
proxy_cookie_path path replacement; #將cookie的作用域由path改為replacement
在使用代理轉發時,可能會發生 cookie 丟失的問題。
比如代理轉發配置如下:
location /aaa/ { proxy_pass http://myIp/; }
此時我們訪問 http://ip/aaa/project/sigin.do,Nginx 會轉發至 http://myIp/project/sigin.do,假設我們通過 sigin 接口來登錄,并且返回 cookie,在該 cookie 里面存放著登錄信息。登錄過后我們通過 http://ip/aaa/project/getUser.do 來繼續請求接口,此時你可能會發現后端拿不到 cookie 信息。
這是因為 sigin.do 接口返回的 cookie 的作用域會是 /project,而我們通過 http://ip/aaa/project/getUser.do 來發出接口瀏覽器是不會帶上 cookie,因為 cookie 的作用域不是 /aaa。此時我們應該修改配置如下:
location /aaa/ { proxy_pass http://myIp/; proxy_cookie_path /project /aaa; #將cookie的作用域由/project改為/aaa }
可參考:https://blog.csdn.net/isyoungboy/article/details/81382193
5、rewrite(重定向)
基本語法結構如下:
rewrite regex replacement [flag]; # regex:指定需要匹配的URI的正則表達式 replacement:將正則表達式匹配到的內容替換成replacement flag:標記,可不加
該指令就是通過正則表達式的使用來更改瀏覽器的 url 。也就是當匹配到指定的正則表達式后,會將 replacement 作為一個新的 URI,組成一個新的 URL 返回給客戶端,客戶端會自動進行重定向即自動請求返回的新的 URL。
示例如下:
# 此時不管我們訪問 http://ip/aaa/bbb/ 或者是 http://ip/ccc/aaa/bbb/ ,瀏覽器都會重定向到 http://ip/portal/。也就是會將replacement直接作為新的URI返回給客戶端 location ~ /aaa/bbb/ { rewrite /aaa/ /portal/ permanent; }
如果 replacement 是以 http://、https:// 或 $scheme 開頭的字符串,則處理流程會立即停止并將 replacement 作為新的 URL 返回并重定向客戶端。
rewrite 只能放在 server{},、location{}、if{} 塊中。默認情況下,rewrite 會將舊的 URL 的請求參數(也就是 ?符號之后的參數)也拼接到新的 URL 后面,如果我們不希望這么做,可以在 replacement 的最后面添加一個 ? 符號。當然,replacement 本身也是可以寫請求參數的。
# 此時我們訪問 http://ip/aaa/bbb/?name=wen ,瀏覽器會重定向到 http://ip/portal/?name=wen location ~ /aaa/bbb/ { rewrite /aaa/ /portal/ permanent; } # 如果不希望默認拼接舊的url的請求參數,則可以在replacement的最后面加一個?符號,此時重定向后的url就不會拼接舊的url的請求參數 # 下面我們訪問 http://ip/aaa/bbb/?name=wen ,瀏覽器會重定向到 http://ip/portal?myage=12 location ~ /aaa/bbb/ { rewrite /aaa/ /portal?myage=12? permanent; }
可以同時存在一個或多個 rewrite 指令,會按照在配置文件中出現的順序依次對 URL 進行匹配和處理。
當 rewrite 寫在 location 里時,它們的執行順序是:執行 server 塊的 rewrite 指令 --> 執行 location 匹配 --> 執行選定的 location 中的 rewrite 指令。如果在某步中 URI 被重寫了,則會重新循環執行1-3,直到找到真實存在的文件為之;循環超過10次,則會返回 500 Internal Server Error錯誤。所以當 rewrite 寫在 location 里時,最好要用 break 作為標記,否則可能會發生上述錯誤。
如果正則表達式有出現 } 或 ; 字符,則整個正則表達式應使用單引號 ' 或雙引號 " 括起來。
可參考:http://www.rzrgm.cn/tugenhua0707/p/10798762.html
5.1、flag(標記)
flag 有如下值:
- last:本條規則匹配完成后,不會再執行后面的 rewrite 指令,但會根據新的 URI 來匹配新的 location,然后可能再繼續執行該 location 下的 rewrite 指令。(不常用)
- break:本條規則匹配完成即終止,新的 URI 也不會再匹配后面的任何規則。(不常用)。
- redirect:返回 302 臨時重定向,瀏覽器地址會顯示跳轉后的新的URL地址。
- permanent:返回 301 永久重定向,瀏覽器地址會顯示跳轉后的新的URL地址。
- last 一般寫在 server 和 if 中,而 break 一般使用在 location 中
- last 不終止重寫后的url匹配,即新的url會再從server走一遍匹配流程,而break終止重寫后的匹配
- break 和 last 都能繼續執行 rewrite 指令的后面的指令?
因為 301 和 302 不能只簡單地返回狀態碼,還必須有重定向的URL,這就是 return 指令無法直接返回301、302的原因了。
6、return 指令
停止處理請求,直接返回狀態碼或重定向到其他 URL。執行 return 指令后,location 中后續指令將不會被執行。
# 語法 return code [text]; return code [URL]; return URL;
上下文為server、location、if。

7、server_name
server name 為虛擬服務器的識別標志,匹配到特定的server塊,轉發到對應的應用服務器中去,如:server_name 127.0.0.1 、 localhost 、域名[www.itcast.cn、www.itheima.com]。用戶通過不同的域名來訪問資源的話,Nginx 會獲取請求頭中的 HOST 字段,并根據 host 字段來匹配到特定的 server 塊,轉發到對應的應用服務器中去。
server_name 的匹配規則優先級如下:
- 精準匹配。(如 server_name www.test.com)
- 通配符在前的。(如server_name *.test.com)
- 通配符在后的。(如 www.test.*)
- 正則匹配。(如 ~ ^\.www\.test\.com$)
如果都不匹配,則:
- 優先選擇 listen 配置項后有 default 或 default_server 的 server 塊
- 找到匹配 listen 對應端口的第一個 server 塊
(注意,server_name _ (即一個下劃線)表示匹配所有域名,即只要通過該域名能訪問到該服務器,則都能匹配到該 server 塊; server_name "" 會匹配沒有傳遞Host頭部的情況。)
7.1、案例解析
配置文件如下:
server { listen 80; server_name www; location / { default_type text/html; content_by_lua ' ngx.say("<p>first</p>") '; } } server { listen 80; server_name www.zkh.com; location / { default_type text/html; content_by_lua ' ngx.say("<p>second</p>") '; } } server { listen 80; server_name www.zkh.*; location / { default_type text/html; content_by_lua ' ngx.say("<p>third</p>") '; } } server { listen 80; server_name ~\w+.com; location / { default_type text/html; content_by_lua ' ngx.say("<p>forth</p>") '; } } server { listen 80; server_name ~.*zkh.com; location / { default_type text/html; content_by_lua ' ngx.say("<p>fifth</p>") '; } }
修改hosts文件:
118.126.100.138 www.zkh.com 118.126.100.138 www.zkh.org 118.126.100.138 zkh.com 118.126.100.138 zkh.org
通過不同域名訪問 Nginx,返回結果如下:


參考:https://blog.csdn.net/Cheng_Kohui/article/details/82930464
8、內置變量
常見內置變量,參考:http://www.rzrgm.cn/sxy-blog/p/17463264.html
8.1、如何修改內置變量
許多內建變量都是只讀的,比如 $uri 和 $request_uri,對只讀變量進行賦值是應當絕對避免的,如果你嘗試改寫另外一些只讀的內建變量,比如 $arg_XXX 變量,在某些 Nginx 的版本中甚至可能導致進程崩潰。
也有一些內建變量是支持改寫的,其中一個例子是 $args. 這個變量在讀取時返回當前請求的 URL 參數串(即請求 URL 中問號后面的部分,如果有的話 ),而在賦值時可以直接修改參數串。我們來看一個例子:
location /test { set $orig_args $args; set $args "a=3&b=4"; echo "original args: $orig_args"; echo "args: $args"; }
這里我們把原始的 URL 參數串先保存在 $orig_args 變量中,然后通過改寫 $args 變量來修改當前的 URL 參數串,最后我們用 echo 指令分別輸出 $orig_args 和 $args 變量的值。
接下來我們這樣來測試這個 /test 接口:
$ curl 'http://localhost:8080/test' original args: args: a=3&b=4 $ curl 'http://localhost:8080/test?a=0&b=1&c=2' original args: a=0&b=1&c=2 args: a=3&b=4
在第一次測試中,我們沒有設置任何 URL 參數串,所以輸出 $orig_args 變量的值時便得到空。而在第一次和第二次測試中,無論我們是否提供 URL 參數串,參數串都會在 location /test 中被強行改寫成 a=3&b=4
8.2、內置變量 $remote_addr
內置變量 $remote_addr 指的是客戶端地址,也就是發起請求者的客戶端 ip 地址。
8.3、內置變量 $http_x_forwarded_for
內置變量 $http_x_forwarded_for 指的是請求頭中的 x-forwarded-for。默認情況下,瀏覽器發出請求的請求頭中是不含 x-forwarded-for 的,所以默認情況下在 Nginx 日志記錄的 $http_x_forwarded_for 是空的。當然我們也可以手動指定發送 x-forwarded-for 請求頭。
比如 Nginx 日志配置如下:
log_format main '客戶端IP:$remote_addr <===> X-Forwarded-For請求頭:$http_x_forwarded_for'; access_log logs/access.log main;
我們通過瀏覽器發出請求,如下,可以看到請求頭中是不含 x-forwarded-for 信息的。

此時 Nginx 日志輸出如下,可以看到能獲取到客戶端 ip,但是獲取到的 x-forwarded-for 信息是空的。

要想Nginx獲取到 x-forwarded-for 信息的,我們只需在發送請求時指定 x-forwarded-for(不區分大小寫) 請求頭即可。比如通過 postman 發送請求,如下:

此時 Nginx 日志輸出如下,可以看到能正常獲取到 x-forwarded-for 信息。

8.3、內置變量 $proxy_add_x_forwarded_for
$proxy_add_x_forwarded_for 變量 = 請求頭X-Forwarded-For,(如果有的話) $remote_addr變量
即表示請求頭 X-Forwarded-For 加上 $remote_addr變量的值。如果X-Forwarded-For字段沒出現在客戶端請求頭,$proxy_add_x_forwarded_for 等同于$remote_addr 變量。
$proxy_add_x_forwarded_for 變量的值如果包含多個地址,用逗號+空格分隔,格式如下:
clientIP, proxyIP1, proxyIP2 # 最左邊的clientIp一般是客戶端真實IP # 舉例 22.12.3.20, 192.168.118.129, 192.168.118.130
9、ngx_http_realip_module 模塊(real_ip_header)
9.1、詳解
realip 功能用途:可以利用 realip 模塊將用戶的真實 ip 賦值到 $remote_addr 變量中以此獲取到用戶的真實IP地址。realip 的set_real_ip_from、real_ip_header、real_ip_recursive 命令都可以用于 http、 server、location 區域配置。
realip 語法解釋:
- set_real_ip_from:設置信任服務器IP(一般設置為代理服務器的ip)。可以定義多行,可定義為ip,ip段,支持ipv4和ipv6。(注意,如果發送方的ip不在此信任名單中,realip模塊則不處理,$remote_addr就還會是發送發的地址。如果ip在信任中,則會根據下一個參數real_ip_header的設定,將指定的header頭字段的數據作為$remote_addr。)
- real_ip_header 請求頭:判定用戶真實IP存在某個請求頭中。比如 real_ip_header X-Forwarded-For,注意添加了此配置后,realip 模塊并不會自動往指定的請求頭如X-Forwarded-For中添加任何信息,所以說 realip 模塊實際上是需要跟其他配置配合使用的,如 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- real_ip_recursive:
- off:會將real_ip_header指定的HTTP頭中的最后一個IP作為真實IP,并賦值給 $remote_addr
- on:會將real_ip_header指定的HTTP頭中的最后一個不屬于信任服務器的IP內的 ip 作為真實IP,并賦值給 $remote_addr
使用 realip 模塊可以獲取用戶真實 ip,大致流程是先判定用戶真實 ip 會放在請求頭的哪個字段中(比如X-Forwarded-For),然后從該字段中剔除信任 ip(實際上可以理解為代理服務器的 ip),剩下的就是用戶真實 ip。
假設架構如下:

此時我們可以在 130 代理服務器中做以下配置:
... http { proxy_set_header Host $host; upstream rtpserver{ server 192.168.118.131; } log_format main 'remote_addr 值:$remote_addr <===> X-Forwarded-For請求頭:$http_x_forwarded_for <===> realip_remote_addr數據:$realip_remote_addr'; access_log logs/access.log main;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; server { listen 8090; server_name localhost;
...
location /portal/ { proxy_pass http://rtpserver/; } } }
然后在 131 服務器做以下配置,即指定上一級代理服務器中存放用戶真實 ip 的請求頭是什么,然后指定信任的 ip(實際上就是所有的代理服務器ip),131在接收到指定的請求頭數據后,會剔除掉信任的ip,剩下的就是用戶真實 ip。
... http { ... log_format main '131服務器 => remote_addr 值:$remote_addr <===> X-Forwarded-For請求頭:$http_x_forwarded_for <===> realip_remote_addr數據:$realip_remote_addr'; access_log logs/access.log main; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 下面三行為重點,添加后就可以獲取到客戶端真實IP set_real_ip_from 192.168.118.0/24; real_ip_header X-Forwarded-For; real_ip_recursive on; server { listen 80; server_name localhost; ... } }
我們在 postman 中發出請求,如下:

130 服務器日志輸出如下,

131服務器輸出如下,可以看到 131 服務器中 $remote_addr 變量的值已被自動賦值為用戶真實 ip,說明我們獲取用戶真實 ip 成功了。

參考:https://cloud.tencent.com/developer/article/1521273、https://amos-x.com/index.php/amos/archives/nginx-realip/
9.2、解決配置 realip 模塊報錯問題
使用 realip 功能需要 Nginx 添加 ngx_http_realip_module 模塊,默認情況下是不被編譯。如果我們沒有配置 realip,而在 Nginx 配置中使用 real_ip_header 的配置,則可能會報以下錯誤:

此時可參考:https://blog.csdn.net/qq_33101675/article/details/79013248。注意,鏈接中方法是重新安裝了一個 Nginx,鏈接中的方法指定了安裝的新的 Nginx 在 /usr/cmcc/nginx/conf 目錄下,所以我們應該使用該目錄下的 Nginx,如果我們還用舊的 Nginx 的話可能會報同樣的錯誤。
realip模塊的作用是:當本機的nginx處于一個反向代理的后端時獲取到真實的用戶IP。
如果沒有realip模塊,nginx的access_log里記錄的IP會是反向代理服務器的IP,PHP中$_SERVER[‘REMOTE_ADDR’]的值也是反向代理的IP。而安裝了realip模塊,并且配置正確,就可以讓nginx日志和php的REMOTE_ADDR都變成真實的用戶IP。

浙公網安備 33010602011771號