12046 字
60 分钟
第 1 篇:Nginx 在后端架构中的位置

第 1 篇:Nginx 在后端架构中的位置——为什么它常被放在应用服务之前#

专栏:《Nginx 从入口代理到云原生流量治理》
文章序号:第 1 / 8 篇
写作与资料核验日期:2026-07-06
适用范围:Nginx Open Source 1.30.x 稳定版为主,核心原理同样适用于相邻主线版本
当前官方版本:稳定版 1.30.3,主线版 1.31.2
实验环境:Docker Compose、Nginx 1.30.3、Java 21、Spring Boot 4.0.x
说明:本文默认讨论 HTTP 入口层。TCP/UDP、TLS、缓存、负载均衡和 Kubernetes 会在后续文章进一步展开。


本文在专栏中的位置#

这是整个 Nginx 专栏的第一篇。

在学习 serverlocationproxy_passupstream、缓存和限流之前,首先必须回答一个更基础的问题:为什么一个已经能够监听 8080 端口并返回 HTTP 响应的 Spring Boot 服务,前面还要再放一层 Nginx?

如果不能回答这个问题,后续学习很容易退化成背配置:看到静态资源就写 root,看到转发就写 proxy_pass,看到多实例就写 upstream,但不知道每个能力处于请求链路的哪一层,也不知道什么时候应该使用 Nginx,什么时候应该交给云负载均衡器、API Gateway、CDN 或 Kubernetes Gateway。

本文先建立整体架构认知。下一篇将进入 Nginx 配置模型,系统讲解 main → events/http → server → location 的层级关系,以及一次请求如何匹配到具体配置。


学习目标#

完成本文后,你应该能够:

  1. 画出客户端访问后端系统时,从 DNS 到应用服务的完整请求链路;
  2. 解释为什么不建议让 Spring Boot 等应用进程直接承担所有公网入口职责;
  3. 准确区分正向代理与反向代理;
  4. 说明 Nginx 作为 Web Server、反向代理、负载均衡器、TLS 终止点和内容缓存时分别承担什么职责;
  5. 解释 Nginx Master/Worker 进程模型与事件驱动、非阻塞 I/O 的关系;
  6. 区分客户端到 Nginx 的连接和 Nginx 到后端服务的连接;
  7. 区分 Nginx、Spring Cloud Gateway、CDN、云负载均衡器和 Kubernetes Gateway 的职责边界;
  8. 使用 Docker Compose 启动一个“静态资源 + Nginx + Spring Boot”最小系统;
  9. 通过端口、响应头和日志验证请求究竟经过了哪些组件;
  10. 根据业务规模判断是否需要引入 Nginx,以及 Nginx 是否形成了新的单点。

一、从浏览器直接访问 Spring Boot 开始#

1.1 Spring Boot 已经能提供 HTTP 服务,为什么还要 Nginx#

一个最简单的 Spring Boot 应用可以监听 8080 端口:

http://server-ip:8080/api/hello

它能够:

  • 接收 HTTP 请求;
  • 执行 Controller、Service 和数据访问逻辑;
  • 返回 JSON;
  • 处理认证、事务和业务异常。

从“能不能运行”的角度,Nginx 并不是必需组件。开发环境、内部工具、小型服务或单机演示完全可以直接访问应用端口。

问题在于:应用服务器擅长执行业务,不等于它适合承担完整的互联网入口职责。

当系统从本地开发走向生产,会逐渐出现以下需求:

  • 用户希望通过 https://api.example.com 访问,而不是记住 10.0.1.25:8080
  • 前端静态文件、图片、下载文件不希望占用 Java 应用线程和堆内存;
  • 后端扩容为多个实例,需要在实例之间分配流量;
  • 证书应集中配置和续期,而不是散落在每个微服务中;
  • 希望统一记录访问日志、真实客户端 IP、耗时和上游状态;
  • 需要限制请求体大小、连接速率和恶意流量;
  • 应用升级或实例故障时,希望入口仍然稳定;
  • 对外只开放 80/443,隐藏内部端口和服务拓扑;
  • 需要同时代理 Java、Python、Node.js、对象存储等不同后端。

这些问题具有共同特征:它们大多属于入口层、连接层或通用流量处理问题,而不是订单、支付、用户、库存等业务逻辑。

因此,一种常见架构是:

客户端只访问 Nginx
Nginx 再决定:
- 直接返回静态文件;
- 将 API 请求转发到应用服务;
- 将请求分配到多个实例;
- 在入口处完成 TLS、日志、限流和缓存。

这就是 Nginx 经常位于应用服务之前的根本原因:把业务无关、重复出现、适合集中治理的入口能力,从应用进程中剥离出来。

1.2 直接暴露应用端口的主要问题#

问题一:公网入口与业务进程强耦合#

应用进程一旦重启,公网入口也随之中断。虽然任何服务重启都可能影响请求,但如果入口与业务完全绑定,就很难在后端多实例之间做平滑切换。

问题二:外部用户看见内部部署细节#

直接访问 :8080:8081:9000 会暴露端口规划。端口暴露本身不是漏洞,但会让外部访问方式与内部部署结构绑定,使迁移、扩容和重构更困难。

问题三:每个服务都重复实现通用能力#

如果有十个服务,每个服务都独立管理:

  • HTTPS 证书;
  • 安全响应头;
  • 访问日志;
  • 压缩;
  • 限流;
  • 跨域;
  • 静态资源;
  • 真实 IP 解析;

就会产生大量重复配置,而且各服务标准不一致。

问题四:静态资源与动态业务争夺资源#

Spring Boot 可以返回静态文件,但这意味着静态文件请求也会经过应用服务器的连接、过滤器和框架处理链。对于小项目影响不大;对于大量图片、前端构建产物和下载文件,专门的静态资源服务器或 CDN 通常更合适。

问题五:多实例缺少统一入口#

假设后端运行三个实例:

10.0.1.11:8080
10.0.1.12:8080
10.0.1.13:8080

客户端不应该自己维护这三个地址,更不应该负责检测实例故障。客户端只应访问稳定入口,由入口层选择可用后端。

1.3 什么时候可以不使用 Nginx#

Nginx 很常用,但不是任何项目都必须部署。

下面这些场景可以暂时不引入:

场景是否必须使用 Nginx原因
本地开发直接访问应用端口更简单
单人内部工具通常否没有公网入口和高可用要求
云平台已经提供完整入口不一定云 LB、API Gateway、CDN 可能已承担相同职责
Kubernetes 中已有 Gateway Controller不一定单独部署数据平面可能本身就是 Nginx、Envoy 或其他代理
Serverless/API 托管平台通常否平台已经管理 TLS、域名和路由
高度定制的业务网关仍可能需要,但位置不同Nginx 可放在业务网关前,也可能由云入口替代

