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; }
可参考:https://www.cnblogs.com/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 作为标记,否则可能会发生上述错误。
如果正则表达式有出现 } 或 ; 字符,则整个正则表达式应使用单引号 ' 或双引号 " 括起来。
可参考:https://www.cnblogs.com/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、内置变量
常见内置变量,参考:https://www.cnblogs.com/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。