Nginx接受代理协议


本文介绍了如何配置NGINX和NGINX Plus以接受PROXY协议,将负载均衡器或代理的IP地址重写为PROXY协议标头中接收到的负载均衡器或代理,配置客户端IP地址的简单日志记录以及启用PROXY协议在NGINX和TC 

介绍

通过PROXY协议, NGINX和NGINX Plus可以接收通过代理服务器和负载均衡器(例如HAproxy和Amazon Elastic Load Balancer(ELB))传递的客户端连接信息。

使用PROXY协议,NGINX可以从HTTP,SSL,HTTP / 2,SPDY,WebSocket和TCP学习原始IP地址。了解客户端的原始IP地址对于设置网站的特定语言,保留IP地址黑名单或仅用于日志记录和统计目的可能很有用。

通过PROXY协议传递的信息是客户端IP地址,代理服务器IP地址以及两个端口号。

使用此数据,NGINX可以通过几种方式获取客户端的原始IP地址:

 

先决条件

  • 要接受PROXY协议v2,NGINX Plus R16和更高版本或NGINX Open Source  1.13.11和更高版本
  • 要接受用于HTTP,NGINX Plus R3和更高版本或NGINX Open Source  1.5.12和更高版本的PROXY协议
  • 对于TCP客户端PROXY协议支持,NGINX Plus R7和更高版本或NGINX Open Source  1.9.3和更高版本
  • 接受用于TCP,NGINX Plus R11和更高版本或NGINX Open Source  1.11.4和更高版本的PROXY协议
  • 默认情况下,NGINX Open Source中不包括用于HTTP流(TCP)的Real-IP模块。有关详细信息,请参见安装NGINX开源。NGINX Plus不需要额外的步骤。

 

配置NGINX以接受代理协议

要配置NGINX接受PROXY协议报头中,添加proxy_protocol参数的listen指令在一个server块中或块。http {}stream {}



http  { 
    #... 
    服务器 { 
        监听 80    proxy_protocol ; 
        监听 443   ssl  proxy_protocol ; 
        #... 
    } 
}
   
流 { 
    #... 
    服务器 { 
        听 12345  proxy_protocol ; 
        #... 
    } 
}



现在,您可以将$proxy_protocol_addr$proxy_protocol_port变量用于客户端IP地址和端口,并另外配置HTTPStream Real-IP模块以通过客户端的IP地址和端口替换$remote_addr$remote_port变量中的负载均衡器的IP地址。

 

将负载均衡器的IP地址更改为客户端IP地址

您可以将负载平衡器或TCP代理的地址替换为从PROXY协议收到的客户端IP地址。这可以通过HTTPStream Real-IP模块来完成。使用这些模块,$remote_addr$remote_port变量保留客户端的实际IP地址和端口,而$realip_remote_addr$realip_remote_port变量保留负载均衡器的IP地址和端口。

要将IP地址从负载均衡器的IP地址更改为客户端的IP地址,请执行以下操作:

  1. 确保已将NGINX配置为接受PROXY协议标头。请参阅配置NGINX接受PROXY协议
  2. 确保您的NGINX安装包括HTTPStream Real-IP模块:
nginx -V 2 > &1  | grep- 'http_realip_module'nginx 
-V 2 > &1  | grep- 'stream_realip_module'

如果不是,请使用这些模块重新编译NGINX。有关详细信息,请参见安装NGINX开源。NGINX Plus不需要额外的步骤。

  1. HTTPStream或两者的set_real_ip_from伪指令中,指定TCP代理或负载均衡器的IP地址或CIDR地址范围:
服务器 { 
    #... 
    set_real_ip_from  192 .168.1.0 / 24 ; 
   #... 
}
  1. 在上下文中,通过为伪指令指定参数,将负载均衡器的IP地址更改为从PROXY协议标头接收的客户端的IP地址:http {}proxy_protocolreal_ip_header
http  { 
    服务器 { 
        #... 
        real_ip_header  proxy_protocol ; 
      } 
}

 

记录原始IP地址

