0%

ngx_http_real_ip 模块

场景

如果客户端的HTTP请求是直连Nginx,则可以通过$remote_addr$remote_port获取客户端的真实IP、端口,以此进行限流、过滤等操作。但若Nginx放在CDN、SLB后面,CDN、SLB转发客户端的HTTP请求到Nginx,$remote_addr$remote_port返回的是CDB、SLB连接Nginx的IP、端口。

当请求经过CDN、SLB转发后,为了上游服务器能获取到用户的真实IP和端口,业界的标准是在转发HTTP请求时,添加指定的头部字段用于保存客户的真实IP和端口,通常是X-Real-IP或者X-Forwarded-For。比如当使用阿里云的CDN时,X-Forwarded-For字段就存储客户端的真实IP、端口。

为此Nginx提供了HTTP Real IP模块,在Nginx的POST_READ阶段,将$remote_addr$remote_port替换为HTTP请求头中指定字段内的IP、端口,进而后续再进行限流、过滤等操作

安装

http_real_ip模块默认未编译进Nginx,需在编译时手动添加参数

1
--with-http_realip_module

常用指令

1. set_real_ip_from
1
2
3
Syntax:	 set_real_ip_from address | CIDR | unix:;
Default: —
Context: http, server, location

用于指定可信地址,只有从可信地址发过来的请求才会进行$remote_addr$remote_port的替换。可以是单个地址,可以是CIDR,若是unix:,则所有的UNIX套接字都被认为是可信的。

此条指令可以重复出现,比如有两个可信地址则可以配置成:

1
2
set_real_ip_from 1.1.1.1;
set_real_ip_from 8.8.8.8;

2. real_ip_head

1
2
3
Syntax:  real_ip_header field | X-Real-IP | X-Forwarded-For | proxy_protocol;
Default: real_ip_header X-Real-IP;
Context: http, server, location

指定转发HTTP请求时存储客户端真实IP、端口的字段,http_realip_module将$remote_addr$remote_port替换为此字段中的IP、端口。

X-Real-IP vs X-Forwarded-For
  • X-Real-IP(默认)只存储一组IP、端口,直接取这组值替换$remote_addr$remote_port
  • X-Forwarded-For会存储多组IP、端口,之间用,隔开,比如:1.1.1.1,8.8.8.8。比如请求先通过CDN,后又有SLB,则每经过一次转发X-Forwarded-For就会在后面追加一个地址。在替换时会取最后一个,在上例子即是8.8.8.8替换$remote_addr$remote_port

3. real_ip_recursive

1
2
3
4
Syntax:  real_ip_recursive on | off;
Default: real_ip_recursive off;
Context: http, server, location
This directive appeared in versions 1.3.0 and 1.2.1.

If recursive search is disabled, the original client address that matches one of the trusted addresses is replaced by the last address sent in the request header field defined by the real_ip_header directive. If recursive search is enabled, the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the request header field.

递归搜索默认是关闭的,用real_ip_head指令指定的字段(X-Forwarded-ForX-Real-IP)内的最后一个地址替换原始的地址。若递归搜索开启,则用最后一个非可信地址的地址替换原始地址。

其他

  • $realip_remote_addr保存原始客户端地址(被替换前的)
  • $realip_remote_port保存原始的客户端端口

Nginx官方文档Module ngx_http_realip_module中提到上面的set_real_ip_fromreal_ip_headerreal_ip_recursive可放在httpserverlocation上下文中,这是不对的。
http_real_ip模块起作用是在POST_READ阶段,是在FIND_CONFIG之前,而FIND_CONFIG阶段对应找到相应的location,则放在location内则是不生效的。

参考