Nginx生产级配置优化指南

线上 Nginx 配置这事,看着简单------官方文档给的示例改改就能跑。但跑起来和跑得好是两码事。很多人装完 Nginx 就拿默认配置上线,worker 进程开一个,连接数不调,gzip 不开,静态文件不缓存,等流量上来了才发现各种 502 和 504。这篇就把生产环境 Nginx 的调优经验从头到尾过一遍。

先说版本。2026 年 7 月,Nginx 稳定版到了 1.30.4(mainline 1.31.3)。1.30 这个版本带来了不少实用特性:Early Hints(103 状态码)、到后端的 HTTP/2 代理、upstream sticky session、Multipath TCP 支持,还有一个细节改动------默认代理 HTTP 版本改成了 1.1 并开启 keep-alive,以前要手动配的现在默认就有了。但线上别用 mainline,稳定版更靠谱。

worker 进程和连接数调优

Nginx 的进程模型是 master + worker。master 负责管理,worker 负责干活。默认配置里 worker_processes 是 1,也就是只有一个 worker 在处理请求,这在多核机器上纯属浪费。

ini 复制代码
# 自动按 CPU 核心数启动 worker
worker_processes auto;

设成 auto 是最省心的做法,Nginx 会根据 CPU 核心数自动启动对应数量的 worker。如果你想手动控制,就填具体数字,一般跟 CPU 核心数一致。

worker_connections 是每个 worker 能同时处理的最大连接数。默认 1024,生产环境太保守了。

ini 复制代码
events {
    worker_connections 10240;
    # 允许一个 worker 同时接受多个连接
    multi_accept on;
}

10240 是个比较稳妥的值,根据机器内存调整。每个连接大概占 256 字节内存,10240 个连接也就 2.5MB,不用担心内存问题。multi_accept on 让 worker 一次性接受所有新连接,而不是一个一个来,高并发场景下能减少延迟。

最大连接数还有一个系统层面的限制:文件描述符。worker_processes * worker_connections 不能超过系统的 ulimit -n。生产环境一般把系统文件描述符设到 65535 或更高:

markdown 复制代码
# /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535

Nginx 配置里也加一行:

ini 复制代码
worker_rlimit_nofile 65535;

keepalive 配置

keepalive 是提升性能的低成本手段。客户端跟 Nginx 之间保持连接复用,避免每次请求都重新握手。Nginx 1.30 默认到后端的代理已经用 HTTP/1.1 + keep-alive 了,但前端的 keepalive 还是要配。

ini 复制代码
http {
    # 客户端长连接超时,65 秒覆盖大部分浏览器默认超时
    keepalive_timeout 65;
    # 单个长连接最大请求数,设够大避免频繁重建连接
    keepalive_requests 1000;
}

到后端的长连接也要配,不然每个请求都新建一条到后端的 TCP 连接,开销不小:

ini 复制代码
http {
    upstream backend {
        server 127.0.0.1:8080;
        # 到后端的长连接池大小
        keepalive 32;
    }

    server {
        location / {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            # 清除 Connection 头,让长连接生效
            proxy_set_header Connection "";
        }
    }
}

keepalive 32 表示为每个 worker 预留 32 个到后端的长连接。后端应用如果不支持 keep-alive(比如某些 CGI 程序),这配置不生效,但现在的应用服务器基本都支持。

gzip 压缩别忘开

默认 Nginx 的 gzip 是关的,这太常见了。一个 200KB 的 JSON 接口,开了 gzip 能压到 30KB 左右,带宽直接省 85%。线上不开 gzip 等于白扔带宽钱。

bash 复制代码
http {
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript
               text/xml application/xml application/xml+rss text/javascript
               application/rss+xml application/atom+xml image/svg+xml;
    gzip_vary on;
    gzip_proxied any;
}

