Nginx 反向代理完全入门:从一个真实场景开始

Nginx 反向代理完全入门:从一个真实场景开始

在服务部署中,经常会遇到这样的场景:

一个在本地 8080 端口启动的服务(例如 Spring Boot 应用或 Node.js API),需要通过 https://mydomain.com/api 这样的公共地址对外提供访问。

这便是 反向代理 的典型应用场景。Nginx 作为网关,负责接收所有用户的请求,然后根据预设规则,将请求转发给内部的实际服务。

本文将介绍如何一步步搭建一个健壮的反向代理,并详细解释其中最关键的两个知识点:proxy_pass 的斜杠规则 和 请求头的正确传递。


第一步:实现基础代理

首先解决上面提出的问题。目标是:当用户访问 .../api/... 时,Nginx 将请求转发给 http://127.0.0.1:8080。

在 Nginx 配置文件 server 块中,加入以下 location 配置:

nginx 复制代码
location /api/ {
    # 将请求转发给本地的 8080 端口
    proxy_pass http://127.0.0.1:8080/;
}

重启 Nginx 后,访问 https://mydomain.com/api/users,Nginx 会返回 http://127.0.0.1:8080/users 的内容。至此,最核心的代理功能已经完成。

第二步:理解 proxy_pass 的斜杠规则

proxy_pass 指令后的斜杠 / 是一个关键细节,它决定了 Nginx 如何处理和转发 URL。

以访问 https://mydomain.com/api/users 为例进行说明。

情况一:proxy_pass 带斜杠(常用)

这是刚才使用的配置:
proxy_pass http://127.0.0.1:8080/; (结尾有 /)

  • 行为 :当 proxy_pass 的地址以 / 结尾时,Nginx 会将 location 匹配到的路径从原始请求 URI 中移除,然后将剩余部分拼接到 proxy_pass 的地址后面。
  • 转换过程 :
    • 原始请求路径: /api/users
    • Nginx 移除匹配的 /api/,剩下: users
    • 最终后端收到的路径: /users
  • 适用场景 :这是最常见的用法。后端服务(如 Spring Boot)的路由通常从根路径 / 开始(例如 /users, /products),并不知道外部代理为其添加了 /api 前缀。

情况二:proxy_pass 不带斜杠

如果去掉结尾的斜杠:
proxy_pass http://127.0.0.1:8080; (结尾没有 /)

  • 行为 :Nginx 会将完整的原始请求 URI 直接拼接到 proxy_pass 的地址后面。
  • 转换过程 :
    • 原始请求路径: /api/users
    • 最终后端收到的路径: /api/users
  • 适用场景 :当后端服务本身已经配置了 /api 这个前缀(Context Path)时使用。

小结与速查

配置方式 proxy_pass 结尾 原始 URL 后端收到的路径 行为描述
方式 A http://ip:port/ (有斜杠) /api/users /users 切除前缀 (常用)
方式 B http://ip:port (无斜杠) /api/users /api/users 保留前缀 (透传)
方式 C http://ip:port/v1/ /api/users /v1/users 替换前缀

第三步:传递真实的请求头信息 proxy_set_header

经过反向代理后,后端服务直接感知到的请求方是 Nginx 服务器,而不是原始客户端。这会导致后端服务丢失关于真实用户和原始请求的关键信息。

proxy_set_header 指令可以将原始请求的重要信息添加到转发给后端的请求头中。

以下是推荐在多数场景下使用的标准配置:

nginx 复制代码
location /api/ {
    proxy_pass http://127.0.0.1:8080/;

    # === 核心 Header 传递 ===
    # 1. 传递客户端请求的域名
    proxy_set_header Host $host;

    # 2. 传递客户端的真实 IP
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 3. 传递客户端使用的协议 (http/https)
    proxy_set_header X-Forwarded-Proto $scheme;
}