判断标准不是“大家都用不用”,而是:你的请求链路中是否已经有组件承担了域名入口、TLS、路由、负载均衡、静态资源和基础流量治理。


二、Nginx 在完整请求链路中的位置#

2.1 一条典型的互联网请求链路#

Nginx 在后端架构中的位置

实际系统不一定拥有图中的所有层。例如:

  • 小型项目可能只有“客户端 → Nginx → Spring Boot”;
  • 云上项目可能是“客户端 → 云 LB → Nginx → 应用”;
  • Kubernetes 项目可能是“客户端 → 云 LB → Gateway Controller → Service → Pod”;
  • 使用 CDN 的静态站点可能在 CDN 命中后根本不会回源;
  • 采用托管 API Gateway 时,可能不再需要自建 Nginx。

2.2 每一层分别解决什么问题#

层次主要职责不应默认承担的职责
DNS将域名解析为可访问地址不执行 HTTP 路径路由,不理解业务接口
CDN边缘缓存、就近访问、回源保护不适合承载复杂业务事务
WAF基于规则识别和阻断 Web 攻击不能替代应用鉴权和业务校验
云负载均衡器提供公网 IP、多可用区入口、四层/七层转发通常不承载复杂业务过滤逻辑
Nginx反向代理、静态文件、TLS、基础路由、负载均衡、缓存、限流、日志不适合承担高度复杂、频繁变化的业务编排
API GatewayAPI 认证、路由、配额、协议适配、业务级插件不应替代领域服务本身
应用服务业务规则、数据一致性、事务、领域逻辑不宜重复承担所有入口基础设施能力
数据层持久化、缓存、消息传递不直接暴露给公网客户端

2.3 Nginx 常见部署位置#

位置一:直接作为公网入口#

Internet → Nginx → Application

适合单机、虚拟机、小规模自建环境。优点是简单;缺点是 Nginx 本身成为单点,需要额外设计高可用。

位置二:位于云负载均衡器之后#

Internet → Cloud Load Balancer → Nginx Cluster → Application

云 LB 提供公网 IP 和多可用区入口,Nginx 负责更细粒度的 HTTP 路由、静态资源和代理配置。

位置三:位于 API Gateway 之前#

Internet → Nginx → API Gateway → Microservices

Nginx 可承担 TLS、静态内容、基础限流和大连接处理;API Gateway 处理认证、服务发现、业务路由、熔断、灰度和插件扩展。

位置四:作为 Kubernetes Controller 的数据平面#

Internet → LoadBalancer Service → Gateway/Ingress Controller → Service → Pod

此时你可能不直接维护传统 nginx.conf,而是通过 Kubernetes API 对象声明路由,Controller 再生成或动态更新代理配置。

截至 2026 年,Kubernetes 官方已经明确建议新能力优先使用 Gateway API;Ingress API 仍然稳定可用,但已经冻结,不再继续扩展。这个话题会在第 8 篇详细展开。


三、正向代理与反向代理#

“正向”和“反向”不是指数据传输方向,而是指代理代表哪一方,以及哪一方知道真实目标

3.1 正向代理:代表客户端访问外部资源#

正向代理流程图

典型过程:

  1. 客户端知道自己配置了代理;
  2. 客户端把目标地址交给代理;
  3. 代理代表客户端访问目标服务器;
  4. 目标服务器看到的直接连接来源通常是代理。

常见用途:

  • 企业统一出口;
  • 网络访问控制;
  • 隐藏客户端来源;
  • 调试和抓包;
  • 访问特定网络资源。

3.2 反向代理:代表服务端接收客户端请求#

反向代理架构流程图

典型过程:

  1. 客户端只知道对外域名,例如 api.example.com
  2. 客户端连接 Nginx;
  3. Nginx 根据域名、路径、请求头或配置选择后端;
  4. 后端响应 Nginx;
  5. Nginx 再将响应返回客户端。

客户端通常不知道真实后端是:

  • 10.0.1.11:8080
  • 另一个容器;
  • 多个应用实例;
  • 一组 Kubernetes Pod;
  • 甚至不同语言实现的服务。

3.3 对比总结#

维度正向代理反向代理
代表对象客户端服务端
客户端是否感知代理通常感知并主动配置通常只把代理当作目标服务器
真实目标是否对客户端透明不一定通常透明
主要用途统一出口、访问控制、客户端匿名服务入口、路由、负载均衡、TLS、缓存
Nginx 常见角色可以实现部分场景,但不是最主要使用方式最典型角色之一

四、Nginx 可以承担哪些职责#

Nginx 官方将其定位为 HTTP Web Server、反向代理、内容缓存、负载均衡器、TCP/UDP 代理和邮件代理。对后端开发者而言,最重要的是以下几类能力。

4.1 Web Server:直接处理 HTTP 请求#

Nginx 本身就是 Web 服务器,不是“只能把请求转发给别人”的中间件。

它可以直接:

  • 监听端口;
  • 匹配域名和 URI;
  • 返回状态码;
  • 返回本地文件;
  • 处理重定向;
  • 添加响应头;
  • 记录访问日志。

例如:

server {
listen 80;
server_name example.com;
location = /health {
return 200 "ok\n";
}
}

访问 /health 时,请求不会进入 Spring Boot,Nginx 会直接生成响应。

4.2 静态资源服务器#

Nginx 可直接从文件系统读取并返回:

  • HTML;
  • CSS;
  • JavaScript;
  • 图片;
  • 字体;
  • 安装包和下载文件。

典型结构:

location / → 返回前端构建产物
location /assets/ → 返回带 Hash 的静态资源
location /api/ → 转发到 Spring Boot

好处是静态资源请求不必进入 Java MVC 处理链,也可以独立配置浏览器缓存、压缩和访问日志。

对于大规模互联网分发,CDN 通常比单个 Nginx 更适合;但 Nginx 仍然可以作为 CDN 的源站或内部静态资源服务器。

4.3 反向代理#

反向代理是后端系统中最常见的 Nginx 用途。

location /api/ {
proxy_pass http://backend:8080;
}

Nginx 接收客户端请求,再创建或复用另一条到后端的连接。

这里必须建立一个重要认知:

连接 1:Client ↔ Nginx
连接 2:Nginx ↔ Spring Boot

它们不是同一条 TCP 连接。Nginx 是两条连接的终点和起点:

  • 对客户端而言,Nginx 是服务器;
  • 对后端而言,Nginx 是客户端。

因此,两侧可以拥有不同的:

  • HTTP 版本;
  • TLS 状态;
  • Keep-Alive 生命周期;
  • 超时时间;
  • 缓冲策略;
  • 请求头;
  • 源 IP 表现。