几个关键参数:gzip_min_length 1k 太小的响应不压缩,压缩开销大于收益。gzip_comp_level 5 是性价比最高的级别,6 以上压缩率提升不明显但 CPU 开销猛增。gzip_types 要把 JSON 和 JS 加上,默认只压缩 text/html。gzip_vary on 加上 Vary: Accept-Encoding 响应头,让 CDN 能正确缓存压缩和非压缩版本。

静态文件缓存策略

静态文件(CSS、JS、图片)是缓存的重点对象。配好了能大幅减少回源请求。

ini 复制代码
server {
    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        # 日志里不记录静态文件请求,减少 IO
        access_log off;
    }
}

expires 30d 设置浏览器缓存 30 天。带 hash 的文件名可以用 immutable,告诉浏览器这个文件永远不会变,连条件请求都省了。没带 hash 的文件名别用 immutable,改了文件浏览器不更新就尴尬了。

服务端缓存可以配合 open_file_cache,缓存文件描述符和元数据,减少磁盘 IO:

ini 复制代码
http {
    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
}

反向代理和负载均衡

反向代理是 Nginx 最常用的功能,负载均衡策略直接决定了后端的压力分布。

ini 复制代码
upstream backend {
    # 加权轮询(默认)
    server 10.0.0.1:8080 weight=3;
    server 10.0.0.2:8080 weight=1;
    server 10.0.0.3:8080 backup;

    # 1.30 新增的 sticky session
    sticky cookie srv_id expires=1h domain=.example.com path=/;
}

默认是加权轮询,weight 大的服务器分到更多请求。backup 表示备用服务器,前面的全挂了才用。

如果你的后端是有状态的(比如 session 存在本地),用 sticky session 让同一个客户端的请求始终打到同一台后端。Nginx 1.30 原生支持了 sticky session,以前只有 Nginx Plus 才有。

最小连接数策略适合后端处理能力不均匀的场景:

ini 复制代码
upstream backend {
    least_conn;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
}

ip_hash 适合需要会话保持但不想用 cookie 的场景,按客户端 IP 哈希分配,但同一 NAT 出口下的所有用户会打到同一台后端,移动端场景慎用。

SSL/TLS 优化

HTTPS 性能损耗主要在握手阶段。优化好了,握手开销能降到几乎无感。

ruby 复制代码
server {
    listen 443 ssl;
    http2 on;

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # 只用 TLS 1.2 和 1.3,干掉不安全的旧版本
    ssl_protocols TLSv1.2 TLSv1.3;

    # 优先用服务端密码套件,防止客户端选弱算法
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

    # session 缓存,减少握手次数
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # TLS 1.3 session ticket
    ssl_session_tickets on;

    # OCSP stapling,客户端不用自己去查证书状态
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
}

TLS 1.3 的握手只需要一次往返,比 1.2 少一轮,延迟能降几十毫秒。ssl_session_cache 让同一个客户端的后续连接复用握手结果,shared:SSL:10m 大约能缓存 4 万个 session。OCSP stapling 把证书状态查询放到服务端,省去客户端额外请求,也能避免某些网络环境下 OCSP 查询失败导致连接变慢。

安全头不能少

安全响应头是低成本高收益的防护手段,配几行就能挡掉一批常见攻击:

ini 复制代码
server {
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
    add_header X-XSS-Protection "1; mode=block";
    add_header Referrer-Policy "strict-origin-when-cross-origin";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    add_header Content-Security-Policy "default-src 'self'";
}

X-Frame-Options 防点击劫持,X-Content-Type-Options 防 MIME 嗅探,HSTS 强制浏览器后续都走 HTTPS。CSP 策略按你的实际需求调,default-src 'self' 是最严格的,可能需要放开一些外部资源域名。

502 和 504 怎么排查

这俩是线上最高频的错误,排查思路要清晰。

502 Bad Gateway 是 Nginx 连不上后端。先看后端进程是不是挂了,ps aux | grep your_app 确认进程在不在。进程在的话看端口,netstat -tlnp | grep 8080 确认后端在监听。都正常就查 Nginx 的 upstream 配置,IP 和端口对不对。还有一种情况是后端处理太慢,Nginx 等不及了,这时候需要调超时:

