Nginx服务变量传递


Nginx 是一款轻量级的 Web 服务器和反向代理服务器!

Nginx 是什么 "engine x" 是一个开源的,支持高性能、高并发的 Web 服务和代理服务软件。它是由俄罗斯人 Igor Sysoev 开发的,作者将源代码以类 BSD 许可的形式开源出来供全球使用。

Nginx服务变量传递 - HEADER的定义


1. 代理服务设置

介绍多层代理设置来获取用户信息的方式!

当我们部署服务的时候,因为某种或者某些原因导致需要部署多个 Nginx 服务进行工作(负责处理不同的问题)。这样就会出现一个问题,后置的 Nginx 服务如何获取到用户访问的 IP 地址呢?

可能到这里,你已经想到了使用 Header 进行变量传递,将用户真实访问地址,间接的传递给后端服务,从而获取到对应地址。这时,需要我们在 Nginx 的配置文件 nginx.conf 中添加如下配置。

  • Host $http_host
    • 包含客户端的域名和端口号
  • X-Forwarded-Proto $scheme
    • 表示客户端真实的协议(http还是https)
  • X-Real-IP $remote_addr
    • 表示客户端真实的 IP 地址
  • X-Forwarded-For $proxy_add_x_forwarded_for
    • 这个 HeaderX-Real-IP类似
    • 但它在多层代理时会包含真实客户端及中间每个代理服务器的 IP 地址

关于 Nginx 相关的变量定义、使用方式、对应解释,我们可以通过查阅 官方的变量列表进行查看 从而获取到我们所需要使用的变量,加以使用。

# 前置Nginx服务配置
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

但是,如果我们在后置 Nginx 服务上面也这样配置的话,然后通过浏览器或者命令行工具进行请求的话,会发现获取的 Host 并不是真实客户端的,而是前置 Nginx 服务的地址。同理,对应的 IP 还是本地的 IP 而非真实客户端 IP 地址。

到这里,我们来完善一下后置 Nginx 的对应配置,来完成获取客户端信息的收集。

# 后置Nginx服务配置
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Real-IP $http_x_real_ip;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;

2. 变量传递规则

host -> $http_host > 所有请求头里面的 Key 再 Nginx 里面都可以通过小写和下划线来让 Nginx 读取

看到这里,肯定有人会问,为什么后置的 Nginx 服务需要配置 http_ 这个前缀,从而获取到前置 Nginx 服务 header 中设置的变量呢?我们下面以 $http 来进行解释和说明。

  • 这里 hostNginx 官方定义的变量名称,可以通过查询得到。而 http_host 是读取请求头 header 里面的 key 获取到的值。
  • 这是因为 $http_host 不是一个固定的变量,它其实是 $http_HEADER 通配后的结果。注意,这里的 HEADER 是一个通配符,通配的是请求头里的 header 属性。
  • 例如 $http_content_type 表示请求头里 content-type 属性的值。同理,我们也就可以使用 $http_host 来指请求头里的 host 属性。

Nginx服务变量传递 - HEADER的定义

说到这里,我们来一起看下,$host 变量值的获得优先级。

  1. 请求行中定义的 host
# 请求行
GET /index.html HTTP/1.1
GET www.test.com/index.html HTTP/1.1
  1. 请求头中定义的 Host 头部

Nginx服务变量传递 - 请求头中的Host信息

  1. 与一条请求匹配的 server name
# 请求匹配
server {
    listen      80;
    server_name test.com www.test.com;
    ...
}

3. 实例演示说明

以一个真实的案例进行说明和解释!

如下图所示,用户通过浏览器访问网站,经由 F5 负载均衡器将用户请求发送到 DMZ 区中的 Proxy-Nginx 服务。该服务可以访问 K8S 系统,将用户请求发送到 K8S 内部的 Proxy-NginxPod 中,最后通过 CoreDNS 转发给 App 服务。

因为 K8S 使用 Ingress 这个通过域名方式来暴露内部服务的(内网域名),所以 DMZ 区中的 Proxy-Nginx 服务需要设置 header 中的 HostK8S 内部的 Proxy-Nginx 的域名地址,才可以访问对应服务(不然K8S也不知道你要访问谁)。此时,我们后置的这个 Nginx 服务就无法得到客户的正式 Host 地址的。

恰好,此时我们这个 App 服务需要使用 Host 进行权限验证的话,那么就尴尬了。因为我们后置的这个 Nginx 服务获取的 Host 就是它自己,传递给 App 也就是自己的地,就无法完成正常的权限校验了。此时,我们可以通过如下这样添加 header 的方式,间接获取到用户的 Host,完成权限校验。

Nginx服务变量传递 - 图示请求流程


4. 获取正式地址

透过代理获取真实 IP 地址!

咳咳咳,当然如果在 Nginx 中提供了对应模块来实现我们的需求的话,可以使用通过使用模块的方式来完成对应工作。比如:

  • Module ngx_http_realip_module - 透过代理获取真实 IP 地址

    • set_real_ip_from
      • 获取真实 IP 地址,可以是网段且可设置多个
    • real_ip_header
      • 从哪个 header 属性中获取真实 IP 地址
    • real_ip_recursive
      • 递归检索真实 IP 地址
      • 如果中 X-Real-IP 中获取,无需递归
      • 如果从 X-Forwarded-For 中获取,则需要递归检索
  • 环境信息

    • client_ip -> proxy_server_x -> web_server
# 环境信息
client_ip:10.10.10.1

proxy_server_1:10.10.10.16
proxy_server_2:10.10.10.17

web_server:10.10.10.18
  • 使用 X-Forwarded-For 完成
# proxy_server_1
location / {
    proxy_pass http://10.10.10.17;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $remote_addr;
}

# proxy_server_2
location / {
    proxy_pass http://10.10.10.18;
    proxy_set_header Host $http_host;
}

# web_server
server {
    set_real_ip_from 10.10.10.16;
    set_real_ip_from 10.10.10.17;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
}
  • 使用 X-Real-IP 完成
# proxy_server_1
location / {
    proxy_pass http://10.10.10.17;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
}

# proxy_server_2
location / {
    proxy_pass http://10.10.10.18;
    proxy_set_header Host $http_host;
}

# web_server
server {
    set_real_ip_from 10.10.10.16;
    set_real_ip_from 10.10.10.17;
    real_ip_header X-Real-IP;
    real_ip_recursive on;
}

5. 参考链接地址

送人玫瑰,手有余香!


文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !
  目录