后续讨论 proxy_set_header、真实 IP、超时和 upstream keepalive 时,都建立在这个连接模型之上。

4.4 负载均衡器#

当一个服务有多个实例时,Nginx 可以将请求分配给一组后端:

upstream backend_cluster {
server backend-a:8080;
server backend-b:8080;
server backend-c:8080;
}
server {
listen 80;
location /api/ {
proxy_pass http://backend_cluster;
}
}

Nginx Open Source 支持常见的轮询、最少连接、IP Hash 和通用 Hash 等方法。默认未显式指定算法时,HTTP upstream 使用轮询思想分配请求。

需要注意:

  • “分发请求”不等于“业务高可用已经完成”;
  • 后端故障检测、重试和非幂等请求风险需要专门设计;
  • 单个 Nginx 仍然可能是单点;
  • Nginx Open Source 的被动故障判断与 NGINX Plus 的主动健康检查能力不能混写。

这些内容会在第 4 篇展开。

4.5 TLS 终止点#

Client --HTTPS--> Nginx --HTTP/HTTPS--> Backend

Nginx 可以在入口处:

  • 加载证书和私钥;
  • 完成 TLS 握手;
  • 选择域名证书;
  • 将解密后的 HTTP 请求转发给内部服务;
  • 或者再次使用 HTTPS 连接后端。

把 TLS 集中在入口层,可以减少每个应用重复管理证书的成本。但是否允许 Nginx 到后端使用明文 HTTP,要根据网络边界、合规要求和威胁模型决定,不能简单认为“内网就一定安全”。

4.6 内容缓存#

Nginx 可以缓存后端响应:

第一次请求:Client → Nginx → Backend
后续命中:Client → Nginx Cache

缓存能够减少后端压力和响应延迟,但必须区分:

  • 浏览器缓存;
  • CDN 缓存;
  • Nginx 代理缓存;
  • 应用内缓存;
  • Redis 等数据缓存。

包含用户身份、Cookie、Authorization 或个性化数据的响应不能在没有完整缓存键与隔离策略的情况下共享缓存。

4.7 基础流量治理和可观测性#

Nginx 还常用于:

  • 请求速率限制;
  • 并发连接限制;
  • 请求体大小限制;
  • 超时控制;
  • 基于域名和路径的路由;
  • 统一 Access Log;
  • 透传 Request ID;
  • 记录 upstream 地址、状态和耗时;
  • 返回统一错误页。

这些能力适合处理与单个业务领域无关的通用入口问题。


五、为什么 Nginx 能处理大量并发连接#

5.1 Master 与 Worker 进程模型#

典型 Nginx 进程结构如下:

Nginx Master Worker 模型图

Master 进程主要负责#

  • 读取并校验配置;
  • 创建监听套接字;
  • 启动和维护 Worker;
  • 接收停止、重载等信号;
  • 在配置重载时创建新 Worker,并通知旧 Worker 优雅退出。

Worker 进程主要负责#

  • 接受连接;
  • 读取请求;
  • 执行 HTTP 处理阶段;
  • 访问文件;
  • 连接 upstream;
  • 发送响应;
  • 记录日志。

官方入门文档明确说明:Nginx 通常由一个 Master 和多个 Worker 组成;Master 负责读取、评估配置并维护 Worker,真正的请求处理由 Worker 完成。

5.2 事件驱动不是“没有进程或线程”#

Nginx 仍然运行在操作系统进程中。所谓事件驱动,指的是一个 Worker 不会为每个连接都长期占用一个独立线程并阻塞等待。

可以把网络请求理解成许多同时进行的状态机:

连接 A:等待客户端发送请求体
连接 B:等待后端返回数据
连接 C:等待套接字可写
连接 D:读取本地文件
连接 E:已经可以继续解析请求头

Worker 会处理当前“已经就绪”的事件,而不是在连接 A 尚未发送完数据时一直停在那里。

在 Linux 上,Nginx 通常利用 epoll 等操作系统事件通知机制:

  1. Worker 将大量套接字交给内核监控;
  2. 内核通知哪些套接字已经可读、可写或发生错误;
  3. Worker 处理这些就绪事件;
  4. 某个连接需要继续等待时,Worker 转去处理其他连接。

5.3 非阻塞 I/O 解决什么问题#

传统“一连接一线程”模型中,如果线程正在等待慢客户端、慢后端或网络数据,线程本身仍然占用栈空间和调度资源。

非阻塞事件模型的目标是:

  • 减少大量连接对应的大量线程;
  • 降低上下文切换;
  • 让少量 Worker 管理大量处于不同等待状态的连接;
  • 在慢连接较多时保持更可控的资源开销。

这并不意味着 Nginx 的任何操作都天然不会阻塞。如果在 Worker 中引入阻塞式第三方模块、同步磁盘操作或耗时脚本,仍可能阻塞该 Worker,影响它管理的其他连接。

5.4 worker_processes auto 的意义#

常见配置:

worker_processes auto;

它让 Nginx 根据可见 CPU 资源选择 Worker 数量。常见经验是使 Worker 数量接近可用 CPU 核心数,以减少不必要的进程调度,同时让多个核心并行处理事件。

但“Worker 数量 = CPU 核数”不是所有场景的绝对最优公式,还会受到以下因素影响:

  • 容器 CPU 限额;
  • CPU 亲和性;
  • 磁盘 I/O;
  • TLS 开销;
  • 第三方模块;
  • NUMA;
  • 实际压测结果。

5.5 Nginx 与应用服务器不是替代关系#

Nginx 的事件模型擅长连接、代理、文件和通用流量处理;Spring Boot 擅长:

  • 业务对象建模;
  • 事务;
  • 数据访问;
  • 认证授权;
  • 复杂业务规则;
  • 领域服务编排。

不要因为 Nginx 能高效处理连接,就试图把复杂业务全部塞进入口配置或脚本。正确关系通常是:

Nginx 管入口和流量
Application 管业务和数据一致性

六、配置加载与优雅重载#

Nginx 被广泛用于入口层的另一个原因,是它支持较成熟的配置重载机制。

6.1 重载过程#

执行:

Terminal window
nginx -t
nginx -s reload

典型过程如下:

Nginx Reload 时序图

官方文档说明,Master 在收到重载信号后会验证新配置;成功时启动新 Worker 并要求旧 Worker 停止接收新连接,旧 Worker 会继续服务已有请求,完成后退出;失败时继续使用旧配置。

6.2 “优雅重载”不等于永远零风险#

