ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Nginx核心作用与生产实践:从反向代理到平滑升级

Nginx核心作用与生产实践:从反向代理到平滑升级 聊到 Nginx很多刚接触服务端的朋友第一反应是“这不就是个 Web 服务器嘛”等真正把它丢进生产环境才发现Nginx 的作用和应用场景比想象中大得多静态资源服务、反向代理、负载均衡、HTTPS 证书卸载、缓存加速、限流防刷……几乎每一层都能看到它的身影。这篇文章我想从一个“普通问题”聊起把 Nginx 的核心作用一条条拆开再结合我这些年实际踩过的坑从安装配置到平滑升级、问题排查给你一份可以直接抄作业的完整参考。整套内容适合刚入门的人也适合已经部署过 Nginx 但没系统梳理过的同学。我尽量不说废话全部以实际场景和可复现的配置为准。1. Nginx 到底在解决什么问题先说一个最容易被忽略的事实Nginx 最初解决的是 C10K 问题也就是单机能不能扛住一万个并发连接。2004 年它刚出来的时候市面上的主流做法还是“每个请求一个进程”的 Apache 模型。连接一多内存和 CPU 就被进程调度吃干净机器直接卡死。Nginx 的思路完全不同它用事件驱动、异步非阻塞的模型用少量 worker 进程就能撑住海量连接。一个进程可以同时处理成千上万个请求就像餐厅里一个优秀的排号员同时在服务几十桌客人而不是每个客人配一个专属服务员。放到今天Nginx 的核心功能已经发展成四块静态资源服务图片、CSS、JS、HTML、音视频交给它又稳又快。反向代理把请求转发到后端的应用服务器比如 Java 的 Spring Boot、Node.js、PHP-FPM。负载均衡把流量分摊到多台后端机器避免一台被压垮。安全与加速SSL/TLS 证书卸载、HTTP/2、HTTP/3QUIC、限流、缓存、访问控制。所以你看很多团队把 Nginx 放在所有流量的最前面它不是简单的“网页服务器”而是整个系统的入口网关。我个人的理解是Nginx 是“连接用户和后端服务之间的那双手”。用户请求进来它决定把人带到哪个页面、哪个后端接口、哪台服务器如果后端挂了它还能帮忙挡一下。这个角色决定了它的配置方式五花八门但底层逻辑始终只有一条——把请求处理到正确的地方。下面我就逐个拆开讲。2. 拆开 Nginx 的四个核心作用2.1 静态资源服务最基础也最容易被忽视静态资源服务是 Nginx 的基本功也是很多人第一次接触它的原因。你本地跑了一个 Vue 或 React 项目执行pnpm run build之后生成一个 dist 目录想让别人能访问最简单的办法就是让 Nginx 直接托管这个目录。配合热词里看到的“pnpm run build 的包怎么 nginx 启动”其实就是把构建产物丢到 Nginx 的 root 路径下。一个最简单的托管配置server { listen 80; server_name example.com; root /data/www; index index.html; location / { try_files $uri $uri/ /index.html; } }注意最后那个try_filesSPA 项目基本都靠它。前端路由是 history 模式时比如/user/123服务器上根本不存在这个物理文件如果不加try_files直接刷新页面会 404。try_files $uri $uri/ /index.html的含义是先找这个路径有没有对应文件没有再找有没有对应目录都没有就统一返回index.html让前端路由自己去处理。静态资源这块有几个关键性能参数值得单独说sendfile on; tcp_nopush on; keepalive_timeout 65; gzip on; gzip_types text/plain text/css application/javascript application/json image/svgxml; gzip_min_length 1k; location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 30d; add_header Cache-Control public, immutable; }sendfile让文件从磁盘到网卡的拷贝过程由内核直接完成减少用户态切换。gzip压缩文本类文件实测静态资源体积能减少 60% 以上。expires 30d给静态资源设置浏览器缓存二次访问几乎无延迟。我见过很多团队花大价钱优化后端接口结果前端静态资源一个 gzip 都没开首屏加载能慢三倍。静态资源托管是最简单的优化起点。2.2 反向代理让请求去它该去的地方反向代理是 Nginx 使用频率最高的功能。所谓反向代理就是用户请求先到 NginxNginx 再按照规则转发到后端的应用服务器。用户可以感知到的只有 Nginx后端服务器具体在哪、有多少台对用户是透明的。对应的还有正向代理那是替客户端转发请求的常用于内网访问外网。Nginx 做的是反过来的事替服务器收请求所以叫反向代理。一个典型的 API 转发配置server { listen 80; server_name api.example.com; location / { proxy_pass http://127.0.0.1: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; } }这里有几个容易忽略的点第一proxy_set_header Host $host非常重要。后端很多框架会根据 Host 头生成跳转链接或判断域名如果不带上后端拿到的一律是 Nginx 的内网地址签名校验、单点登录、跨域这些全都会出问题。第二X-Real-IP和X-Forwarded-For是为了让后端拿到用户真实 IP。如果没有这两个配置后端日志里看到的所有请求 IP 都是 Nginx 的地址一旦要做封禁、限流、审计完全没法搞。第三proxy_pass后面有没有子路径行为完全不一样。比如location /api/ { proxy_pass http://backend/; }这种写法会把/api/前缀去掉再转发。而location /api/ { proxy_pass http://backend; }这种不带尾部/的会把完整的/api/...路径直接拼到后端地址后面。这个细节是大坑我见过不下五次因为这里多一个斜杠少一个斜杠导致接口 404。热词里有一条“nginx 限制只转发带参数的 url”这个需求本质就是按照查询参数决定要不要转发。常见做法是在 location 里判断$arg_或$query_stringlocation /api/ { if ($args ~ token.) { proxy_pass http://backend; break; } return 404; }意思很直白请求里带了 token 参数才转发否则直接返回 404。break的作用是命中 if 之后不再继续走后续 rewrite 规则。需要注意的是Nginx 的if指令在很多场景下有坑官方文档只建议在 return、rewrite 这类场景用整体转发逻辑尽量谨慎能用location或map实现就不要硬写一堆 if。2.3 负载均衡把流量摊到多台机器上当单台后端扛不住并发你就需要横向扩容前面放一个 Nginx 做负载均衡。Nginx 的upstream模块就是干这个的配合请求量把流量分发到不同后端。最小的负载均衡配置upstream backend_cluster { server 192.168.1.10:8080 weight3; server 192.168.1.11:8080 weight1; server 192.168.1.12:8080 backup; } server { listen 80; server_name app.example.com; location / { proxy_pass http://backend_cluster; proxy_set_header Host $host; } }这里我用了三个节点前两台权重是 3:1意思是每 4 个请求里约 3 个打到 10 这台1 个打到 11 这台。权重适合两台机器配置不一样的场景配置高的多加一点流量。第三台打了backup标记平时不参与服务只有前面两台都挂了才启用。这相当于一个灾备节点自动化切换。除了权重轮询Nginx 还支持ip_hash按用户 IP 的哈希结果分配同一 IP 固定打到同一台后端。适合需要 session 保持的老项目。least_conn优先发给当前连接数最少的后端适合请求处理时长差异较大的场景。负载均衡不是单纯“把请求发出去”还要考虑后端健康状态。Nginx 有被动健康检查即请求转发后如果连续失败max_fails次就把这台服务器临时标记为不可用等fail_timeout时间后再重试。常用配置upstream backend_cluster { server 192.168.1.10:8080 max_fails2 fail_timeout30s; server 192.168.1.11:8080 max_fails2 fail_timeout30s; }意思是 30 秒内失败 2 次就摘掉这个节点30 秒后再试探。这种机制应对日常宕机足够了但它属于“事后发现”请求已经转发过去并失败了。如果要求更主动的健康探测得用商业版 Plus 或者配合第三方模块也可以用脚本定时探测后动态修改 upstream。关于高可用线上一般会再加一层 keepalived把 Nginx 本身做成双机热备用虚拟 IPVIP对外提供服务。一台 Nginx 挂了VIP 自动漂移到另一台对用户完全无感知。这里不展开讲 keepalived 的配置但方向是明确的Nginx 做流量入口keepalived 做入口的 “保险丝”。2.4 SSL/TLS 终端证书卸载与安全加速现在大部分网站都是 HTTPS证书配置是每个 Nginx 用户绕不开的活。Nginx 在 SSL 这块的位置也非常特殊它通常是 TLS 连接的“终点站”外网客户端和 Nginx 之间走 HTTPSNginx 和后端之间可以走内网 HTTP。这样做的原因很实际TLS 握手和加解密都是 CPU 密集操作把这事集中在 Nginx 这一层做后端应用就能省出大量 CPU 去处理业务逻辑。一段常规 HTTPS 配置server { listen 443 ssl; http2 on; server_name www.example.com; ssl_certificate /etc/nginx/certs/example.com.pem; ssl_certificate_key /etc/nginx/certs/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://backend; } } server { listen 80; server_name www.example.com; return 301 https://$host$request_uri; }第一个server块监听 443 端口加载证书处理加密流量第二个server块把 80 端口的 HTTP 请求全部 301 跳转到 HTTPS。很多小项目直接用这一套就完成了 HTTPS 改造。ssl_protocols建议只保留 TLSv1.2 和 TLSv1.3老旧的 TLSv1.0、TLSv1.1 都有已知漏洞没必要为了兼容十几年前的浏览器留着。顺带说一下热词里的 “docker pull nginx quic 协议”。QUIC 是 HTTP/3 的底层传输协议Nginx 从 1.25.0 开始对 HTTP/3 的支持逐渐成熟。要启用 HTTP/3Nginx 编译时需要加--with-http_v3_module参数然后在 listen 指令里加上http3listen 443 quic reuseport; listen 443 ssl; http3 on;如果你的 Nginx 是官方通过 yum/apt 安装的版本先确认版本和编译参数是否带了 HTTP/3 模块可以用nginx -V看。Docker 镜像docker pull nginx拉下来之后官方主线版镜像是否包含 v3 模块取决于镜像构建参数需要先nginx -V 21 | grep http_v3验证。如果没带就考虑用源码编译或换成带模块的镜像。QUIC 确实能显著改善弱网环境下的连接成功率但部署复杂度也更高不是所有项目都急着上。3. 应用场景与选型什么时候该用 Nginx3.1 前端接入层统一入口大多数 Web 项目的第一层入口就是 Nginx。它的作用相当于一个“前台接待”所有外部请求先到这里再根据域名、路径、请求头分发到不同服务按域名区分api.example.com走 API 服务admin.example.com走管理后台。按路径区分/api/*走后端接口/static/*走静态资源/websocket走长连接服务。按请求方法区分读接口和写接口分到不同的上游。有了这一层后端的任何服务都不需要直接暴露公网 IP只需要监听内网端口整个入口的收口和安全控制都变得很轻松。限流也是入口层常见的需求。比如给登录接口加限制limit_req_zone $binary_remote_addr zonelogin_limit:10m rate10r/m; location /api/login { limit_req zonelogin_limit burst5 nodelay; proxy_pass http://backend; }这里rate10r/m表示每分钟最多 10 个请求burst5表示允许突发 5 个进入排队队列。对登录、短信验证码这类高风险接口限流是必须的。3.2 动静分离前端静态资源与后端动态接口解耦传统后端渲染的项目尤其是 PHP、Java 单体应用静态资源和动态接口都混在一起。用户访问一个页面服务器既要读模板文件又要查数据库全部串行处理慢且耗资源。用 Nginx 做动静分离之后静态资源直接走 Nginx 文件系统动态请求才转发给后端location ~* \.(html|css|js|png|jpg|gif|ico|svg|woff2?)$ { root /data/static; expires 7d; } location / { proxy_pass http://backend; }动静分离对混合架构特别有用。比如前端用 React 构建静态页面后端用 Java 提供 API整体结构就是Nginx 托管前端静态文件同时把/api/请求转发到 Java 服务。这也是现在最常见的前后端分离部署形态。3.3 微服务与 API 网关场景微服务架构里每个服务可能单独部署在一组机器上客户端不可能记住每个服务的地址。Nginx 可以作为轻量 API 网关按路径把请求分发到不同的微服务upstream order_service { server 10.0.0.11:8080; server 10.0.0.12:8080; } upstream user_service { server 10.0.1.11:8080; server 10.0.1.12:8080; } server { listen 80; server_name gateway.example.com; location /api/order/ { proxy_pass http://order_service/; } location /api/user/ { proxy_pass http://user_service/; } }服务规模不大时这种轻量网关方案比引入全套微服务网关框架要简单得多。它没有臃肿的依赖规则就是纯文本配置文件Git 管理、版本回滚都方便。只有当你需要复杂的服务发现、动态路由、熔断、灰度发布时才应该考虑更重的网关方案。3.4 Nginx、Apache、HAProxy 怎么选这是一个被问烂了但又必须回答的问题。我习惯用下面这张表总结对比项NginxApacheHAProxyEnvoy并发模型事件驱动异步非阻塞进程/线程模型事件驱动事件驱动静态资源处理强一般不支持一般七层路由能力强强较弱强四层转发TCP/UDP支持stream较弱非常强支持动态配置需 reload需 reload需 reload支持 API 热更新上手成本低低中高生态成熟度极高高高快速增长简单说需要同时处理静态文件和动态反代首选 Nginx纯四层高并发流量转发HAProxy 更专业在 Kubernetes 里做 Ingress Controller常见的 nginx-ingress 或 Envoy 都比较合适需要动态路由和灰度发布Envoy 这类云原生网关更应景。我这几年线上项目基本都跑 Nginx只有在一台机器上要对大量 TCP 端口做负载均衡时才考虑 HAProxy。Nginx 的最大优势是“中庸且全面”大部分场景一个它就能全包。4. 亲手搭一套安装、配置与实操细节4.1 安装 Nginx从包管理到 Docker 到源码不同的部署环境安装方式不一样。我这里列三种最常用的。包管理器安装是最快的# Debian / Ubuntu apt update apt install -y nginx # CentOS / RedHat / Rocky yum install -y nginx # 或者 dnf install -y nginx包管理器安装的好处是省事版本随系统源走能用 systemd 管理。缺点是版本通常偏旧可能缺少新特性比如 HTTP/3 模块。如果是内网环境没有外网访问就需要离线安装。思路是找一台同系统版本的机器可以联网装好 Nginx 和依赖用 rpm 或 deb 包导出再拷贝。CentOS 下# 能联网的机器上 mkdir nginx-packages yum install --downloadonly --downloaddirnginx-packages nginx然后把整个目录拷到内网机器rpm -ivh nginx-packages/*.rpm即可。这里容易踩依赖坑Nginx 依赖的 pcre、openssl、zlib 可能也被装到下载目录里了拷过去一起装通常没问题。离线安装前最好先确认系统版本完全一致我遇到过开发机是 CentOS 7.9、生产机是 Rocky 9rpm 包互相不兼容白折腾一小时。Docker 方式适合容器化部署docker pull nginx:stable docker run -d --name my-nginx \ -p 80:80 -p 443:443 \ -v /data/www:/usr/share/nginx/html \ -v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \ nginx:stableDocker 镜像的好处是环境隔离升级和回滚都方便。但要注意容器里的 Nginx 配置文件是短路径和宿主机不一定完全对应日志最好也挂载出来不然docker logs看起来费劲。另外如果想用 QUIC/HTTP/3得先确认镜像里的 Nginx 是否带http_v3_module。源码编译安装是自由度最高的方式也是平滑升级的前提wget https://nginx.org/download/nginx-1.26.2.tar.gz tar xzf nginx-1.26.2.tar.gz cd nginx-1.26.2 ./configure \ --prefix/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_v3_module \ --with-stream \ --with-stream_ssl_module make make install--prefix决定安装路径后续升级、回滚都要依赖这个路径一定要记住。--with-http_ssl_module是 HTTPS 必需的--with-stream是四层 TCP/UDP 转发用的--with-http_v3_module是为了 HTTP/3。装完之后先验证版本nginx -v nginx -Vnginx -V会输出完整的编译参数这个信息在升级时必须保留后面讲平滑升级时会用到。4.2 配置文件结构与关键参数Nginx 主配置文件默认在/etc/nginx/nginx.conf源码安装则在--prefix下的conf/nginx.conf。核心结构如下user nginx; worker_processes auto; worker_rlimit_nofile 65535; events { worker_connections 4096; } http { include /etc/nginx/mime.types; include /etc/nginx/conf.d/*.conf; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; } }几个关键参数worker_processes auto通常设置为 CPU 核数Nginx 每个 worker 进程可以充分利用一个核。设多了反而引起上下文切换开销。worker_connections 4096每个 worker 进程最多同时处理的连接数。最大并发连接数约等于worker_processes * worker_connections。如果这个值太小高并发时日志里会出现 worker_connections are not enough。worker_rlimit_nofile单个进程可以打开的最大文件数。因为每一条 TCP 连接都对应一个文件描述符这个值太小并发一高就报 too many open files。include把主配置拆分成多个子配置文件方便管理。推荐每个站点或每个应用单独建一个 conf 文件放在/etc/nginx/conf.d/下而不是全部堆在一个文件里。4.3 反向代理 负载均衡完整示例我把两个功能合在一起给一份可以直接用的完整配置upstream app_backend { least_conn; server 10.0.0.10:8080 max_fails2 fail_timeout30s; server 10.0.0.11:8080 max_fails2 fail_timeout30s; } server { listen 80; server_name app.example.com; access_log /var/log/nginx/app.access.log; error_log /var/log/nginx/app.error.log; location / { proxy_pass http://app_backend; 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_connect_timeout 5s; proxy_read_timeout 30s; } location /static/ { alias /data/static/; expires 7d; } }这里把/static/请求直接交给 Nginx 读文件系统其他请求全部负载均衡到后端。alias和root的区别值得单独强调root会把 location 的路径拼接在根目录后面比如root /data/static; location /static/时请求/static/a.png会找/data/static/static/a.pngalias /data/static/时则找/data/static/a.png。用错这两个指令静态资源会全部 404这是新手最容易踩的坑之一。proxy_connect_timeout 5s是 Nginx 与后端建立 TCP 连接的超时时间设太短后端偶尔忙一下就会 502。proxy_read_timeout 30s是读取后端响应的超时时间如果后端有长任务接口比如导出报表要跑一分钟这里得对应调大。4.4 HTTPS 证书配置实战这里以已有证书文件为前提不展开怎么申请证书直接说配置server { listen 443 ssl; http2 on; server_name www.example.com; ssl_certificate /etc/nginx/certs/www.example.com.pem; ssl_certificate_key /etc/nginx/certs/www.example.com.key; ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; # 安全协议配置 ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; } }ssl_session_cache shared:SSL:10m是很多团队容易漏的配置。TLS 握手是乘法运算每次建立新连接都要重新跑一次代价很高。开了 session cache 之后同一台客户端一段时间内可以复用会话密钥握手开销大幅下降。10m 大概能缓存几万个 session足够日常使用。证书到期是一个高频事故。建议配一个 crontab 定时任务检查证书有效期0 0 * * * /usr/bin/openssl x509 -enddate -noout -in /etc/nginx/certs/www.example.com.pem每个月跑一次看到快到期就提前换。我见过太多次证书过期导致线上全站报错起因就是大家都不记得证书是去年哪一天配的。4.5 前端构建产物的部署与“401 验证身份”配置热词里的 “pnpm run build 的包怎么 nginx 启动”我再展开一下。前端项目构建完得到 dist 目录部署到服务器/data/wwwNginx 配置server { listen 80; server_name front.example.com; root /data/www; index index.html; location / { try_files $uri $uri/ /index.html; } }前端路由如果是 hash 模式try_files那行其实不加也能跑。但 history 模式必须加否则用户点击浏览器刷新、或直接访问二级路由时会 404。有些后台页面需要访问控制Nginx 自带最简单的 HTTP Basic Auth配置两个指令就行location /admin/ { alias /data/www/admin/; auth_basic Restricted Area; auth_basic_user_file /etc/nginx/.htpasswd; }然后用工具生成密码文件htpasswd -c /etc/nginx/.htpasswd admin这个命令会提示输入密码生成的文件里存的是用户名和密码哈希。之后访问/admin/就会弹浏览器原生认证框输入账号密码才能访问。热词里提到的 “index.php 401 验证身份” 和这个类似如果后端是 PHP 并且接口返回 401要么是auth_basic导致的安全拦截要么是后端代码里自己做了登录校验。先用curl -I看 401 来自哪个响应头如果响应头里有WWW-Authenticate: Basic realm...基本就是 Nginx 的auth_basic在拦。5. 平滑升级、版本管理与踩坑记录5.1 Nginx 平滑升级到底怎么操作为什么要单独讲平滑升级因为很多人直接用包管理yum update nginx版本是升了但线上连接会被切断运气不好配置项兼容性还会出问题。尤其热词里提到“Nginx 升级到新版本要注意什么”这绝对是运维里一个高风险动作。源码编译的 Nginx 平滑升级标准步骤如下第一步查看当前版本和编译参数nginx -V把输出的 configure arguments 完整记录下来新版本编译时参数要和原来一致不然升级完某些模块就没了。第二步下载新版源码用同样的 prefix 和 configure 参数编译wget https://nginx.org/download/nginx-1.26.2.tar.gz tar xzf nginx-1.26.2.tar.gz cd nginx-1.26.2 ./configure \ --prefix/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_v3_module \ --with-stream make注意这里只执行make不要执行make install否则会直接覆盖老版本少了回滚机会。第三步备份旧二进制并替换mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old cp objs/nginx /usr/local/nginx/sbin/nginx第四步向旧 master 进程发送 USR2 信号启动新 masterkill -USR2 $(cat /usr/local/nginx/logs/nginx.pid)这时新旧 master 会同时存在新 worker 进程已接管配置。再发送 WINCH 信号给旧 master让它优雅关闭旧 workerkill -WINCH $(cat /usr/local/nginx/logs/nginx.pid.oldbin)升级完成后新版本就用原 pid 文件旧进程信息在nginx.pid.oldbin里。确认一切正常后可以把旧的二进制文件收起来避免误用。如果新版本有问题想回滚mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.new mv /usr/local/nginx/sbin/nginx.old /usr/local/nginx/sbin/nginx kill -USR2 $(cat /usr/local/nginx/logs/nginx.pid.oldbin) kill -QUIT $(cat /usr/local/nginx/logs/nginx.pid)这套流程在热词里对应“nginx 平滑升级指南”是线上升级的必修课。核心原则是能热切换就不要冷重启能回滚就不要硬着头皮修。5.2 日常运维reload、stop、日志切割日常管理命令不多但每一条都要记清楚命令作用nginx -t检查配置语法并显示测试结果nginx -s reload平滑重载配置不中断服务nginx -s stop快速停止服务nginx -s quit优雅停止处理完当前请求再退出systemctl status nginx查看服务状态和最近日志nginx -V查看编译参数和版本Windows 下关闭 Nginx 是nginx.exe -s stop或nginx.exe -s quit对应热词里的 “cmd 关闭 nginx”。注意 Windows 下 nginx 不推荐二进制的生产部署但本地调试完全没问题。日志切割也经常踩坑。Nginx 默认把日志写在一个文件里时间一长就是几十 GB。标准做法是用 logrotate/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 640 nginx adm sharedscripts postrotate [ -f /var/run/nginx.pid ] kill -USR1 cat /var/run/nginx.pid endscript }关键是postrotate里的kill -USR1这个信号会让 Nginx 重新打开日志文件。如果不发这个信号你就算把旧日志改名了Nginx 还在往旧文件里写等于没切割。5.3 上线前我必做的“三查”配置上线前我给自己定了一个固定流程到今天还在用第一查nginx -t。这步不用多说语法错误必须在这层拦掉。但我见过有人配完忘了跑直接 reload结果 reload 失败线上老配置还在跑新配置根本没生效排查半天。第二查检查权限和端口。Nginx 报Permission denied时多半是静态文件目录没有读权限或者 SELinux 没放行。检查端口占用ss -lntp | grep :80如果端口被其他进程占了Nginx 会报bind() to 0.0.0.0:80 failed。第三查做一次真实请求验证。用 curl 测curl -I http://127.0.0.1:80 curl -I -k https://127.0.0.1:443加上-I只看响应头能快速判断 HTTP 状态码是不是预期。如果 502去看 Nginx error.log 和后端服务状态如果 403去看目录权限和 index 文件如果 404先确认 root/alias 路径对不对。6. 常见问题与排查技巧6.1 Nginx 状态码速查表排查问题时状态码是第一手信号。我把最常见的整理成一张表状态码含义常见原因301永久重定向http 跳 https 配置302临时重定向登录跳转、鉴权跳转304未修改命中本地缓存Nginx 返回 not modified400请求错误请求头格式异常、参数非法401未认证auth_basic 或后端登录校验失败403禁止访问目录权限不足、无 index 文件、IP 被封404未找到root/alias 路径错误、SPA try_files 缺失405方法不允许静态文件上 POST 请求未处理413请求体过大client_max_body_size 设置过小429请求过多limit_req 限流触发500服务器内部错误后端应用异常502网关错误后端服务未启动、端口不通、超时503服务不可用后端无可用节点、正在维护504网关超时后端处理超时proxy_read_timeout 太小6.2 高频故障排查实录502 Bad Gateway 是最常见的故障。排查顺序systemctl status nginx确认 Nginx 本身活着。检查后端服务是否启动ss -lntp | grep 8080。在后端机器上直接curl http://127.0.0.1:8080/health确认后端本身能不能访问。如果后端正常但 Nginx 还是 502看 Nginx error.logtail -f /var/log/nginx/error.log常见报错是connect() failed (111: Connection refused)或connect() failed (110: Connection timed out)。前者说明端口没开或者 IP 不通后者说明防火墙或网络策略拦了。504 是另一个高发问题。典型场景是后端接口本身要跑很久比如导出大量数据Nginx 默认proxy_read_timeout 60s后端 60 秒内没返回Nginx 就主动断开返回 504。解决办法是给长任务接口单独配一个 location调大超时时间location /api/export/ { proxy_pass http://backend; proxy_read_timeout 300s; }403 往往不是权限问题就是索引问题。我遇到最多次的是两种一是 root 目录下的文件权限不是 nginx 用户可读二是autoindex off且目录下没有 index.html。先ls -l看权限再确认目录下有没有 index 文件。另外 CentOS 系统还要注意 SELinuxgetenforce一下如果是 Enforcing试试setsebool -P httpd_can_network_connect 1放行。404 分清是 Nginx 的还是后端的。如果请求打到后端接口返回 404那是后端路由问题如果是 Nginx 直接返回 404 的页面多半是 root 或 alias 配错。判断方法是看错误日志tail -f /var/log/nginx/error.log日志里会写清楚 “open() “/data/www/xxx” failed (2: No such file or directory)”告诉你 Nginx 实际在找哪个文件对照一下就明白了。413 Request Entity Too Large是老生常谈。上传文件时报这个错就是client_max_body_size没配或太小client_max_body_size 20m;放在http、server或location块里都行location里的优先级最高。6.3 我踩过的一些坑先说一个关于if的大坑。Nginx 的if指令被官方称为 “evil”因为它在location里和proxy_pass同时出现时行为很容易不符合直觉。不是不能用而是只用它做改路径或 return不要在里面写复杂逻辑。有一次我在if里设置变量再proxy_pass结果每次 reload 都报错最后改成用map做变量映射才解决。再说 reload 不是“不会断”。nginx -s reload理论上不会中断现有连接但如果你的配置里改动了 upstream 地址正在处理的长连接会被切掉。所以我建议不要在业务高峰期做这种改动尽量安排在凌晨低峰期。还有一个大家都容易忽略的点改了配置一定要先nginx -t再 reload。这个习惯我强调过无数次但每个月依然能遇到没跑测试直接 reload 导致线上配置状态混乱的情况。反正就一条命令多敲一下不亏。最后是日志。排查问题第一件事永远是看日志很多人习惯先猜。Nginx 的 access_log 和 error_log 分开看error.log记录错误比如连接失败、权限不足、配置文件报错。access.log记录每次请求状态码、耗时、来源 IP 都在里面。分析慢请求时在 Nginx 配置里加上$request_time字段就能从 access log 里看出哪些接口响应慢log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for rt$request_time urt$upstream_response_time;这里$request_time是 Nginx 处理请求的总时间$upstream_response_time是后端响应时间。两者差值大说明瓶颈在 Nginx 到后端这一段或网络两者都大基本就是后端接口本身慢。7. 最后分享一点个人心得Nginx 这个工具文档写得很全配置语法也不算难真正的难度在于你对自己系统的请求链路有没有想清楚。我在生产环境折腾 Nginx 这几年最大的体会是配置之前先画清楚“用户请求从哪进来、经过哪些层、最后到哪台机器哪个接口”再动手写配置文件基本不会出大错。每次上线前我会强制自己做三件事备份当前配置、执行nginx -t、把 access log 打开看两分钟真实请求。这套流程看起来土但比任何花哨的监控面板都好使。另外虽然我前面讲了不少进阶功能但如果不是业务需要不要为了炫技硬加功能。配置每多一层故障面就大一分保持“够用且可维护”才是最好的状态。如果后面有机会我打算再单独写一篇关于 Nginx 与 keepalived 高可用、以及 HTTP/3 QUIC 实战部署的内容。你们在配置 Nginx 时遇到过最诡异的问题是什么欢迎留言交流说不定下一篇文章就是专门为你排坑写的。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表