Nginx 反向代理配置指南 详解 proxy_pass 与请求头设置

在现代 Web 架构中,将 Nginx 部署在应用服务器前端是最常见的部署模式之一。应用服务器只需在本地端口上监听普通的 HTTP 请求,而 Nginx 则负责处理所有面向公网的流量:TLS 终止、请求头重写、缓存、压缩,以及多后端负载均衡。
反向代理的工作机制是:接收客户端请求,将其转发给一个或多个后端服务器,再将后端响应返回给客户端。凭借出色的性能和小巧的内存占用,Nginx 常被用作 HTTP 服务器(如 Node.js、Python、Java 应用)的反向代理,也适用于 PHP-FPM、FastCGI 等非 HTTP 后端。
使用 Nginx 作为反向代理的优势
- 负载均衡:将客户端请求分发到多台上游服务器,提升性能、扩展性和可用性。
- 缓存:缓存后端响应并直接返回给客户端,降低后端压力,加速页面加载。
- TLS 终止:Nginx 接收 HTTPS 连接并解密,与上游通过普通 HTTP 通信。这样 TLS 配置和证书可以集中管理。
- 压缩:如果后端未返回压缩响应,Nginx 可以在返回客户端前进行压缩。
- 限流与访问控制:基于客户端 IP 限制请求频率,或根据地理位置、User-Agent、Referer 等请求头进行访问限制。
本文将系统讲解 Nginx 反向代理的配置方法,涵盖基础语法、常用的 proxy_set_header 指令,以及常见问题的排查思路。
1. Nginx 反向代理基础配置
要将 Nginx 配置为 HTTP 服务器的反向代理,打开对应域名的 server 块配置文件,在 location 中声明转发规则:
server {
listen 80;
server_name www.example.com example.com;
location /app {
proxy_pass http://127.0.0.1:8080;
}
}
proxy_pass 指令用于设置上游服务器地址,支持 http 或 https 协议,可填写域名或 IP 地址,并可选指定端口和 URI。
上述配置表示:所有匹配 /app 路径的请求,都会被转发到 http://127.0.0.1:8080。
提示:在 Ubuntu 和 Debian 系发行版中,server 块文件通常位于 /etc/nginx/sites-available/;在 Fedora、RHEL 及其衍生版中,则位于 /etc/nginx/conf.d/。
location 与 proxy_pass 的交互规则
以下示例展示了两者如何配合工作:
server {
listen 80;
server_name www.example.com example.com;
location /blog {
proxy_pass http://node1.com:8000/wordpress/;
}
}
当用户访问 http://example.com/blog/my-post 时,Nginx 会将请求代理到 http://node1.com:8000/wordpress/my-post。
规则说明:当 proxy_pass 地址中包含 URI(如 /wordpress/)时,请求 URI 中匹配 location 前缀的部分会被替换为该 URI;若 proxy_pass 地址不含 URI,则原始请求 URI 保持不变直接转发。
2. 使用 proxy_set_header 设置请求头
默认情况下,Nginx 在代理请求时会重写两个请求头:Host 被设为上游主机名($proxy_host),Connection 被设为 close。其余客户端发送的请求头原样转发,空值请求头会被自动移除。
这种默认行为在绝大多数场景下并不合适。特别是,上游服务器看到的 Host 头是 $proxy_host 而非用户实际访问的域名,且会将 127.0.0.1(即 Nginx 自身)视为远程地址。解决方法是显式设置上游所需的请求头。
以下是一个通用的 HTTP 反向代理请求头配置模板:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
各指令的作用如下:
| 指令 | 值 | 作用 |
|---|---|---|
| Host | $host | 转发客户端实际请求的域名。若不设置,上游看到的是 $proxy_host,无法进行基于域名的路由,也无法生成正确的绝对 URL。 |
| X-Real-IP | $remote_addr | 将真实客户端 IP 传递给上游。若不设置,上游看到的是 127.0.0.1。 |
| X-Forwarded-For | $proxy_add_x_forwarded_for | 将客户端 IP 追加到已有的 X-Forwarded-For 链中,便于上游还原请求经过的完整代理路径。 |
| X-Forwarded-Proto | $scheme | 告知上游原始请求是 http 还是 https。框架依赖此信息生成重定向或规范 URL。 |
| X-Forwarded-Host | $host | 转发客户端请求的原主机名,适用于上游监听端口与公网端口不一致的场景。 |
| X-Forwarded-Port | $server_port | 转发客户端实际连接的端口。 |
如需阻止某个请求头被传递到上游,可将其值设为空字符串。例如,以下配置移除 Accept-Encoding 头,确保上游始终返回未压缩的响应:
proxy_set_header Accept-Encoding "";
配置修改后,记得重载 Nginx 使设置生效。
3. WebSocket 反向代理
WebSocket 使用 HTTP Upgrade 机制,因此需要额外配置。如果应用提供 WebSocket 端点,需在 http 上下文中添加 map 映射,并为该端点配置如下 location:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
# ... 其他指令
location /socket/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
以下 WebSocket 专用指令仅在实际处理 WebSocket 流量的 location 中使用:
- proxy_http_version 1.1:当上游需要 HTTP/1.1 特性(如 WebSocket 升级或持久连接)时使用。Nginx 1.29.7 之前的版本默认使用 HTTP/1.0;1.29.7 及之后版本默认使用 HTTP/1.1。
- Upgrade $http_upgrade 和 Connection $connection_upgrade:WebSocket 升级必需。map 配置确保仅在客户端请求升级时将 Connection 设为 upgrade,普通请求则回退为 close。
如果启用了 proxy_cache,建议添加 proxy_cache_bypass $http_upgrade;,避免 WebSocket 升级请求被缓存命中。
4. proxy_set_header 与 add_header 的区别
这两个指令常被混淆,核心区别在于作用对象不同:
- proxy_set_header:设置 Nginx 发送给上游服务器的请求头。
- add_header:设置 Nginx 返回给客户端的响应头。
需要让上游获取某些信息(如客户端 IP、原始主机名)时,使用 proxy_set_header;需要让浏览器获取某些信息(如安全响应头、CORS、缓存控制)时,使用 add_header。
5. 代理非 HTTP 后端
Nginx 还可以代理不基于 HTTP 协议的后端,此时不使用 proxy_pass,而是使用协议专属指令:
| 指令 | 用途 |
|---|---|
| fastcgi_pass | 反向代理到 FastCGI 服务器(如 PHP-FPM) |
| uwsgi_pass | 反向代理到 uWSGI 服务器 |
| scgi_pass | 反向代理到 SCGI 服务器 |
| memcached_pass | 反向代理到 Memcached 服务器 |
最常见的场景是将 Nginx 作为 PHP-FPM 的反向代理:
server {
# ... 其他指令
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
请根据系统上安装的 PHP-FPM 版本调整 socket 路径(例如 Ubuntu 24.04 使用 php8.3-fpm.sock,Debian 13 可能使用 php8.4-fpm.sock)。
6. TLS 终止配置
如今,HTTPS 已是标配。在 Nginx 处终止 TLS,并以普通 HTTP 转发给上游,是主流做法:
server {
listen 443 ssl;
http2 on;
server_name www.example.com example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
http2 on; 用于在该 server 块中启用 HTTP/2。如果你使用的是 Nginx 1.25.1 之前的版本(如 Ubuntu 24.04 的默认包),该指令不可用,请改用 listen 443 ssl http2;。
如果尚未获取证书,可以使用 Certbot 申请免费的 Let’s Encrypt 证书并自动配置 Nginx。
7. 速查表
7.1 常用 proxy_set_header 指令
| 指令 | 值 | 作用 |
|---|---|---|
| Host | $host | 转发客户端请求的域名,而非 $proxy_host |
| X-Real-IP | $remote_addr | 将客户端 IP 发送给上游 |
| X-Forwarded-For | $proxy_add_x_forwarded_for | 将客户端 IP 追加到已有代理链 |
| X-Forwarded-Proto | $scheme | 告知上游原始请求是 http 还是 https |
| X-Forwarded-Host | $host | 转发客户端请求的原始主机名 |
| X-Forwarded-Port | $server_port | 转发客户端实际连接的端口 |
| Upgrade | $http_upgrade | WebSocket 场景使用 |
| Connection | $connection_upgrade | WebSocket 场景使用 |
7.2 其他辅助指令
| 指令 | 值 | 作用 |
|---|---|---|
| proxy_pass | 上游 URL | 反向代理的目标地址 |
| proxy_http_version | 1.1 | 当上游需要 HTTP/1.1 特性(如 WebSocket)时使用 |
| proxy_cache_bypass | $http_upgrade | 若启用缓存,对 WebSocket 升级请求跳过缓存 |
8. 常见问题排查
8.1 502 Bad Gateway
Nginx 无法连接到上游。请依次检查:
- 上游服务是否已在 proxy_pass 指定的地址和端口上监听(使用 ss -tlnp 或在 Nginx 主机上执行 curl 测试);
- SELinux 或防火墙是否拦截了连接;
- 查看 /var/log/nginx/error.log 获取具体原因(连接被拒绝、超时、TLS 握手失败等)。
8.2 后端看到的客户端 IP 是 127.0.0.1
缺少 proxy_set_header X-Real-IP $remote_addr; 或 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;。添加这两个指令后,还需确保应用正确读取这些请求头。如果应用前面有多层代理,还需配置应用信任最外层代理的地址。
8.3 WebSocket 连接立即断开
WebSocket 需要 HTTP/1.1 以及 Upgrade/Connection 请求头对。请确保:
- 设置了 proxy_http_version 1.1;
- 设置了 proxy_set_header Upgrade $http_upgrade; 和 proxy_set_header Connection $connection_upgrade;
- 在 http 上下文中正确定义了 map 映射
8.4 应用生成的是 http:// URL,但站点实际是 HTTPS
因为 Nginx 终止了 TLS 并以普通 HTTP 转发给上游,应用不知道原始请求是 HTTPS。请添加 proxy_set_header X-Forwarded-Proto $scheme;,并在框架中配置信任该请求头(例如 Express 中的 trust proxy,Django 中的 SECURE_PROXY_SSL_HEADER)。
8.5 上游的虚拟主机路由失效
上游收到的 Host 头是 $proxy_host,无法匹配其虚拟主机配置。请使用 proxy_set_header Host $host; 转发原始主机名。
FAQ
Q:如何在 Nginx 反向代理中设置请求头?
在拥有 proxy_pass 的 location 块中使用 proxy_set_header。例如,proxy_set_header Host $host; 将原始主机名转发给上游。若要移除某个请求头,将其值设为空字符串即可:proxy_set_header Accept-Encoding “”;。
Q:proxy_set_header 和 add_header 有什么区别?
proxy_set_header 修改 Nginx 发送给上游的请求头;add_header 修改 Nginx 返回给客户端的响应头。前者用于与上游通信,后者用于与浏览器通信(例如设置 Strict-Transport-Security 或 CORS 响应头)。
Q:应该向上游转发哪些请求头?
至少应转发 Host、X-Real-IP、X-Forwarded-For 和 X-Forwarded-Proto。对于 WebSocket,还需设置 Upgrade、Connection $connection_upgrade,并使用 proxy_http_version 1.1。可选但建议添加:X-Forwarded-Host 和 X-Forwarded-Port(当公网端口与上游端口不一致时)。
Q:为什么后端看到的客户端 IP 是 127.0.0.1?
未显式配置请求头时,上游只能看到 Nginx 发起连接的地址,通常是 127.0.0.1。请添加 proxy_set_header X-Real-IP $remote_addr; 和 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,并配置应用读取这些请求头。
总结
将 Nginx 配置为反向代理,核心在于做好两件事:一是将 proxy_pass 指向正确的上游地址,二是转发上游所需的请求头,使其行为如同客户端直接连接。搞定这两点后,就可以在此基础上叠加 TLS 终止、缓存、负载均衡、限流等功能,而无需修改应用代码本身。
以上关于Nginx 反向代理配置指南 详解 proxy_pass 与请求头设置的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » Nginx 反向代理配置指南 详解 proxy_pass 与请求头设置
微信
支付宝