在 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。