仍需注意:

  • 配置语法正确不代表业务路由正确;
  • 长时间 WebSocket、SSE 或下载连接会让旧 Worker 长期存在;
  • 频繁 reload 可能积累多代旧 Worker;
  • 新配置引用的证书、文件、DNS 和后端地址可能在运行时失败;
  • 容器编排平台可能直接替换整个 Pod,而不是原地 reload;
  • 必须设计配置发布、验证、监控和回滚流程。

因此生产流程至少应是:

编辑配置
→ 静态检查
→ nginx -t
→ 测试环境验证
→ 灰度发布
→ reload
→ 观察错误率和延迟
→ 必要时回滚

七、Nginx 与其他入口组件的边界#

7.1 Nginx 与 Spring Cloud Gateway#

Spring Cloud Gateway 官方将自身定位为构建在 Spring 生态之上的 API Gateway,重点是 API 路由以及安全、监控和弹性等横切能力。

维度NginxSpring Cloud Gateway
实现语言/运行时C,独立进程Java,基于 Spring 生态
强项高效连接处理、静态资源、反向代理、TLS、缓存、基础负载均衡服务发现、Java 过滤器、认证集成、业务化路由、Spring 生态扩展
配置方式Nginx 指令与模块Java/YAML、Predicate、Filter
业务扩展不适合写大量复杂业务逻辑更适合与 Java 业务组件集成
静态文件与边缘连接非常常见通常不是核心定位
典型位置最外层或基础代理层API 业务网关层

两者可以组合:

Client → Nginx → Spring Cloud Gateway → Microservices

但不要为了“架构完整”机械增加层数。每增加一层都会增加:

  • 网络跳数;
  • 配置复杂度;
  • 故障点;
  • 日志关联难度;
  • 运维成本。

7.2 Nginx 与 API Gateway#

“API Gateway”是架构角色,不是某个固定产品。Nginx 可以承担部分 API Gateway 能力,但完整 API Gateway 往往还包括:

  • API Key/OAuth/JWT 认证;
  • 租户配额;
  • 开发者门户;
  • API 生命周期管理;
  • 协议转换;
  • 复杂插件体系;
  • 服务发现;
  • 业务级审计;
  • 消费者管理。

如果系统只需要域名、路径路由、TLS 和简单限流,Nginx 可能已经足够;如果需要大量动态业务策略和平台化治理,应评估专门的 API Gateway。

7.3 Nginx 与云负载均衡器#

云负载均衡器通常提供:

  • 稳定公网 IP;
  • 多可用区;
  • 托管高可用;
  • 四层或七层负载均衡;
  • 与云安全组、证书和监控集成。

Nginx 则提供更可控、更细粒度的代理和内容处理能力。

常见组合:

Cloud LB → 多台 Nginx → 多个应用实例

云 LB 解决 Nginx 节点自身的高可用入口,Nginx 解决应用层的详细路由和治理。

7.4 Nginx 与 CDN#

CDN 的关键价值是将内容缓存到离用户更近的边缘节点。

Client → Nearby CDN Edge → Origin Nginx → Application

Nginx 即使性能很好,也无法改变物理距离。跨国家或跨洲访问时,CDN 的边缘网络和专线回源能力通常更有价值。

合理分工:

  • CDN:大范围边缘分发、DDoS/WAF、静态缓存;
  • Nginx:源站入口、回源控制、动态代理、内部路由。

7.5 Nginx 与 Kubernetes Ingress/Gateway#

必须区分三个概念:

  1. Ingress/Gateway API 对象:声明“流量应该如何进入集群”;
  2. Controller:监听这些 API 对象并将其转化为真实配置;
  3. 数据平面代理:真正接收连接和转发流量,可能是 Nginx、Envoy、HAProxy 或云厂商负载均衡器。

所以“Ingress 是不是 Nginx”这个问题本身不准确。Ingress 是 API;某个 Ingress Controller 可能使用 Nginx 作为数据平面。

截至 2026 年,Kubernetes 官方建议优先评估 Gateway API,Ingress API 保持稳定但已冻结。新项目应根据 Controller 维护状态、Gateway API 一致性和迁移成本选择方案,而不是只搜索一份旧的 ingress-nginx YAML 就直接用于生产。

7.6 Nginx 与 Service Mesh#

Service Mesh 主要面向服务之间的东西向流量:

Service A → Sidecar/Node Proxy → Service B

Nginx 常见的入口代理主要面向南北向流量:

External Client → Nginx → Internal Service

两者可以同时存在。是否需要 Mesh 取决于:

  • 服务数量;
  • mTLS;
  • 流量策略;
  • 可观测性;
  • 多集群;
  • 团队运维能力。

不要把 Nginx 入口层和 Service Mesh 简单理解成互斥替代。


八、最小可运行实验#

本实验完成两件事:

  1. Nginx 直接返回静态首页;
  2. Nginx 将 /api/ 请求转发给 Spring Boot。

8.1 最终请求链路#

最小实验请求链路流程图

外部只映射 Nginx 的 8088 端口。Spring Boot 只在 Docker 内部网络暴露 8080,不直接映射到宿主机。

8.2 目录结构#

nginx-column-demo/
├── docker-compose.yml
├── nginx/
│ ├── nginx.conf
│ ├── conf.d/
│ │ └── default.conf
│ └── html/
│ └── index.html
└── backend/
├── Dockerfile
├── pom.xml
└── src/
└── main/
└── java/
└── com/example/demo/
├── DemoApplication.java
└── HelloController.java

8.3 docker-compose.yml#

services:
backend:
build:
context: ./backend
container_name: nginx-column-backend
expose:
- "8080"
environment:
SERVER_PORT: "8080"
networks:
- nginx-lab
nginx:
image: nginx:1.30.3-alpine3.23
container_name: nginx-column-entry
depends_on:
- backend
ports:
- "8088:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./nginx/html:/usr/share/nginx/html:ro
networks:
- nginx-lab
networks:
nginx-lab:
driver: bridge

说明:

  • 使用固定镜像 nginx:1.30.3-alpine3.23,避免 latest 随时间变化;
  • backend 只使用 expose 声明容器内端口,不映射到宿主机;
  • nginx 映射宿主机 8088 到容器 80
  • 两个容器加入同一个 Compose 网络;
  • Nginx 可以通过服务名 backend 使用 Docker DNS 找到后端;
  • depends_on 只表达启动依赖顺序,不等价于“后端业务已经健康”,生产环境应配合健康检查和重试边界。

8.4 nginx/nginx.conf#

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'request_time=$request_time '
'upstream_addr=$upstream_addr '
'upstream_status=$upstream_status '
'upstream_time=$upstream_response_time';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}

8.5 nginx/conf.d/default.conf#

server {
listen 80;
server_name _;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /api/ {
proxy_pass http://backend:8080;
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;
add_header X-Entry-Proxy nginx always;
}
location = /nginx-health {
access_log off;
default_type text/plain;
return 200 "nginx ok\n";
}
}