Header 的作用

  1. Host $host; : 传递客户端请求的原始域名。如果后端服务需要根据域名进行逻辑判断(如多站点部署),此值至关重要。若不设置,后端获取到的 Host 可能是 127.0.0.1:8080。

  2. X-Real-IP 和 X-Forwarded-For: 传递客户端的真实 IP 地址。

    • $remote_addr 是直接连接到 Nginx 的客户端 IP。
    • $proxy_add_x_forwarded_for 会记录请求经过的每一层代理的 IP 链条,格式为 用户IP, CDN节点IP, ...。
    • 若不设置,后端日志记录的访问 IP 将永远是 Nginx 服务器的 IP,这对日志分析和安全审计非常不利。
  3. X-Forwarded-Proto $scheme : 传递客户端使用的协议(http 或 https)。

    • 场景 :Nginx 对外提供 https 服务,但 Nginx 与后端之间通过 http 通信以提高性能。
    • 如果后端不知道客户端正在使用 https,在执行重定向(如登录后跳转)时,可能会生成一个 http:// 链接。这会导致浏览器报告"混合内容"错误,或将用户从安全的 https 页面降级到不安全的 http 页面。

第四步:解决常见的静态资源 404 问题

一个常见的问题是:代理配置完成后,主页的 HTML 内容成功加载,但页面样式、图片等静态资源无法加载,浏览器控制台报告大量 404 错误。

问题根源

该问题通常源于应用代码中资源路径的写法。

假设后端返回的 HTML 中包含以下 CSS 引用:
<link rel="stylesheet" href="/css/style.css">

这是一个根路径。浏览器会据此发起一个独立的请求,地址为:
https://mydomain.com/css/style.css

由于 Nginx 配置中只有 /api/ 路径的代理规则,没有匹配 /css/ 的规则,因此这个请求无法被正确处理,导致 404 错误。

解决方案(推荐)

最佳实践是配置应用,使其感知到自身运行在特定的子路径下。

  • 前端应用 (Vue/React) :在打包配置中设置 publicPath 或 base。例如,在 vue.config.js 中设置为 publicPath: '/api/'。
  • 后端应用 (Spring Boot) :在 application.properties 中配置 server.servlet.context-path=/api。
  • 后端应用 (Swagger UI) :需要配置相关的路径参数,使其知道基础路径是 /api。

修改后,应用生成的 HTML 资源路径会自动带上 /api 前缀,变为:
<link rel="stylesheet" href="/api/css/style.css">

这样,浏览器请求的 https://mydomain.com/api/css/style.css 就能被 location /api/ 规则正确捕获并代理到后端。


完整的代理配置示例

综合以上所有知识点,一个健壮、通用的反向代理配置如下:

nginx 复制代码
# ----------------------------------------------------
# API 子路径代理
# 访问入口: https://mydomain.com/api/
# ----------------------------------------------------
location /api/ {
    # 1. 代理规则 (切掉 /api/ 前缀)
    proxy_pass http://127.0.0.1:8080/;

    # 2. 传递核心 Header
    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;

    # 3. WebSocket 支持 (可选,如果后端需要)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # 4. 超时设置 (可选,如果接口耗时较长建议调大)
    proxy_connect_timeout 60s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;

    # 5. 自动修正后端重定向地址 (可选,但推荐)
    # 如果后端返回一个重定向到 /login,Nginx 会自动修正为 /api/login
    proxy_redirect default; 
}

希望这篇教程能帮助读者更好地理解和应用 Nginx 反向代理。

相关推荐
姜鱼问生3 小时前
每次开机手动检查 6 样东西?我写了个 2 秒自检脚本
运维·网络·nginx·docker·容器
程序员大阳13 小时前
副队长大数据教程(7)--Hadoop 集群角色配置逻辑详解
大数据·hadoop·分布式·集群·配置·角色·逻辑
张张123y1 天前
后端第九课:部署上线(把你的 FastAPI 后端真正跑起来给别人用)
python·docker·部署·fastapi
xixingzhe21 天前
Nginx 看懂请求耗时瓶颈
服务器·前端·nginx
北风toto1 天前
Windows 下用 OpenSSL 生成 SSL 密钥并配置 Nginx 教程
windows·nginx·ssl
卜锦元1 天前
Docker Compose 部署 Nginx 1.30.6 完整指南
nginx·docker·容器
小小龙学IT1 天前
Nginx 开源 Web 服务器与反向代理深度解
前端·nginx·开源
Joy T2 天前
阿里云全栈部署 Skill:环境检查、版本适配、灰度发布与回滚实践
阿里云·云计算·部署·skills·ai能力接入·版本冲突
Coisinier2 天前
docker命令管理镜像及容器
linux·运维·nginx·docker·容器·操作系统
2301_32241428042 天前
基于web的校园失物招领管理系统59695-计算机毕设 原创(免费领源码+部署教程+开发环境)
mysql·nginx·php·apache·thinkphp·phpstudy·wampserver