资讯详情

Nginx 核心配置拆解:从静态部署到反向代理与负载均衡实战

📅 2026/10/10 8:25:02 | 华诺云谱 👁 阅读
Nginx 核心配置拆解:从静态部署到反向代理与负载均衡实战
作为一名常年跟线上服务打交道的人我对 Nginx 的感情一直很复杂。一方面静态部署、反向代理、负载均衡这几件事随便拿出来一个都不算难网上教程一把一把的另一方面真到了线上出问题的时候——SSL 证书换了不生效、浏览器报net::err_cert_common_name_invalidd、后端接口一会儿通一会儿不通——很多人对着配置文件就是一脸懵。经常有人问我配置都照抄了为什么还是不行问题多半出在你根本没理解 Nginx 处理一个请求时走的是哪条链路。这篇文我不打算给你念文档而是把从静态部署到反向代理再到负载均衡这条线的核心知识点拆开讲透顺便把我踩过的坑、排查过的线上事故一起交代清楚。适合刚入门想系统搞懂 Nginx 的开发者也适合被线上故障逼着来补课的同学。1. 先搞懂 Nginx 收到请求后到底做了什么很多人配置 Nginx 全凭记忆server、location、proxy_pass这些指令都会写但从来没人告诉他这些指令之间是怎么协作的。结果就是配置能跑但稍微改一点就翻车。这一节我们先把这个地基打牢——理解 Nginx 的请求处理模型后面所有配置和排错才有依据。1.1 server 块监听端口与虚拟主机匹配一个请求到达 Nginx 时第一件事是看listen。这个指令决定了 Nginx 在哪个 IP 和端口上接收流量比如listen 80;就是监听所有网卡的 80 端口listen 443 ssl;是监听 443 并启用 SSL。同一台机器上可以写很多个server块每个server监听不同的端口或 IP也可以监听同一个端口但通过server_name区分——这就是虚拟主机Virtual Host的概念。server_name的匹配规则很多人搞不清楚其实优先级是精确匹配 左侧通配符*.example.com 右侧通配符www.example.* 正则匹配~^www\.\d\.example\.com$ 默认 server。如果所有server_name都没匹配上Nginx 会使用这个端口上第一个定义的server块或者显式声明listen 80 default_server;的那个。这个默认规则很容易被忽略我遇到过不止一次新增了一个server块后流量全部跑到了旧站点就是因为新块写在了前面成了隐式 default_server。再说一个容易被带偏的点server_name如果你写了localhost那就只有浏览器地址栏输入 localhost 才会命中你拿本机 IP 访问会直接落到默认 server。所以本地开发要多站点调试比如热搜里那个本地虚拟机 多端口 nginx 开发环境多站点自定义域名配置本质上就是靠listen不同的端口或server_name不同的域名来区分站点然后在 hosts 文件里把自定义域名指到 Nginx 所在机器。你看到 1panel 这类面板图形界面上配置多个网站反向代理底层生成的就是一组server块没什么神秘可言。1.2 location 匹配不是从上到下找第一个而是按规则优先级location是 Nginx 配置里最容易被低估的指令。很多初学者的理解是请求进来后从上到下找第一个匹配的 location 就完事了这个理解在部分场景下凑巧成立但完全不是 Nginx 的规则。真正的匹配分了两轮先比普通前缀再比正则。普通前缀分两种不带修饰符的location /api和带^~修饰的location ^~ /api正则也有两种区分大小写的location ~ /api和不区分大小写的location ~* /api还有精确匹配location /api。匹配顺序是这样的优先级匹配类型说明1精确匹配完全一致才命中优先级最高命中后立即停止2^~前缀匹配普通前缀中找到最长匹配项且命中后不再检查正则3正则匹配~/~*按配置文件里的书写顺序逐个匹配第一个命中的生效4普通前缀匹配取最长匹配项但仍会继续检查正则若正则没命中使用该前缀5/兜底以上都未命中时使用看到没普通前缀并不是哪个写在前面用哪个而是哪个匹配得长用哪个而正则恰恰相反是哪个写在前面用哪个。我举个例子你就明白了请求GET /static/js/app.js配置里有location /和location /static/两个普通前缀Nginx 会选/static/因为它更长、更具体如果你还配了location ~* \.js$那正则会在前缀匹配之后参与竞争一旦正则命中就用正则的结果。这个机制带来的坑是正则 location 一旦写多了顺序就变成了一件极其敏感的事。比如有人写了location ^~ /api/又写了location ~ /api/v1/本来前缀优先但如果在后面配正则时会继续检查正则……不对^~命中后连正则都不看了。如果想让某个前缀彻底隔离正则干扰^~就是你要的修饰符。1.3 一个请求最终落到了哪个处理分支把 1.1 和 1.2 串起来一个请求在 Nginx 内部的完整路径大概是先按listen找到对应的监听端口然后在监听端口下按server_name找到合适的server块接着在server块里按location匹配规则找到对应的处理分支。这个分支要么是静态文件指令root、alias、try_files要么是反向代理指令proxy_pass也可能是返回指令return。我个人建议你在排查任何 Nginx 问题时都在心里过一遍这三步请求落在哪个 server落在哪个 location这个 location 里执行的是静态还是代理逻辑能回答这三个问题至少一半的 Nginx 疑难杂症你已经能自己看出来。比如访问域名打不开——先 curl 一下看是不是连到了 Nginx排除 DNS、防火墙再确认是不是有匹配的 server_name再看默认 server 是谁路径基本就出来了。接下来两章我们就把静态和代理这两大分支分别讲透。2. 静态部署把配置文件写清楚少踩 root/alias 的坑静态部署是 Nginx 最朴素的应用但恰恰是朴素两个字让人放松警惕。root、alias、index、try_files这几个指令单看文档都能懂组合到一起就全是戏。2.1 root 与 alias看起来差不多行为差很远这两个指令的区别是静态配置里最经典的问题。简单说root会把完整的请求 URI 拼接到文件路径后面alias则是把 location 匹配到的部分替换成自己指定的路径。拿具体例子对比一下。配置location /static/ { root /var/www/html; }这时请求GET /static/css/app.cssNginx 拼出的磁盘路径是/var/www/html/static/css/app.css——也就是root的值加上完整 URI。再看location /static/ { alias /var/www/html/static/; }同样的请求拼出的路径是/var/www/html/static/css/app.css——/static/这个前缀被替换成了 alias 的值后面的/css/app.css原样接上。在这个场景下两者结果一样很容易让人以为差不多。但如果你把 alias 写成/var/www/static末尾没有斜杠或者 location 不是/static/而是/static不带斜杠拼接结果立刻变得诡异最常见的 404 就是这么来的。说一个我实际踩过的坑location /static/ { root /var/www/site; }其实会访问/var/www/site/static/下的文件而很多人以为 root 和 alias 一样配了root /var/www/site/static/;结果路径变成了/var/www/site/static/static/访问全 404。所以我的习惯是静态文件场景优先用root并且root后面不要想当然地加上 location 的路径只有当你明确想改变 URL 与磁盘目录的映射关系时才使用alias并且记住alias路径末尾的/要和 location 的/对应——location 以/结尾alias 也以/结尾否则拼接就会错位。2.2 一个生产可用的静态站点配置长什么样静态部署不只是root index两行。真正能用、性能还过得去的静态站点至少要考虑到缓存、压缩、目录安全和 SPA 路由回退。下面这套配置我在多个项目里直接用过可以当模板server { listen 80; server_name example.com www.example.com; root /var/www/example; index index.html; gzip on; gzip_types text/plain text/css application/javascript application/json image/svgxml; gzip_min_length 1024; location / { try_files $uri $uri/ /index.html; } location /static/ { expires 7d; add_header Cache-Control public, no-transform; } location ~* \.(php|sh|env)$ { deny all; } autoindex off; }几个关键点说一下。try_files $uri $uri/ /index.html;是 SPA单页应用的标准写法先找真实文件再找目录都找不到就回退到入口页把路由交给前端框架处理。这行配置是很多前后端分离项目刷新页面就 404的根治方案。location /static/里那两行是给静态资源加缓存头让浏览器对该目录下的文件缓存 7 天减少重复请求。deny all那段正则是防止敏感文件被直接下载——很多人的.env、备份脚本就是这么泄露出去的。autoindex off;关闭目录列表防止别人直接浏览你的文件目录结构。2.3 多站点多端口一个 Nginx 多个网站的配置思路热搜里那组本地虚拟机 多端口 nginx 开发环境多站点自定义域名配置我单独拎出来说一下。做本地开发经常需要同时跑好几个前端项目每个项目一个端口甚至一个自定义域名用 Nginx 统一入口比一个个起静态服务要方便得多。思路很简单Nginx 给你开好几个server每个server监听不同端口或者用不同的server_name然后你在系统 hosts 文件里把这些域名指向 127.0.0.1或虚拟机 IP。server { listen 8081; server_name site1.dev; root /home/dev/site1/dist; index index.html; location / { try_files $uri $uri/ /index.html; } } server { listen 8082; server_name site2.dev; root /home/dev/site2/dist; index index.html; location / { try_files $uri $uri/ /index.html; } }hosts 文件里写127.0.0.1 site1.dev site2.dev浏览器访问http://site1.dev:8081就会打到 site1http://site2.dev:8082打到 site2。这套逻辑跟 1panel 面板里配置反向代理、多个网站的原理完全一样面板只是可视化地帮你生成server块踩坑点依然绕不开listen、server_name、root这几个字段的匹配关系。把底层原理搞懂你用不用面板都不会慌。2.4 静态站 403/404 的排查顺序静态站点最容易出两个状态码403 和 404。403 多数是权限问题404 多数是路径映射问题排查顺序可以固定成下面的流程。403 的排查先看 Nginx 进程用户通常是www-data或nobody对目标目录有没有读权限和执行权限——目录至少要有r-x文件至少要有r--再确认目录下有没有index指定的入口文件然后确认autoindex是不是关闭了但目录下又没有可访问的 index 文件最后看一眼有没有被deny规则命中。用命令ls -l /path/to/dir和sudo -u www-data cat /path/to/file可以快速定位。404 的排查核心是确认 Nginx 拼接出来的磁盘路径跟实际文件路径是否一致。我强烈建议在server块里临时加一行error_log /tmp/nginx_debug.log debug;重载后看日志里打印的实际文件路径比瞎猜快得多。除此之外root后面多拼了一层、alias末尾缺斜杠、location 前缀与目录结构不一致都是高频原因。记住一个心法Nginx 的 404 绝大多数时候不是文件不存在而是你告诉它找的路径和你以为的路径不一致。3. 反向代理核心不是 proxy_pass 一行而是你把握住了什么反向代理是 Nginx 最核心的用途。很多人觉得反向代理就是写一行proxy_pass http://后端地址;其实这一行的背后藏着 URI 传递规则、header 处理、SSL 回源、超时与长连接等一系列问题。搜索引擎里nginx 反向代理 不生效nginx 反向代理 ollamanet::err_cert_common_name_invalidd这些热搜词全是这些细节没掌握导致的。3.1 proxy_pass 的 URI 继承规则最容易翻车没有之一proxy_pass后面写不带路径和带路径行为完全不同。这绝对是 Nginx 反向代理配置里翻车率最高的知识点。先说结论再上例子。规则是如果proxy_pass后面带了 URI哪怕只是一个/那么 Nginx 会用这个 URI 替换掉 location 匹配到的部分然后把剩余路径接在后面如果proxy_pass后面不带 URI那么原始请求 URI 会被原样转发给后端。三个例子你就懂了配置写法请求后端实际收到的 URIproxy_pass http://10.0.0.2;GET /api/user/api/userproxy_pass http://10.0.0.2/;GET /api/user/userproxy_pass http://10.0.0.2/server/;GET /api/user/server/user看到区别了吗第一行原样转发第二行把/api替换成了/第三行把/api替换成了/server。很多人的后端接口写着/api/userNginx 配了proxy_pass http://backend/;结果后端收到的是/user接口 404然后开始怀疑后端代码有 bug折腾大半天——这个场景我见过不下五次。还有两个衍生坑要记住。第一如果 location 用的是正则匹配~、~*proxy_pass后面不允许带 URI带了 Nginx 直接报错并拒绝启动因为正则匹配的不确定性让 Nginx 无法确定从哪里开始替换。第二proxy_pass里的域名后面跟了 URI 时nginx 会忽略 location 前缀本身你配置里的 location 前缀在转发时会被啃掉所以凡是希望保留原始路径的场景proxy_pass的 URL 就不要带尾斜杠也不要带任何路径。3.2 头部信息Host 与 X-Forwarded-* 为什么必须配反向代理的本质是中间人后端服务默认只知道请求来自 Nginx 的 IP不知道真实客户端是谁也不知道客户端访问的是哪个域名。一旦涉及日志分析、IP 限流、HTTPS 跳转、多域名共用一个后端你就必须显式传递头部信息。我常用的四行配置如下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;逐个解释。Host $host;把客户端请求里的 Host 传给后端否则后端拿到的 Host 是proxy_pass里的 IP:端口很多基于域名的路由比如 Spring Cloud Gateway、Kubernetes Ingress 后端会直接路由失败。X-Real-IP $remote_addr;是 Nginx 这一跳看到的最真实客户端 IP因为 Nginx 就是直接面对客户端的那个。X-Forwarded-For $proxy_add_x_forwarded_for;会在已有 XFF 基础上追加当前$remote_addr这样后端拿到的就是一整条代理链上的客户端 IP 记录。X-Forwarded-Proto $scheme;告诉后端用户原本用的是 http 还是 https——如果你不配这一行后端做强制 HTTPS 跳转时看到的一直是 http就会陷入无限重定向。这里顺带纠正一个高频率的误解$host和$http_host不一样。$host优先取请求行里的主机名如果没有则取 HOST 头且会去掉端口号$http_host百分百取 HOST 头原值带端口就带端口。在绝大多数场景下用$host更符合直觉不容易搞出端口不匹配的问题。3.3 HTTPS 回源证书校验与 SNI 的那些事反向代理遇到 HTTPS坑一下就变多了。最常见的场景有两种一种是你自己对外提供 HTTPS 服务收到 443 的 HTTPS 请求后反代给内网的 HTTP 服务——这种只需把证书配置在前端 server 块回源不需要加密另一种是你的后端服务本身也是 HTTPSNginx 需要以 HTTPS 客户端去访问后端这种就要处理证书校验和 SNI。先讲第二种因为它和热搜里的net::err_cert_common_name_invalidd直接相关。Nginx 默认用http://访问上游时不会去校验上游证书但这不代表它会把 SNIServer Name IndicationTLS 握手里告诉服务器我要访问哪个域名的字段正确发过去。如果你的proxy_pass写的是 IP比如https://192.168.1.10:8443而后端服务器上的证书是为某个域名签发的TLS 握手时 Nginx 没有发送 SNI后端就不知道应该下发哪个证书可能发了一个默认的、跟实际访问域名不匹配的证书浏览器立刻报err_cert_common_name_invalidd。解法是加上location /api/ { proxy_pass https://192.168.1.10:8443; proxy_ssl_server_name on; proxy_ssl_name api.internal.example.com; }proxy_ssl_server_name on启用 SNIproxy_ssl_name指定 SNI 里应该带的名字也就是后端证书的域名。如果是自签名证书要跳过校验再加proxy_ssl_verify off;。这套配置也是本地跑 Ollama 这类 AI 服务做反向代理时绕不开的细节——你通过 Nginx 暴露 Ollama 服务、在 CherryStudio 这类客户端里填 API Key 时如果遇到证书校验失败先检查的就是这几个参数。3.4 超时与长连接流式接口为什么总是断反向代理场景下请求超时三个字背后可能是完全不同的阶段。需要分清三个超时参数参数作用默认值合理调整proxy_connect_timeout与上游建立 TCP 连接的超时60s内网可保持默认proxy_send_timeout向下游客户端发送数据的超时60s大文件下载可调大proxy_read_timeout等待上游响应的超时60s流式接口建议调到 300s 以上AI 推理、流式返回、长轮询这类接口最典型的故障就是前端页面转圈转着转着就报 504Nginx error.log 里出现upstream timed out。原因多半是默认的proxy_read_timeout只有 60 秒而上游模型推理超过 60 秒没有产生任何响应Nginx 就主动断开了。流式场景建议把proxy_read_timeout调到 300s 甚至更高。另外注意proxy_buffering off;在流式场景里的作用——它的本意是让 Nginx 不要缓冲整个上游响应而是边收边传给客户端对 SSEServer-Sent Events类接口几乎是必选项否则客户端收不到实时事件。还有一个热搜词是nginx mirror 超时时间。mirror指令可以把请求复制一份发给另一个上游做流量镜像或录制重点是镜像请求的超时或失败不应该影响主链路。如果配置了 mirror 后主接口变慢或挂掉先查 mirror 上游能不能在规定时间内响应——镜像请求默认也在走代理超时逻辑你把proxy_read_timeout调大了镜像请求同样会跟着放大等待时间。4. 负载均衡从轮询到真实流量的分配负载均衡可以说是 Nginx 最出圈的能力之一。upstream模块写起来就那么几行但把流量分发给多个后端这件事策略选错、健康检查缺失、连接数算错都会从隐性小坑变成线上大事故。这一节把 upstream 的常用配置和决策逻辑给你讲透。4.1 upstream 基础配置与转发机制一个标准的负载均衡配置分为两部分先定义上游服务器组再在location里通过proxy_pass引用它。看这个例子upstream web_cluster { server 192.168.1.10:8080 weight3 max_fails2 fail_timeout10s; server 192.168.1.11:8080 weight2 max_fails2 fail_timeout10s; server 192.168.1.12:8080 backup; } server { listen 80; server_name example.com; location / { proxy_pass http://web_cluster; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }upstream块里每个server可以带一系列参数weight表示权重默认 1max_fails和fail_timeout组合实现故障摘除——比如max_fails2 fail_timeout10s的意思是 10 秒内失败 2 次就把该节点标记为不可用10 秒后再试探恢复backup表示备用节点正常节点全部不可用时才接管流量down表示永久下线。注意这些参数是配合被动健康检查工作的也就是 Nginx 是在转发请求发现失败后才摘除节点而不是主动探测。4.2 四种均衡策略怎么选upstream默认的负载策略是轮询round-robin请求依次分发给每个后端权重高的多分发。但真实流量并不是永远均匀的于是 Nginx 又给了几种策略策略写法适用场景轮询默认后端无状态、机器性能均衡加权轮询server ... weight3机器性能差异明显时一致性哈希hash $request_uri consistent;需要将同一请求固定到同一后端比如缓存命中友好ip_haship_hash;需要会话保持但注意前端统一入口时会分发不均最少连接least_conn;后端处理耗时差异大、长连接请求多ip_hash是我最想提醒的一个。它按客户端 IP 的哈希结果分发看起来能解决会话保持但如果你前面还挂了一层 CDN 或另一个负载均衡所有请求的$remote_addr都来自同一个出口 IPip_hash就退化成了所有请求全打到一个后端负载完全失衡。真正要解决会话保持优先考虑让应用层用 Redis 存 session或者后端自己做粘性会话Nginx 层的ip_hash只适合小规模、纯直连的场景。least_conn适合后端处理耗时差异大的场景。比如三个后端里一个处理慢、两个处理快轮询会让慢节点堆积请求least_conn会优先把新请求分给当前活跃连接最少的节点整体吞吐更均衡。4.3 健康检查与故障摘除被动检查的局限前面说了max_fails和fail_timeout属于被动健康检查。它的优点是零额外成本缺点是只有转发到坏节点失败之后才知道节点坏了而且失败次数和摘除时间都需要靠配置调优。比如某个接口偶发超时如果你的proxy_next_upstream配置比较激进Nginx 会把同一个请求重试给下一个节点这虽然提高了成功率但也意味着后端可能收到重复请求。proxy_next_upstream的默认值是error timeout也就是只有连接错误和超时才尝试下一个节点。如果后端返回 502、503、504默认不会重试。你可以显式扩展但一定要想清楚重试的幂等性location /api/ { proxy_pass http://web_cluster; proxy_next_upstream error timeout http_502 http_503 http_504; proxy_next_upstream_tries 2; }POST 请求尤其小心如果你的请求已经到达后端并且后端已经开始处理此时发生了超时Nginx 重试到下一个节点下一个节点又处理一遍就可能出现重复下单、重复扣款这类事故。幂等接口可以放心配重试非幂等接口尽量把重试范围缩小甚至不配。4.4 worker 与连接数反向代理的 TCP 最大连接数怎么算热搜里有nginx 作为反向代理 tcp 最大连接数这是性能调优绕不开的问题。先给结论单个 worker 能维持的最大并发连接数由worker_connections决定整个 Nginx 的最大并发连接数约等于worker_processes * worker_connections但在反向代理模式下每个请求会占用两条连接——一条是客户端到 Nginx一条是 Nginx 到上游——所以能处理的并发请求数约为这个数字的一半。worker_processes一般设成auto或 CPU 核心数worker_connections默认 1024一般会调大到 4096 或 10240。但调大之前要确认两件事一是系统文件描述符限制Linux 上用ulimit -n查看Nginx 的 worker 进程实际能打开的文件描述符受这个值约束二是内核参数尤其是net.core.somaxconn和net.ipv4.ip_local_port_range后者决定 Nginx 作为客户端向上游发起连接时可用的本地端口范围如果同时并发连接数过高端口耗尽就会出现Cannot assign requested address。在上游配置里加keepalive也是减少连接开销的关键手段upstream web_cluster { server 192.168.1.10:8080; keepalive 32; } server { location / { proxy_http_version 1.1; proxy_set_header Connection ; proxy_pass http://web_cluster; } }这里有两步缺一不可proxy_http_version 1.1让 Nginx 用 HTTP/1.1 与上游通信HTTP/1.0 默认不支持长连接proxy_set_header Connection 是为了清空请求头里的Connection: close让上游不要主动关闭连接。两个一起配Nginx 到上游的 TCP 连接才能复用高并发场景下的性能差距非常明显。5. 高频故障排查SSL 不生效、CORS 报错、超时问题最后这一章我把搜索引擎里反复出现的几类 Nginx 故障集中讲一下。别看它们症状五花八门根因基本都是配置细节没对上。5.1 替换 SSL 证书不生效先分清是没加载、还是没生效我把新证书放到服务器上改了ssl_certificate的路径也nginx -s reload了访问还是旧证书。这个场景的排查链路我建议按下面来。第一步确认 Nginx 到底加载的是哪个证书。执行nginx -T注意大写 T可以把当前生效的完整配置打印出来然后 grep 一下ssl_certificate看看实际生效的路径是不是你以为的那个路径。这一步非常关键因为有些人改的是conf.d/下某个文件但实际生效的配置可能来自/etc/nginx/nginx.conf里的 include 顺序后 include 的文件覆盖了先 include 的。第二步看证书链是否完整。浏览器要求服务器返回的证书链必须包含站点证书和中间证书如果你的ssl_certificate文件只放了站点证书而没有中间证书浏览器会报证书链不完整表现也是证书没生效。正确做法是cat 站点证书 中间证书 fullchain.pem顺序不能反。第三步确认 reload 是不是真的成功了。nginx -t只检查语法nginx -s reload让 worker 进程平滑重载配置但如果你的 worker 进程因为某些原因没有重载成功配置其实没生效ps -ef | grep nginx看一下 master 和 worker 的启动时间可以判断。第四步如果你用了 1panel 这类面板替换证书后还要检查站点配置里绑定的证书 ID 是否切换到了新证书——面板生成的配置里证书路径往往是动态注入的页面上的勾选没跟上磁盘上的文件换了也没用。5.2 net::err_cert_common_name_invalidd 的完整排查链路这个浏览器报错含义很明确证书里的域名和你在地址栏敲的域名对不上。但对不上可能发生在三条不同的链路上。链路一是客户端直接到 Nginx。你用https://example.com访问Nginx 给的是证书里只有www.example.com没有example.com就会报这个错。这最常见也最好查用openssl s_client -connect example.com:443 -servername example.com看看实际返回的证书主体是不是你要访问的域名。链路二是 Nginx 作为客户端访问 HTTPS 上游前面 3.3 节说过proxy_pass用 IP、未开启proxy_ssl_server_name上游下发了错误的证书浏览器看到的是Nginx 转发链路里有一跳证书不匹配——报错也是这个。链路三是访问了旧 IP、旧域名比如你换了证书但 CDN 或 hosts 缓存还没刷新浏览器把请求打到了旧的接入点。给一个实用的排查命令组合curl -vI https://example.com 21 | grep -i SSL connection openssl s_client -connect example.com:443 -servername example.com /dev/null 2/dev/null | openssl x509 -noout -subject -issuer -dates顺便说一句2020 年后主流浏览器都强制要求证书必须包含 SANSubject Alternative Name字段以前那种只写 CN 的老证书即使浏览器地址栏域名跟 CN 一致也会报这个错。所以新申请证书时务必确认 SAN 里把你要用的每个域名都列上。5.3 invalid cors requestCORS 到底是在谁身上配invalid cors request这个报错经常出现在跨域场景。前端在http://localhost:3000后端接口在http://api.example.com浏览器发起跨域请求时先发一个 OPTIONS 预检请求预检通过才发真正的请求。如果这个 PR 预检在 Nginx 层面处理得不对就会出现invalid cors request。处理思路是在反向代理的 location 里显式处理 OPTIONS 和响应头。我常用的模板location /api/ { if ($request_method OPTIONS) { add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS always; add_header Access-Control-Allow-Headers Authorization, Content-Type, X-Requested-With always; add_header Access-Control-Max-Age 86400 always; add_header Access-Control-Allow-Credentials true always; return 204; } add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Credentials true always; proxy_pass http://backend; }几个要点说明。$http_origin是请求里的 Origin 头把它原样回显到Access-Control-Allow-Origin可以做到谁请求就允许谁但如果你要限制跨域来源就不能这么写要改成具体的域名白名单。always参数是一定要加的它的作用是即使响应码不是 200 也会带上这些响应头否则 4xx、5xx 响应里会丢失 CORS 头浏览器一样会报错。还有一点add_header指令在 location 里一旦写了会覆盖从 server 层继承下来的 add_header如果你之前上级配过 CORS 头内层不要漏配。再说一下谁身上配的问题。Nginx 只是第一层真正要做严谨的 CORS 校验后端应用也要处理。Nginx 层的 CORS 能解决 80% 的开发调试问题但如果你的接口涉及敏感操作、需要严格控制来源后端必须自己校验 Origin。5.4 nginx -t 通过但服务异常时的通用排查步骤nginx -t通过只代表语法没问题逻辑问题它一概不管。当nginx -t通过但线上服务还是异常时我习惯按下面这张清单逐步排查症状检查点常见结论配置改了不生效nginx -T看实际配置、检查 worker 进程时间改的文件没被 include、没 reload访问返回 502上游是否存活、proxy_pass的上游地址是否可达上游挂了、端口写错、防火墙拦截访问返回 499客户端提前断开看是不是超时设置太短与后端处理时长不匹配错误日志无输出确认error_log级别和路径默认 error.log 在/var/log/nginx/容器内挂载配置报错检查挂载目录是否存在、权限是否正确alpine 镜像conf.d目录需要先存在挂载时注意subPath语义容器场景我再补一句用 nginx 官方 alpine 镜像时很多人把宿主机配置目录直接挂到/etc/nginx/conf.d结果容器启动报错说目录不存在或没有配置。原因是官方镜像里/etc/nginx/conf.d是符号链接直接挂载会覆盖掉链接本身。常见的做法是先把配置目录挂到其他位置再用自定义入口脚本或直接修改主配置里的 include 路径。这个坑在 Kubernetes 部署 Nginx 时尤其常见——你以为是 Yaml 写错了其实就是目录挂载语义没搞清。另外如果你用 zabbix 这类监控工具盯着 Nginx记得在主配置里开启stub_status模块暴露/nginx_status端点zabbix 才能采集到活跃连接数、请求总数这些指标。这也是很多人配置了监控模板却拿不到数据的常见原因——模板没问题是 Nginx 没把状态页开出来。我个人的习惯是线上环境改动任何 Nginx 配置之前先做三件事备份原配置、nginx -t验语法、想清楚这次改动会影响哪个 server、哪个 location。改完之后不是直接看页面而是先curl -I看响应头对不对。三次事故下来你就发现Nginx 的问题基本不是不会配而是配置的生效链路没搞清。把这篇文章里讲的请求匹配顺序、URI 传递规则、SSL/SNI 的握手逻辑串起来再遇到搜索记录里那些高频报错你至少能知道该去看哪个文件、哪一行了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