本文只解释整体职责,不深入分析 location 匹配和 proxy_pass URI 改写;它们分别是第 2、3 篇的重点。

8.6 nginx/html/index.html#

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nginx 专栏实验</title>
</head>
<body>
<h1>Nginx 静态资源响应成功</h1>
<p>这个页面由 Nginx 直接从文件系统返回,没有经过 Spring Boot。</p>
<p><a href="/api/hello">访问后端 API</a></p>
</body>
</html>

8.7 backend/pom.xml#

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.2</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>nginx-column-backend</artifactId>
<version>1.0.0</version>
<name>nginx-column-backend</name>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

说明:示例使用 Spring Boot 4.0.2 与 Java 21。若你的本地依赖仓库尚未同步该版本,可改为组织内已经验证的 Spring Boot 4.0.x 版本;这不影响 Nginx 实验的核心逻辑。

8.8 DemoApplication.java#

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

8.9 HelloController.java#

package com.example.demo;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.net.InetAddress;
import java.util.LinkedHashMap;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class HelloController {
@GetMapping("/hello")
public Map<String, Object> hello(HttpServletRequest request) throws Exception {
Map<String, Object> result = new LinkedHashMap<>();
result.put("message", "hello from Spring Boot");
result.put("instance", InetAddress.getLocalHost().getHostName());
result.put("serverPort", request.getLocalPort());
result.put("remoteAddrSeenByBackend", request.getRemoteAddr());
result.put("host", request.getHeader("Host"));
result.put("xRealIp", request.getHeader("X-Real-IP"));
result.put("xForwardedFor", request.getHeader("X-Forwarded-For"));
result.put("xForwardedProto", request.getHeader("X-Forwarded-Proto"));
return result;
}
}

8.10 backend/Dockerfile#

FROM maven:3.9.11-eclipse-temurin-21-alpine AS builder
WORKDIR /workspace
COPY pom.xml ./
COPY src ./src
RUN mvn -B -DskipTests package
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /workspace/target/nginx-column-backend-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

8.11 启动实验#

在项目根目录执行:

Terminal window
docker compose config
docker compose build
docker compose up -d

查看状态:

Terminal window
docker compose ps

查看日志:

Terminal window
docker compose logs -f nginx backend

8.12 配置检查#

Terminal window
docker compose exec nginx nginx -t

预期输出包含:

syntax is ok
test is successful

查看 Nginx 实际加载的完整配置:

Terminal window
docker compose exec nginx nginx -T

nginx -T 比只查看某个配置文件更可靠,因为它会展开 include 后打印当前完整配置。

8.13 验证静态资源#

Terminal window
curl -i http://localhost:8088/

预期:

  • 状态码 200
  • Content-Type 为 HTML;
  • 响应体包含“Nginx 静态资源响应成功”;
  • Spring Boot 日志中不会出现对应 Controller 请求。

这证明请求由 Nginx 直接完成。

8.14 验证 Nginx 自身健康接口#

Terminal window
curl -i http://localhost:8088/nginx-health

预期响应:

HTTP/1.1 200 OK
...
nginx ok

该请求也不会到达 Spring Boot。

8.15 验证反向代理#

Terminal window
curl -i http://localhost:8088/api/hello

预期响应头包含:

X-Entry-Proxy: nginx

响应体类似:

{
"message": "hello from Spring Boot",
"instance": "2d7f...",
"serverPort": 8080,
"remoteAddrSeenByBackend": "172.20.0.3",
"host": "localhost",
"xRealIp": "172.20.0.1",
"xForwardedFor": "172.20.0.1",
"xForwardedProto": "http"
}

不同环境的容器 IP 会不同。

此结果说明:

  1. 客户端连接的是宿主机 8088
  2. 宿主机端口转发到 Nginx 容器 80
  3. Nginx 再连接 backend:8080
  4. Spring Boot 看到的直接网络来源是 Nginx 容器,而不是原始客户端;
  5. 原始客户端信息需要通过受控的代理 Header 传递。

8.16 证明后端没有直接暴露给宿主机#

执行:

Terminal window
curl -i http://localhost:8080/api/hello

正常情况下应连接失败,因为 Compose 没有将 backend 的 8080 映射到宿主机。

这就是“隐藏内部应用端口”的最小示例。注意:它只是 Docker 网络隔离,不等同于完整安全体系;生产环境还需要安全组、防火墙、网络策略和身份认证。

8.17 查看访问日志#

Terminal window
docker compose exec nginx tail -f /var/log/nginx/access.log

再次请求:

Terminal window
curl http://localhost:8088/api/hello

可以观察:

  • 请求方法和 URI;
  • Nginx 返回状态码;
  • 总请求时间;
  • upstream 地址;
  • upstream 状态码;
  • upstream 响应时间。

这体现了入口层集中日志的价值。

8.18 停止与清理#

Terminal window
docker compose down --remove-orphans

如需同时删除本实验构建的镜像:

Terminal window
docker compose down --rmi local --remove-orphans

九、配置逐段解释:一次请求到底发生了什么#

9.1 请求 /#

curl localhost:8088/
宿主机 8088 映射至 Nginx 容器 80
命中 server { listen 80; }
命中 location /
Nginx 从 /usr/share/nginx/html 读取 index.html
Nginx 直接返回文件

Spring Boot 完全不参与。

9.2 请求 /api/hello#

curl localhost:8088/api/hello
Client 与 Nginx 建立连接
Nginx 匹配 location /api/
Nginx 解析 Docker DNS 名称 backend
Nginx 与 backend:8080 建立另一条连接
Spring Boot 返回 JSON 给 Nginx
Nginx 添加 X-Entry-Proxy 响应头
Nginx 返回响应给 Client

9.3 两条连接的状态对照#

项目客户端侧连接upstream 侧连接
两端Client ↔ NginxNginx ↔ Spring Boot
Nginx 的角色服务端客户端
目标端口Nginx 80(宿主机映射为 8088)Spring Boot 8080
真实源地址Nginx 可见客户端/上一跳地址Spring Boot 通常只直接看到 Nginx 地址
TLS可以是 HTTPS可以独立选择 HTTP 或 HTTPS
Keep-Alive客户端侧独立管理upstream 侧独立管理
超时客户端读写相关超时proxy connect/send/read 等超时

这一张表是理解后续代理配置的基础。


十、从开发配置升级到生产架构#

上面的实验只证明链路可运行,不是完整生产配置。

10.1 第一阶段:最小可运行#

能力:

  • 静态文件;
  • 单后端代理;
  • 基础访问日志;
  • 固定 Nginx 镜像版本。

