Nginx实现多级反向代理客户端IP透传

Posted 一夜入秋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nginx实现多级反向代理客户端IP透传相关的知识,希望对你有一定的参考价值。

反向代理配置参数

官方文档:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html

proxy_pass;
#用来设置将客户端请求转发给的后端服务器的主机,可以是主机名(将转发至后端服务做为主机头首部)、IP地址:端口的方式
#也可以代理到预先设置的主机群组,需要模块ngx_http_upstream_module支持

proxy_hide_header field;
#用于nginx作为反向代理的时候,在返回给客户端http响应时,隐藏后端服务器相应头部的信息,可以设置在http,server或location块
proxy_hide_header ETag;
#隐藏后端服务器ETag首部字段

proxy_pass_request_body on | off; 
#是否向后端服务器发送HTTP实体部分,可以设置在http,server或location块,默认即为开启

proxy_pass_request_headers on | off; 
#是否将客户端的请求头部转发给后端服务器,可以设置在http,server或location块,默认即为开启

proxy_set_header;
#可更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实IP的时候,就要更改每一个报文的头部

#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#添加客户端IP和反向代理服务器IP到请求报文头部
“X-Forwarded-For”客户端请求标头字段,$remote_addr附加变量,用逗号分隔。
如果客户端请求标头中不存在“X-Forwarded-For”字段,则该$proxy_add_x_forwarded_for变量等于该$remote_addr变量。

proxy_set_header X-Real-IP $remote_addr;
#添加HOST到报文头部,如果客户端为NAT上网那么其值为客户端的共用的公网IP地址,常用于在日之中记录客户端的真实IP地址。
#在后端httpd服务器修改配置,添加日志记录X-Forwarded-For字段
LogFormat "%h %l %u %t \\"%r\\" %>s %b \\"%Refereri\\" \\"%User-Agenti\\" \\"%X-Forwarded-Fori\\"" combined

proxy_connect_timeout time;
#配置nginx服务器与后端服务器尝试建立连接的超时时间,默认为60秒,用法如下:
proxy_connect_timeout 6s; 
#60s为自定义nginx与后端服务器建立连接的超时时间,超时会返回客户端504响应码

proxy_read_timeout time;
#配置nginx服务器向后端服务器或服务器组发起read请求后,等待的超时时间,默认60s
proxy_send_timeout time; 
#配置nginx项后端服务器或服务器组发起write请求后,等待的超时 时间,默认60s

反向代理缓存功能的配置

默认缓存功能是没有开启的,需要手动配置一下才可以启用。
相关的配置如下:

proxy_cache zone_name | off; 默认off
#指明调用的缓存,或关闭缓存机制;Context:http, server, location
#zone_name 表示缓存的名称.需要由proxy_cache_path事先定义

proxy_cache_key string;
#缓存中用于“键”的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri;

proxy_cache_valid [code ...] time;
#定义对特定响应码的响应内容的缓存时长,定义在http...中
示例:
proxy_cache_valid 200 302 301 10m; 

proxy_cache_path;
#定义可用于proxy功能的缓存;Context:http 
proxy_cache_path path [levels=levels] [use_temp_path=on|off] 
keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number] 
[manager_sleep=time] [manager_threshold=time] [loader_files=number] 
[loader_sleep=time] [loader_threshold=time] [purger=on|off] 
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
示例:在http配置定义缓存信息
proxy_cache_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动创
建目录
   levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=2^20=1048576个目录
   keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数),一般1M可存放8000个左右的key
   inactive=120s  #缓存有效时间  
   max_size=10g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值

#调用缓存功能,需要定义在相应的配置段,如server...;或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri; #对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m;   #除指定的状态码返回的数据以外的缓存多长时间,必须设置,否则不会缓存

清理缓存的方法:

  • 方法1: rm -rf 缓存目录
  • 方法2: 使用第三方扩展模块ngx_cache_purge

添加响应报文的头部信息

nginx基于模块ngx_http_headers_module可以实现对后端服务器响应给客户端的报文中添加指定的响应首部字段
官方文档:
https://nginx.org/en/docs/http/ngx_http_headers_module.html
语法格式:

Syntax: add_header name value [always];
Default:    —
Context:    http, server, location, if in location

示例:

location /static 
    proxy_pass http://10.0.0.101:80/;
    proxy_cache proxycache;
    proxy_cache_key $request_uri;
    proxy_cache_valid 200 302 301 1h;
    proxy_cache_valid any 1m;
    
    proxy_set_header clientip $remote_addr;
    add_header X-Via  $server_addr;
    add_header X-Cache $upstream_cache_status;
    add_header X-Accel $server_name;

案例:多级代理实现客户端 IP 透传

实现的架构图:

环境准备:

client :10.0.0.8 测试
nginx1 :10.0.0.100 X-Forwarded-For:client ip
nginx2 :10.0.0.102 X-Forwarded-For:client ip
httpd :10.0.0.7 X-Forwarded-For:client ip,nginx1

第一个代理服务器配置

root@nginx1:~# vim /apps/nginx/conf/nginx.conf
#开启日志格式,记录x_forwarded_for
http 
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens off;
    proxy_cache_path /data/nginx/proxycache levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g;

    log_format  main  $remote_addr - $remote_user [$time_local] "$request" 
                      $status $body_bytes_sent "$http_referer" 
                      "$http_user_agent" "$http_x_forwarded_for";
    access_log  logs/access.log  main;

#定义反向代理
root@nginx1:~# vim /apps/nginx/conf.d/pc.conf
server 
    listen 80;    server_name www.zhanggui.com;
    proxy_cache off;
    proxy_cache_key $request_uri;
    proxy_cache_valid 200 302 301 10m;
    proxy_cache_valid any 5m;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_hide_header ETag;
    add_header X-Via $server_addr;
    add_header X-Cache $upstream_cache_status;
    add_header X-Accel $server_name;
    location / 
        root /data/nginx/html/pc;
        index index.html index.hml;                                                                  
        proxy_pass http://www.zhanggui.org;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    

root@nginx1:~# vim /etc/hosts   #加上本地的host解析
10.0.0.102 www.zhanggui.org
#重新加载
root@nginx1:~# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
root@nginx1:~# nginx -s reload

第二个代理服务器配置

root@nginx2:~# vim /apps/nginx/conf/nginx.conf
#开启日志格式,记录x_forwarded_for
http 
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens off;
    proxy_cache_path /data/nginx/proxycache levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g;

    log_format  main  $remote_addr - $remote_user [$time_local] "$request" 
                      $status $body_bytes_sent "$http_referer" 
                      "$http_user_agent" "$http_x_forwarded_for";
    access_log  logs/access.log  main;

#定义反向代理
root@nginx2:~# vim /apps/nginx/conf.d/pc.conf
server 
    listen 80;
    server_name www.zhanggui.org;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    location / 
        root /data/nginx/html
        proxy_pass http://10.0.0.7;
    

root@nginx2:~# echo 10.0.0.102 > /data/nginx/html/index.html
#检查nginx配置文件语法并重新加载配置文件
root@nginx2:~# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
root@nginx2:~# nginx -s reload

现在测试一下访问一下www.zhanggui.com并在各个代理服务器上查看相关日志

#在第一个代理服务器上面查看日志
root@nginx1:~# tail -f /apps/nginx/logs/access.log
10.0.0.8 - - [23/Apr/2022:22:13:09 +0800] "GET /index.html HTTP/1.1" 200 612 "-" "curl/7.61.1" "-"

#在第二个代理服务器上面查看日志
root@nginx2:~# tail -f /apps/nginx/logs/access.log
10.0.0.100 - - [23/Apr/2022:22:13:09 +0800] "GET /index.html HTTP/1.0" 200 612 "-" "curl/7.61.1" "10.0.0.8"

现在配置一下httpd后端的服务器

#yum安装Apache包
[root@httpd ~]# yum -y install httpd
#配置服务器的日志格式
[root@httpd ~]# vim /etc/httpd/conf/httpd.conf
LogFormat "\\"%x-Forwarded-Fori\\" %h %l %u %t \\"%r\\" %>s %b \\"%Refereri\\" \\"%User-Agenti\\"" testlog
    CustomLog "logs/access_log" testlog
[root@httpd ~]# httpd -t
AH00558: httpd: Could not reliably determine the servers fully qualified domain name, using fe80::20c:29ff:fe80:5484. Set the ServerName directive globally to suppress this message
Syntax OK
[root@httpd ~]# systemctl start httpd
#设置访问页面
[root@httpd ~]# echo 10.0.0.7 > /var/www/html/index.html

在客户端测试访问并查看后端服务器的日志

[root@client ~]#curl http://www.zhanggui.com
10.0.0.7
[root@httpd ~]# tail -f /var/log/httpd/access_log 
"10.0.0.8, 10.0.0.100" 10.0.0.102 - - [23/Apr/2022:22:35:46 +0800] "GET / HTTP/1.0" 200 9 "-" "curl/7.61.1"

以上是关于Nginx实现多级反向代理客户端IP透传的主要内容,如果未能解决你的问题,请参考以下文章

Nginx多级反向代理下的IP透传

Nginx实现反向代理客户端IP透传

Nginx多层反向代理透传客户端真实IP

haproxy+openresty实现反向代理和ip透传

Nginx实践:用rewrite规则实现域名重定向及客户端IP地址透传

08-nginx的反向代理缓存功能