ini 复制代码
location / {
    proxy_pass http://backend;
    # 后端响应超时时间
    proxy_read_timeout 60s;
    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
}

proxy_connect_timeout 是连接后端的超时,一般 5 秒够了------连不上说明后端有问题。proxy_read_timeout 是等待后端响应的超时,如果后端有慢接口,适当调大,但别设成 300s 之类的离谱值。

504 Gateway Timeout 是连上了后端但后端在规定时间内没返回。这个基本就是后端的问题了------接口太慢、数据库查询卡死、死循环。查后端日志,看慢查询,该加索引加索引,该加缓存加缓存。

Nginx 层面能做的是给后端加一层降级保护,避免慢请求拖垮整个连接池:

ini 复制代码
location / {
    proxy_pass http://backend;
    proxy_next_upstream error timeout http_502 http_504;
    proxy_next_upstream_tries 2;
    proxy_next_upstream_timeout 10s;
}

一个后端超时了自动切到下一个,最多试两次,总超时 10 秒。这样单个后端节点出问题不会让用户干等。

一份可用的生产配置骨架

把上面的配置整合一下,给一份能直接拿来改的生产骨架:

ini 复制代码
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 10240;
    multi_accept on;
}

http {
    include 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';

    access_log /var/log/nginx/access.log main buffer=32k flush=5s;
    error_log /var/log/nginx/error.log warn;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 65;
    keepalive_requests 1000;

    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript
               text/xml application/xml image/svg+xml;
    gzip_vary on;

    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;

    upstream backend {
        server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
        server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
        keepalive 32;
    }

    server {
        listen 80;
        server_name example.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        http2 on;
        server_name example.com;

        ssl_certificate /etc/nginx/ssl/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1d;

        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-Content-Type-Options "nosniff";
        add_header Strict-Transport-Security "max-age=31536000";

        location ~* .(js|css|png|jpg|gif|ico|svg|woff2)$ {
            expires 30d;
            add_header Cache-Control "public, immutable";
            access_log off;
        }

        location / {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            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 60s;
        }
    }
}

这份配置覆盖了进程调优、连接复用、压缩、缓存、HTTPS、安全头、反向代理这些核心项。拿去改改 IP 和域名就能用。上线前记得跑一下 nginx -t 验证配置语法,改完用 nginx -s reload 平滑加载,不会断已有连接。

Nginx 调优不是一次性的事,流量涨了、后端变了、新版本出了功能了,都得回头看看配置是不是还合理。养成习惯,定期 review 一次,比出事了再救火强太多。

相关推荐
渣渣盟1 小时前
Nginx 从零到上手:Windows & Linux 双环境教程
linux·windows·nginx
小小工匠3 小时前
Nginx - 10 万终端接入卡在 4 万:一次 nginx TCP 代理容量天花板的完整拆解
tcp/ip·nginx
hzxpaipai3 小时前
杭州网站运维|企业官网上线前技术检查清单:SEO、GEO、安全、服务器与备份
运维·服务器·nginx·安全
虎王物联15 小时前
Docker Compose编排物联网平台后端:Nginx+PHP-FPM+EMQX+InfluxDB一键部署实战
物联网·nginx·docker
浪兎兎18 小时前
Nginx 笔记
运维·笔记·nginx
因_崔斯汀18 小时前
Nginx 开启 Gzip 完整配置
nginx
不灭的程序员阿澄1 天前
Nginx 容器化部署实战:SPA 路由、Cookie 透传与 WebSocket 全配置详解
websocket·nginx·状态模式
Csxyzj1 天前
Nginx:企业高性能web服务器(一)
运维·服务器·nginx
Linux运维技术栈1 天前
云平台服务器遭遇黑客攻击?用 Nginx 批量封锁敏感接口,自动返回 444 关闭连接
运维·服务器·nginx·安全·防御