缺失:

  • HTTPS;
  • 多实例;
  • 健康检查;
  • 限流;
  • 缓存;
  • 安全加固;
  • 日志采集;
  • 监控和告警;
  • Nginx 自身高可用。

10.2 第二阶段:统一入口#

增加:

  • 正式域名;
  • 默认拒绝未知 Host;
  • TLS 证书;
  • 安全响应头;
  • 请求体大小;
  • 统一错误页;
  • 真实 IP 信任边界。

10.3 第三阶段:后端多实例#

增加:

  • upstream
  • 负载均衡算法;
  • upstream keepalive;
  • 被动故障判断;
  • 安全的重试边界;
  • 应用幂等机制。

10.4 第四阶段:性能与保护#

增加:

  • 静态资源缓存;
  • gzip/Brotli 评估;
  • proxy cache;
  • 请求限流;
  • 连接限制;
  • 超时分层;
  • 大文件和流式接口策略。

10.5 第五阶段:可观测与发布#

增加:

  • JSON 结构化日志;
  • Request ID / Trace ID;
  • Nginx 指标;
  • upstream 延迟监控;
  • 4xx/5xx 告警;
  • 配置版本管理;
  • 自动 nginx -t
  • 灰度、回滚和变更审计。

10.6 第六阶段:入口高可用#

单个 Nginx 容器或虚拟机仍然是单点。可选方案包括:

  • 云负载均衡器 + 多个 Nginx;
  • Keepalived + 双节点虚拟 IP;
  • Kubernetes Deployment + Service/Gateway;
  • DNS 多记录配合外部健康检查;
  • 托管 API Gateway 或边缘平台。

生产架构不能只考虑“后端有几个实例”,还要考虑“入口本身是否可用”。


十一、常见错误与反例#

11.1 错误一:认为用了 Nginx 就自动高可用#

错误现象#

后端部署了三个实例,但 Nginx 主机故障后整个网站不可访问。

根本原因#

Nginx 解决了后端流量分配,却成为唯一入口。后端多实例不等于入口多实例。

修复方向#

在 Nginx 前增加高可用入口,或部署多个 Nginx 并使用云 LB、虚拟 IP 或 Kubernetes Service 暴露。

验证方式#

主动停止一台入口节点,检查:

  • DNS 或公网 IP 是否仍可访问;
  • 新连接是否切换到其他入口;
  • 已有连接如何处理;
  • 监控是否及时告警。

11.2 错误二:把 Nginx 当成业务服务替代品#

错误现象#

在大量 ifmap、rewrite 或脚本中实现复杂用户权限、订单状态和业务编排,配置越来越难维护。

根本原因#

把入口层的声明式请求处理能力,当成通用业务编程平台。

修复方向#

Nginx 保留稳定的通用流量逻辑;复杂认证、领域规则和事务放回 API Gateway 或应用服务。

11.3 错误三:认为反向代理只是“透明转发同一条连接”#

错误现象#

无法解释为什么后端看到的源 IP 是 Nginx,或者为什么客户端 HTTPS 而后端却是 HTTP。

根本原因#

忽略了 Client ↔ Nginx 和 Nginx ↔ Backend 是两条独立连接。

修复方向#

按照双连接模型配置真实 IP、Header、TLS、Keep-Alive 和超时。

11.4 错误四:直接信任客户端传入的 X-Forwarded-For#

错误现象#

攻击者自行构造 Header,伪造来源 IP,导致审计、限流或风控失真。

根本原因#

代理 Header 只是 HTTP 字段,客户端也可以发送。只有由受信任代理写入或追加的部分才可信。

修复方向#

  • 明确受信任代理链;
  • 在边界代理处覆盖或规范化 Header;
  • 使用 Real IP 模块时严格限制 set_real_ip_from
  • 不要对所有来源无条件信任代理协议或 Header。

11.5 错误五:所有流量都经过应用服务#

错误现象#

图片、JS、CSS、健康检查都进入 Spring Boot,增加应用连接和日志噪声。

根本原因#

没有按内容类型和路径划分职责。

修复方向#

  • 可缓存静态内容交给 CDN/Nginx/对象存储;
  • 简单入口健康检查由 Nginx 直接返回;
  • 业务健康检查仍由应用暴露并由监控系统调用。

11.6 错误六:为了“层次完整”同时部署太多网关#

错误现象#

请求经过 CDN、云 LB、Nginx、WAF、API Gateway、Ingress、Service Mesh,每层都做部分重试、限流和 Header 改写,故障难以定位。

根本原因#

没有定义每层唯一职责,重复建设相同能力。

修复方向#

建立入口能力矩阵,明确每项能力的唯一主要责任层,例如:

能力主要责任层
全球静态缓存CDN
公网高可用 IP云 LB
源站静态文件/基础代理Nginx
API 身份与业务配额API Gateway
领域鉴权与事务应用服务
服务间 mTLSService Mesh

11.7 错误七:修改配置后只看文件,不检查实际加载结果#

错误现象#

文件已经改了,请求行为却没有变化。

可能原因#

  • 没有 reload;
  • 修改了错误文件;
  • include 没有包含该路径;
  • 容器挂载路径不对;
  • reload 失败后仍使用旧配置;
  • 请求实际进入另一台 Nginx。

修复方式#

Terminal window
nginx -t
nginx -T
ps -ef | grep nginx
curl -v http://target

同时检查 error log 和发布日志。


十二、故障排查流程#

12.1 标准排查路径#

Nginx 故障排查流程图

12.2 第一步:确认客户端到入口#

Terminal window
curl -v http://localhost:8088/nginx-health

关注:

  • DNS 解析结果;
  • 连接的 IP 和端口;
  • TCP 是否成功;
  • HTTP 状态码;
  • 响应头是否能证明请求经过目标入口。

12.3 第二步:确认 Nginx 正在运行#

Terminal window
docker compose ps
docker compose logs nginx

非容器环境:

Terminal window
ps -ef | grep nginx
ss -lntp | grep nginx

12.4 第三步:确认实际配置#

Terminal window
docker compose exec nginx nginx -t
docker compose exec nginx nginx -T

不要只根据编辑器中的文件判断。

12.5 第四步:确认 Nginx 能访问后端#

进入 Nginx 容器:

Terminal window
docker compose exec nginx sh

Alpine 镜像可能没有 curl,可使用 wget

Terminal window
wget -qO- http://backend:8080/api/hello

如果容器内可以访问,而从外部通过 Nginx 不行,重点检查 Nginx 路由与代理配置;如果容器内也不能访问,重点检查 Docker DNS、网络、端口和应用状态。

12.6 第五步:区分 Nginx 状态码与后端状态码#