当您知道客户端的原始IP地址时,可以配置正确的日志记录:

  1. 对于HTTP,配置NGINX以使用$proxy_protocol_addr带有proxy_set_header伪指令的变量将客户端IP地址传递给上游服务器:
http  { 
    proxy_set_header  X-Real-IP        $ proxy_protocol_addr ; 
    proxy_set_header  X-Forwarded-For  $ proxy_protocol_addr ; 
}
  1. $proxy_protocol_addr变量添加到log_format指令(HTTPStream):
  • http块中:
HTTP  { 
    #... 
    log_format  结合 ' $ proxy_protocol_addr  -  $ REMOTE_USER  [ $ time_local]  ' 
                        ' “ $要求”  $状态 $ body_bytes_sent  ' 
                        ' “ $ HTTP_REFERER”  “ $ HTTP_USER_AGENT”' ; 
}
  • stream块中:
流 { 
    #... 
    log_format  基本 ' $ proxy_protocol_addr  -  $ REMOTE_USER  [ $ time_local]  ' 
                      ' $协议 $状态 $ bytes_sent  $ bytes_received  ' 
                      ' $ session_time' ; 
}

 

用于与上游TCP连接的PROXY协议

对于TCP流,可以为NGINX和上游服务器之间的连接启用PROXY协议。要启用PROXY协议,请将proxy_protocol指令包含server在该级别的块中:stream {}



流 { 
    服务器 { 
        监听 12345 ; 
        proxy_pass  example.com :12345 ; 
        proxy_protocol  开启;
    } 
}



 



HTTP  { 
    log_format  合并 ' $ proxy_protocol_addr  -  $ REMOTE_USER  [ $ time_local]  ' 
                        ' “ $请求”  $状态 $ body_bytes_sent  ' 
                        ' “ $ HTTP_REFERER”  “ $ HTTP_USER_AGENT”' ; 
    #...

    服务器 { 
        server_name  localhost ;

        听 80    proxy_protocol ; 
        监听 443   ssl  proxy_protocol ;

        ssl_certificate       /etc/nginx/ssl/public.example.com.pem ; 
        ssl_certificate_key   /etc/nginx/ssl/public.example.com.key ;

        位置 / app /  { 
            proxy_pass        http:// backend1 ; 
            proxy_set_header  主机            $ host ; 
            proxy_set_header  X-Real-IP        $ proxy_protocol_addr ; 
            proxy_set_header  X-Forwarded-For  $ proxy_protocol_addr ; 
        } 
    } 
} 

流 { 
    log_format  基本 ' $ proxy_protocol_addr  -  $ REMOTE_USER  [ $ time_local]  ' 
                     ' $协议 $状态 $ bytes_sent  $ bytes_received  ' 
                     ' $ session_time' ; 
    #... 
    服务器 { 
        听              12345  ssl  proxy_protocol ;

        ssl_certificate      /etc/nginx/ssl/cert.pem ; 
        ssl_certificate_key  /etc/nginx/ssl/cert.key ;

        proxy_pass           backend.example.com :12345 ; 
        proxy_protocol       开启;
    } 
}



该示例假定NGINX前面有一个负载平衡器来处理所有传入的HTTPS流量,例如Amazon ELB。NGINX在端口443()上接受HTTPS流量,在端口12345上接受TCP流量,并接受通过PROXY协议从负载均衡器传递的客户端IP地址(和块中指令的参数)。listen 443 ssl;proxy_protocollistenhttp {}stream {}

NGINX终止HTTPS流量(ssl_certificatessl_certificate_key指令),并将解密的数据代理到后端服务器:

  • 对于HTTP: proxy_pass http://backend1;
  • 对于TCP: proxy_pass backend.example.com:12345

它包括带有proxy_set_header指令的客户端IP地址和端口。

指令中$proxy_protocol_addr指定的变量log_format还将HTTP和TCP的客户端IP地址传递到日志。

此外,TCP服务器(该块)将其自己的PROXY协议数据发送到其后端服务器(该指令)。stream {}proxy_protocol on