在  Nginx  代理后端  HTTP  服务时,通过  `proxy_set_header`  配置  `X-Forwarded-For`  和  `X-Forwarded-Proto`  请求头,是传递客户端真实  IP  和原始请求协议的标准方法。

一、核心配置:`proxy_set_header`

这两个指令通常放在  Nginx  配置的  `location`  或  `server`  块中。

1.  传递真实客户端  IP:`X-Forwarded-For`

使用  `$proxy_add_x_forwarded_for`  变量,它会将客户端的真实  IP  追加到现有的  `X-Forwarded-For`  头中。

```nginx

location  /  {

        proxy_pass  http://your_backend_server;

        #  ...  其他配置

        proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;

}

```

原理:`$proxy_add_x_forwarded_for`  的值等于“客户端IP,  已存在的X-Forwarded-For值”。如果请求头中没有  `X-Forwarded-For`,它的值就等于客户端的  IP。

  最佳实践:通常与  `X-Real-IP`  一起配置,`X-Real-IP`  只包含客户端的真实  IP。

        ```nginx

        proxy_set_header  X-Real-IP  $remote_addr;

        proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;

        ```

2.  传递原始请求协议:`X-Forwarded-Proto`

使用  `$scheme`  变量,它会自动获取客户端与  Nginx  建立连接时使用的协议(`http`  或  `https`)。

```nginx

location  /  {

        proxy_pass  http://your_backend_server;

        #  ...  其他配置

        proxy_set_header  X-Forwarded-Proto  $scheme;

}

```

  作用:如果后端应用需要知道原始请求是  HTTP  还是  HTTPS(例如,用于生成正确的重定向链接),这个配置就至关重要。

二、完整配置示例

将以上配置整合,一个典型的  Nginx  反向代理配置如下:

```nginx

server  {

        listen  80;

        server_name  your_domain.com;

        location  /  {

                proxy_pass  http://your_backend_server;

                #  传递真实客户端IP

                proxy_set_header  X-Real-IP  $remote_addr;

                proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;

                #  传递原始请求协议  (HTTP  或  HTTPS)

                proxy_set_header  X-Forwarded-Proto  $scheme;

                #  传递原始Host头

                proxy_set_header  Host  $host;

        }

}

```

三、后端如何获取这些信息?

配置完成后,后端服务器需要从相应的  HTTP  头中读取信息:

  获取真实  IP:读取  `X-Forwarded-For`  头的第一个(最左侧)  IP  地址。`X-Real-IP`  也可以作为备选。

  获取原始协议:读取  `X-Forwarded-Proto`  头的值。

不同后端语言的获取方式不同,例如在  PHP  中:

```php

//  获取真实IP

$ip  =  $_SERVER['REMOTE_ADDR'];

if  (isset($_SERVER['HTTP_X_FORWARDED_FOR']))  {

        $ips  =  explode(',',  $_SERVER['HTTP_X_FORWARDED_FOR']);

        $ip  =  trim($ips[0]);

}  elseif  (isset($_SERVER['HTTP_X_REAL_IP']))  {

        $ip  =  $_SERVER['HTTP_X_REAL_IP'];

}

//  获取原始协议

$protocol  =  isset($_SERVER['HTTP_X_FORWARDED_PROTO'])  ?  $_SERVER['HTTP_X_FORWARDED_PROTO']  :  'http';

```

四、重要安全提示:防止  IP  伪造

仅配置  `proxy_set_header`  存在安全风险,因为  `X-Forwarded-For`  头可以被伪造。

  在后端使用  `ngx_http_realip_module`  模块:该模块可以基于可信代理  IP  列表,用  `X-Forwarded-For`  中的真实  IP  替换  `$remote_addr`  变量。

  配置示例(在后端  Nginx  的  `http`,  `server`  或  `location`  块中):

        ```nginx

        #  指定可信的代理服务器IP或网段

        set_real_ip_from  192.168.1.0/24;    #  替换为你的代理服务器IP段

        set_real_ip_from  10.0.0.0/8;

        #  指定从哪个头获取真实IP

        real_ip_header  X-Forwarded-For;

        #  如果有多层代理,开启递归查找

        real_ip_recursive  on;

配置后,后端应用直接使用  `$remote_addr`  即可获取真实  IP。