访问日志中建议同时记录:

  • $status:Nginx 最终返回客户端的状态;
  • $upstream_status:上游返回状态,可能包含多次尝试;
  • $request_time:入口观察到的总时间;
  • $upstream_response_time:上游响应时间。

例如:

  • $status=502$upstream_status=-:可能根本没连上后端;
  • $status=500$upstream_status=500:后端明确返回 500;
  • $status=504:常见于等待 upstream 超时;
  • $status=404$upstream_status=-:可能由 Nginx 本地路由或文件查找产生;
  • $status=404$upstream_status=404:后端返回 404。

十三、生产实践与能力边界#

13.1 什么规模下 Nginx 足够#

下面的系统通常可以从 Nginx 开始:

  • 单体应用或少量服务;
  • 固定域名和路径路由;
  • 简单 TLS 和静态资源;
  • 少量后端实例;
  • 团队能够维护 Linux 和配置文件;
  • 不需要复杂 API 生命周期平台。

13.2 什么时候需要 CDN#

  • 大量静态资源;
  • 用户分布跨地区;
  • 源站带宽压力大;
  • 希望边缘缓存和 DDoS/WAF 能力;
  • 下载、图片、视频等内容分发占比高。

13.3 什么时候需要云负载均衡器#

  • Nginx 节点不止一台;
  • 需要托管公网 IP;
  • 需要多可用区高可用;
  • 不希望自己维护 Keepalived 和公网故障切换;
  • 需要与云证书、安全组、监控体系集成。

13.4 什么时候需要 API Gateway#

  • 多租户与消费者管理;
  • OAuth/JWT/API Key 集中认证;
  • 复杂配额与计费;
  • 动态服务发现;
  • 插件化协议转换;
  • 开发者门户和 API 生命周期治理;
  • 路由规则频繁由平台动态下发。

13.5 什么情况下 Nginx 不应承担该职责#

  • 复杂订单状态机;
  • 领域事务;
  • 细粒度数据权限;
  • 用户画像和实时风控决策;
  • 需要数据库事务的业务编排;
  • 大量可测试、可演进的业务代码。

这些逻辑应留在应用或专门的业务网关中。

13.6 Nginx 的核心价值总结#

Nginx 的价值不是“多加一层”,而是建立清晰边界:

公网与内部服务之间的边界
静态内容与动态业务之间的边界
通用流量治理与领域逻辑之间的边界
客户端连接与应用连接之间的边界
单一稳定入口与内部可变拓扑之间的边界

十四、架构选择决策表#

问题
是否需要统一域名和 80/443 入口评估 Nginx/云 LB/Gateway可直接访问应用
是否需要直接返回静态资源Nginx/CDN/对象存储仅代理 API 即可
是否有多个应用实例需要负载均衡层单实例代理即可
是否需要托管公网高可用优先云 LB 或托管入口可自建 Nginx
是否需要复杂 API 认证和业务插件引入 API GatewayNginx 基础能力可能足够
是否在 Kubernetes 新建入口优先评估 Gateway API 实现传统虚拟机 Nginx 即可
是否有全球静态用户引入 CDN源站 Nginx 可能足够
是否存在服务间流量治理需求评估 Mesh/Gateway只做南北向入口
是否能容忍单个入口故障单 Nginx 可暂用部署入口高可用

十五、面试与复习问题#

15.1 核心问题#

1. Spring Boot 已经能监听 HTTP 端口,为什么还要 Nginx?#

**答案:**因为应用服务器主要负责业务逻辑,而 Nginx 可以集中承担域名入口、TLS、静态文件、反向代理、负载均衡、缓存、基础限流和访问日志等通用流量能力,从而隐藏内部拓扑、减少重复建设并提升入口可治理性。但小型或托管环境不一定必须使用 Nginx。

2. 正向代理和反向代理的核心区别是什么?#

**答案:**正向代理代表客户端访问目标,客户端通常知道代理;反向代理代表服务端接收请求,客户端通常只知道代理入口,不知道真实后端。

3. 客户端到 Nginx 与 Nginx 到后端是不是同一条连接?#

**答案:**不是。Nginx 终止客户端连接,再作为客户端建立或复用 upstream 连接。两侧的 HTTP 版本、TLS、Keep-Alive、Header、超时和缓冲都可以独立配置。

4. Nginx 的 Master 进程负责什么?#

**答案:**主要负责读取和校验配置、创建和管理 Worker、处理控制信号,以及在重载时启动新 Worker、通知旧 Worker 优雅退出。真正处理请求的是 Worker。

5. 什么是事件驱动模型?#

**答案:**Worker 同时管理大量连接,将等待网络事件的套接字交给操作系统监控,只在连接可读、可写或发生错误时继续处理,而不是为每个连接长期阻塞一个线程。

6. 使用 Nginx 后是否自动实现高可用?#

**答案:**没有。Nginx 可以把流量分给多个后端,但单个 Nginx 本身仍可能是单点。需要通过云 LB、多节点、虚拟 IP 或 Kubernetes 等方式保障入口高可用。

7. Nginx 和 API Gateway 有什么区别?#

**答案:**Nginx 强于连接处理、反向代理、TLS、静态资源、缓存和基础流量控制;完整 API Gateway 更强调消费者、认证、配额、协议转换、服务发现、插件和 API 生命周期。Nginx 可以承担部分网关职责,但不必强行替代完整 API 管理平台。

8. Nginx 和 CDN 能互相替代吗?#

**答案:**不能完全替代。CDN 的优势是全球边缘节点和就近缓存,Nginx 更常作为源站入口或内部代理。两者可以协作。

9. 为什么后端看到的客户端 IP常常是 Nginx IP?#

**答案:**因为后端 TCP 连接由 Nginx 发起。原始客户端地址需要由受信任代理通过 X-Forwarded-ForX-Real-IP 或 PROXY Protocol 等机制传递,并建立严格信任边界。

10. Ingress 是否等于 Nginx?#

**答案:**不等于。Ingress 是 Kubernetes API 对象;Controller 负责实现它;数据平面可能使用 Nginx,也可能使用 Envoy、HAProxy 或云负载均衡器。新项目还应评估 Gateway API。

15.2 场景分析题#

场景 1:只有一个内部管理后台,是否需要 Nginx?#

**参考答案:**不一定。若只在可信内网使用、单实例、无 TLS 集中管理和静态资源需求,直接访问 Spring Boot 即可。若需要统一域名、证书、访问日志或未来扩容,可以引入 Nginx。

场景 2:已经使用云负载均衡器,还需要 Nginx 吗?#

**参考答案:**取决于云 LB 是否已经满足路径路由、TLS、静态资源、缓存、Header 改写、细粒度日志和发布需求。若满足,可减少一层;若需要更可控的源站代理配置,可以在云 LB 后部署 Nginx 集群。

场景 3:前端是 Vue,后端是 Spring Boot,如何划分?#

**参考答案:**常见做法是由 CDN/Nginx 返回前端构建产物,将 /api/ 转发给 Spring Boot。前端资源与后端 API 可使用同域名,减少部署分散;生产中还要配置缓存、TLS、CORS 边界和 SPA 路由。

场景 4:系统需要 JWT 鉴权,应该放 Nginx 还是应用?#

**参考答案:**简单、统一、稳定的入口校验可以由网关层承担,但领域权限和数据权限必须在应用中再次保证。是否由原生 Nginx 实现取决于模块、动态规则和维护成本;复杂鉴权通常更适合 API Gateway 或应用安全框架。

场景 5:Nginx 后面有三个应用实例,为什么用户仍然偶发失败?#

**参考答案:**负载均衡只是基础。还需检查后端健康、连接超时、重试边界、非幂等请求、会话状态、数据库依赖、Nginx 自身单点,以及应用实例是否真正无状态。

15.3 配置排错题#

排错题 1:修改 default.conf 后行为没有变化#

**排查答案:**执行 nginx -tnginx -T,确认文件被 include;检查是否 reload 成功;确认挂载路径;确认请求是否进入了另一台入口;查看 error log 是否因语法错误继续使用旧配置。

排错题 2:Nginx 健康接口正常,但 /api/hello 返回 502#

**排查答案:**说明客户端到 Nginx 基本正常,问题集中在 Nginx 到后端。检查 Docker DNS backend、后端端口、应用进程、网络、连接拒绝日志和 proxy_pass 地址。

排错题 3:后端日志中的来源 IP 都是容器地址#

**排查答案:**这是反向代理双连接模型的正常表现。需要由 Nginx设置并由应用正确解析受信任的转发 Header;同时不能无条件信任客户端自行提供的 Header。


十六、本文总结#

本文解决的核心问题不是“如何写一段 proxy_pass”,而是建立 Nginx 的架构坐标。

一次典型请求可能经历:

Client
→ DNS
→ CDN/WAF
→ Cloud Load Balancer
→ Nginx
→ API Gateway
→ Spring Boot
→ Database

其中 Nginx 经常承担:

  • 稳定的 HTTP 入口;
  • 反向代理;
  • 静态资源;
  • TLS 终止;
  • 多实例负载均衡;
  • 缓存、压缩、限流和日志;
  • 外部连接与内部服务拓扑之间的隔离层。

必须牢记三个结论:

  1. Nginx 与应用服务是分工关系,不是简单替代关系。
  2. Client ↔ Nginx 与 Nginx ↔ Backend 是两条独立连接。
  3. Nginx 可以提升后端可扩展性,但单个 Nginx 本身仍可能是单点。

下一篇将进入 Nginx 配置模型,重点回答:

  • maineventshttpserverlocation 是什么关系;
  • 多个域名和端口如何选择 server
  • 精确、前缀、^~ 和正则 location 如何匹配;
  • rootaliastry_filesrewrite 为什么经常引发路径错误。

参考资料#

  1. Nginx Official Website, nginx:产品定位与最新版本信息。访问日期:2026-07-06。
    https://nginx.org/
  2. Nginx Official, nginx: download:稳定版 1.30.3、主线版 1.31.2。访问日期:2026-07-06。
    https://nginx.org/en/download.html
  3. Nginx Official Documentation, Beginner’s Guide:进程模型、配置结构、静态资源、代理与配置重载。访问日期:2026-07-06。
    https://nginx.org/en/docs/beginners_guide.html
  4. NGINX Community Blog, Inside NGINX: How We Designed for Performance & Scale:事件驱动、非阻塞 Worker 和重载机制。访问日期:2026-07-06。
    https://blog.nginx.org/blog/inside-nginx-how-we-designed-for-performance-scale
  5. Nginx Official Documentation, Using nginx as HTTP load balancer:负载均衡方法和开源版/Plus 能力边界。访问日期:2026-07-06。
    https://nginx.org/en/docs/http/load_balancing.html
  6. Nginx Official Documentation, Configuring HTTPS servers:TLS 入口和证书配置。访问日期:2026-07-06。
    https://nginx.org/en/docs/http/configuring_https_servers.html
  7. Docker Hub Official Image, nginx:官方镜像及固定版本标签。访问日期:2026-07-06。
    https://hub.docker.com/_/nginx
  8. Spring Cloud Gateway Official Reference, Spring Cloud Gateway:API Gateway 的定位与能力。访问日期:2026-07-06。
    https://docs.spring.io/spring-cloud-gateway/reference/index.html
  9. Kubernetes Official Documentation, Ingress:Ingress 定义、Controller 关系,以及 Gateway 优先方向。访问日期:2026-07-06。
    https://kubernetes.io/docs/concepts/services-networking/ingress/
  10. Kubernetes SIG Network, Gateway API Introduction:下一代 Kubernetes 流量路由 API。访问日期:2026-07-06。
    https://gateway-api.sigs.k8s.io/

文章验收清单#

内容完整性#

  • 说明 Nginx 在后端架构中的位置;
  • 说明直接暴露应用端口的限制;
  • 区分正向代理和反向代理;
  • 讲解 Web Server、静态资源、反向代理、负载均衡、TLS、缓存和流量治理职责;
  • 讲解 Master/Worker 与事件驱动模型;
  • 明确客户端连接与 upstream 连接不是同一条连接;
  • 对比 Nginx、API Gateway、CDN、云 LB、Kubernetes Gateway 和 Service Mesh;
  • 提供完整 Docker Compose + Spring Boot 实验;
  • 提供故障排查流程;
  • 提供面试题、场景题和配置排错题。

技术准确性#

  • 核验 2026-07-06 Nginx 官方稳定版与主线版;
  • 固定 Docker 镜像版本,不使用 latest
  • 没有把 NGINX Plus 主动健康检查写成开源版默认能力;
  • 没有把 Ingress、Ingress Controller 与 Nginx 混为一谈;
  • 说明 Kubernetes Ingress API 已冻结并推荐 Gateway;
  • 没有把 CORS、WAF 或入口代理当成业务鉴权替代品;
  • 说明单个 Nginx 仍然是单点。

配置可运行性#

  • 给出完整目录结构;
  • 给出 Compose、Nginx、Maven、Java 和 Dockerfile;
  • 给出启动、检查、验证、日志和清理命令;
  • 给出 nginx -tnginx -T
  • 说明预期响应和网络表现。
第 1 篇:Nginx 在后端架构中的位置
https://jupiter-ws.cn/posts/backend/nginx/01_nginx_backend_architecture_position/
作者
Jupiter
发布于
2026-07-06
许可协议
CC BY-NC-SA 4.0