前面几篇讲了负载怎么分、缓存怎么用、冷热怎么拆、CDN 怎么就近——落地时,很多团队的第一站仍是 Nginx。装好之后真正要啃的,是 nginx.conf 怎么写对、怎么改稳。
本篇围绕配置结构讲清全局块、events、http/server/location,并给出反向代理、负载均衡、HTTPS、限流等常用示例与校验命令。
TL;DR
- Nginx 擅长 HTTP/反向代理、负载均衡、动静分离等;核心配置是
nginx.conf(也可拆到conf.d)。 - 结构:全局块 → events 块 → http 块(内嵌 server → location)。
- 全局:
user、worker_processes(建议设auto,由 Nginx 自动匹配 CPU 核数);events:worker_connections控单进程连接上限。 - http/server/location:虚拟主机、监听端口、
root、匹配规则(=/~/~*/^~)。 - 常用能力:
proxy_pass反向代理、upstream加权/ip_hash/least_conn 负载均衡、SSL、limit_req限流。 - 动静分离:静态资源直出(
root+expires),/api等动态路径走proxy_pass,减轻后端压力。 - proxy 头与超时:
proxy_set_header透传真实 IP/Host/协议;三个超时(connect/read/send)缺一不可。 - HTTPS:显式
ssl_protocols TLSv1.2 TLSv1.3并配现代 cipher 套件,HIGH:!aNULL:!MD5已偏旧、不建议直接照抄。 - 限流本质:
limit_req是漏桶式平滑(固定速率放行 +burst队列),不是严格意义的令牌桶;rate是漏出速率而非”令牌补充速率”。 - 运维:改配置前先
nginx -t校验,再nginx -s reload热重载;重启会中断现有连接,慎用。
Table of contents
Open Table of contents
1. Nginx 能做什么
Nginx 的核心能力包括:高性能 HTTP 服务、反向代理、负载均衡、动静分离处理,以及邮件代理服务等。
安装完成后,nginx.conf 是配置的核心入口,正确理解其结构与各参数含义,是安全修改和调优 Nginx 的前提。
HTTP/反向代理、负载均衡、动静分离是日常最常用的能力。
2. nginx.conf 结构
nginx.conf 是 Nginx 的主配置文件。也可以在 conf.d 目录下添加多个独立的配置文件(如按域名拆分),Nginx 会将它们一并加载。生产环境有多个域名需要代理时,通常在 conf.d 下为每个域名维护独立配置。
配置文件的整体层级结构为:全局块 → events 块 → http 块;http 块内可嵌套多个 server 块,每个 server 块可嵌套多个 location 块。
配置从外到内:全局 → events → http → server → location。
2.1 全局块
全局块配置影响整个 Nginx 进程的运行参数:
user nginx;
worker_processes auto;
# error_log logs/error.log;
# error_log logs/error.log notice;
# error_log logs/error.log info;
# pid logs/nginx.pid;
user:指定 Nginx 工作进程的运行用户(及用户组),默认nobody,生产环境通常设为nginx。worker_processes:指定 Nginx 启动的工作进程数。推荐设为auto,Nginx 会自动根据 CPU 核数决定;也可以手动指定为 CPU 核数。error_log和pid:日志路径与进程 ID 文件,一般使用默认值即可。
2.2 events 块
events 块设置 Nginx 的工作模式与连接上限:
events {
worker_connections 65535;
}
worker_connections:每个工作进程可以同时处理的最大连接数。Nginx 的理论最大并发连接数约为worker_processes × worker_connections,需结合服务器性能与业务并发量合理配置,同时注意操作系统的文件描述符上限(ulimit -n)。
2.3 http 块
http 块是整个配置的核心,大部分 HTTP 相关指令(MIME 类型、日志、超时、虚拟主机等)都在此处定义:
http {
include mime.types;
default_type application/octet-stream;
sendfile on; # 启用高效文件传输模式
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name localhost;
# access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
}
}
主要参数说明:
listen:虚拟主机监听的端口,不同 server 块监听的端口不可冲突。server_name:虚拟主机的域名匹配规则,支持四种写法:
# 精确匹配
server_name www.example.com;
# 左侧通配
server_name *.example.com;
# 右侧通配
server_name www.example.*;
# 正则匹配
server_name ~^www\.example\.*$;
root:静态资源根目录。访问www.example.com/index.html时,Nginx 实际读取的是root目录下的index.html文件。error_page 404:指定 404 错误页的路径;error_page 500 502 503 504指定 5xx 错误页的路径。
2.4 location 块
location 块用于配置不同 URL 路径的处理规则,支持反向代理、重定向、静态文件服务等:
location / {
root html;
index index.html index.htm;
}
location = /50x.html {
root html;
}
location 匹配规则(优先级从高到低):
= # 精确匹配,优先级最高
^~ # 前缀匹配,匹配成功后停止搜索其他规则
~ # 正则匹配,区分大小写
~* # 正则匹配,不区分大小写
/ # 通用前缀匹配,兜底规则
location 匹配优先级对照:
| 优先级 | 前缀 | 匹配类型 | 示例 | 说明 |
|---|---|---|---|---|
| 1(最高) | = | 精确匹配 | location = /login | 仅匹配 /login 本身,命中即停止搜索 |
| 2 | ^~ | 前缀匹配(优先) | location ^~ /static/ | 匹配 /static/ 前缀后立即停止,不再尝试正则 |
| 3 | ~ | 正则匹配(区分大小写) | location ~ \.php$ | 按配置顺序依次尝试,第一个匹配成功即生效 |
| 3 | ~* | 正则匹配(不区分大小写) | location ~* \.(jpg|png)$ | 与 ~ 优先级相同,按声明顺序匹配 |
| 4(最低) | 无前缀 / | 普通前缀匹配 | location / | 最长前缀匹配,常作兜底规则 |
易错点:
~/~*之间没有优先级区分,命中顺序取决于配置文件中的先后声明顺序,而非正则的“精确程度”——把更具体的正则写在前面,否则可能被范围更宽的规则提前拦截。
location 配置示例:
server {
listen 80;
server_name www.example.com;
# 精确匹配 /web02
location = /web02 {
root /usr/local/nginx/html;
index index.html index.htm;
}
# 精确匹配 /web01
location = /web01 {
root /usr/local/nginx/html;
}
# 正则匹配图片资源(区分大小写)
location ~ \.(jpeg|jpg|png)$ {
root /usr/local/nginx/html;
}
}
3. 常用配置示例
3.1 反向代理
反向代理通过 proxy_pass 指令将请求转发到后端服务器。转发时通常需要透传客户端信息(真实 IP、Host 等):
upstream app {
server 10.10.10.100:8090;
server 10.10.10.101:8090;
}
server {
listen 8090;
server_name www.example.com;
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
静态本地/CDN 返回,动态经 proxy_pass 打到后端。
3.2 负载均衡
算法与 L4/L7 选型见负载均衡;这里只给 Nginx upstream 常用写法。
负载均衡通过 upstream 定义后端节点池,proxy_pass 将流量打入池中。Nginx 支持三种主要策略(参见负载均衡):
一句话:
upstream定义后端池,proxy_pass把流量打进去——权重、ip_hash、least_conn都在这一层选。
加权轮询(默认):
upstream web_weighted {
server 10.10.10.100 weight=1;
server 10.10.10.101 weight=2;
server 10.10.10.102 down; # 临时下线
}
IP 哈希(会话粘滞):
upstream web_iphash {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
最少连接:
upstream web_leastconn {
least_conn;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
使用方式统一通过 proxy_pass 引用:
server {
listen 80;
location / {
proxy_pass http://web_weighted;
}
}
3.3 HTTPS
获取域名的 SSL 证书和私钥后,在 server 块中配置如下:
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /path/to/your_certificate.pem;
ssl_certificate_key /path/to/your_private.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# 只保留现代协议,禁用已弃用的 TLS 1.0/1.1
ssl_protocols TLSv1.2 TLSv1.3;
# TLS 1.3 的套件由 OpenSSL 内置管理;下面这行仅约束 TLS 1.2 的套件
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
# TLS 1.3 下客户端优先,1.2 下服务端优先即可,无需强制服务端顺序
ssl_prefer_server_ciphers off;
location / {
root html;
index index.html index.htm;
}
}
为什么不再照抄
HIGH:!aNULL:!MD5:HIGH是一个随 OpenSSL 版本变化的宽泛别名,可能纳入 CBC 等已不推荐的套件,且无法表达”只走 ECDHE 前向保密 + AEAD”的现代要求。生产建议直接锁定TLSv1.2 TLSv1.3与上面这类明确的 ECDHE-AEAD 套件列表(可用 Mozilla SSL Configuration Generator 按 nginx 版本生成 intermediate 配置),并配合 OCSP Stapling、HSTS 一起上线。
生产环境建议同时配置 HTTP → HTTPS 的强制跳转,以及 HTTP/2(新版本用 http2 on; 指令,旧版本用 listen 443 ssl http2)以提升并发性能。
3.4 限流
Nginx 通过 ngx_http_limit_req_module 模块限制请求速率,保护后端免受突发过载或恶意请求冲击(各算法原理详见服务限流;负载均衡层面的流量控制背景可参见负载均衡)。
措辞纠正:
limit_req的实现更接近漏桶(leaky bucket)——请求以rate指定的固定速率被”漏出”放行,burst相当于桶的容量(可排队的额外请求数),超出即拒绝。它不是严格意义上的令牌桶:令牌桶允许把攒下的令牌一次性用于瞬时突发,而limit_req即使在burst之内也仍按固定间隔放行(除非加nodelay)。因此下文中的rate应理解为”漏出/放行速率”,而非”令牌补充速率”。
http {
# 定义限流区:按客户端 IP 限速,共享内存 10MB,速率 10 req/s
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
listen 80;
location / {
# burst=20:允许最多 20 个排队请求;nodelay:超出 burst 立即返回 503
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://backend;
}
}
}
rate:漏桶的固定放行速率(每秒稳定处理的请求数),如10r/s即每 100ms 放行一个;burst:漏桶容量,即可排队的额外请求数,超出后立即拒绝;nodelay:burst内的排队请求立即放行而非按rate间隔等待,超出burst直接返回 503(去掉nodelay则严格按固定间隔排队漏出)。
默认超限返回 503,可用
limit_req_status 429;改为更语义化的 429 Too Many Requests。
3.5 动静分离
动静分离的核心思路:静态资源由 Nginx 直接服务(避免经过 JVM/Python 等运行时),动态请求才走 proxy_pass 打到后端,既节省后端资源,又可对静态文件单独设置缓存头。
upstream app {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name www.example.com;
# 静态资源:Nginx 直出,设置长效缓存
location ~* \.(html|css|js|jpg|jpeg|png|gif|ico|svg|woff2?)$ {
root /var/www/static;
expires 7d;
add_header Cache-Control "public, max-age=604800, immutable";
}
# API 请求:转发到后端
location /api/ {
proxy_pass http://app;
}
# 兜底:其余路径(如 SPA history 模式)也走后端
location / {
proxy_pass http://app;
}
}
生产上静态目录通常通过 CI/CD 同步或挂载 CDN;动静分离也可在 CDN 层实现(静态回源 OSS,动态回源 LB),两层不互斥。
3.6 Proxy 头与超时
proxy_pass 转发时,若不显式透传头,后端收到的 Host 会变成 upstream 地址,REMOTE_ADDR 会变成 Nginx 本机 IP。以下是生产环境的标准写法:
location / {
proxy_pass http://app;
# 透传原始 Host,避免后端虚拟主机匹配错误
proxy_set_header Host $host;
# 客户端真实 IP
proxy_set_header X-Real-IP $remote_addr;
# 完整代理链(多层代理时追加)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 原始协议(HTTP/HTTPS),后端用于生成正确的跳转链接
proxy_set_header X-Forwarded-Proto $scheme;
# 三段超时缺一不可(单位:秒)
proxy_connect_timeout 5s; # 与后端建立 TCP 连接的超时
proxy_read_timeout 60s; # 等待后端响应数据的超时(含业务处理时间)
proxy_send_timeout 60s; # 向后端发送请求体的超时
}
超时设置过小会导致正常慢请求被截断;设置过大则故障节点会长时间占用连接。生产建议结合业务 P99 RT 设定,并与服务端超时保持一致(参见依赖韧性)。
proxy 超时参数对照:
| 参数 | 含义 | 默认值 | 生产建议值 | 设置过小的风险 | 设置过大的风险 |
|---|---|---|---|---|---|
proxy_connect_timeout | 与 upstream 建立 TCP 连接的超时 | 60s | 3–5s | 后端瞬时抖动即被误判为不可用 | 故障节点长时间占用等待队列,拖慢整体转发 |
proxy_read_timeout | 等待 upstream 返回响应数据的超时(含业务处理耗时) | 60s | 按 P99 RT × 1.5–2 倍设定 | 正常慢请求(大查询、慢接口)被提前截断返回 504 | 故障节点的连接迟迟不释放,占满 worker 连接数 |
proxy_send_timeout | 向 upstream 发送请求体的超时(两次写操作间的最大间隔) | 60s | 与 proxy_read_timeout 保持同量级 | 大文件上传等场景可能被中途打断 | 与 read 超时同理,故障连接占用时间变长 |
对齐原则:三段超时应与客户端超时、服务端框架超时(如 Spring MVC 的
server.tomcat.connection-timeout)形成一致的梯度——上游超时应略长于下游,否则会出现「Nginx 已经超时返回 504,但后端还在继续跑」的资源浪费。
3.7 Upstream 健康检查与摘除
Nginx 开源版内置被动健康检查:连续失败达阈值后自动摘除节点,待 fail_timeout 窗口过后再尝试恢复。
upstream app {
# 60s 内连续失败 3 次则摘除,60s 后重新探测
server 10.10.10.100:8080 max_fails=3 fail_timeout=60s;
server 10.10.10.101:8080 max_fails=3 fail_timeout=60s;
# backup:主节点全部不可用时才启用
server 10.10.10.102:8080 backup;
# down:手动标记永久下线(不参与调度、也不尝试恢复)
# server 10.10.10.103:8080 down;
}
摘除与优雅排水:down 适合发版前手动摘节点;发版完成后去掉 down 再 nginx -s reload 即可重新上线。零停机发版建议结合上游 LB 或服务注册中心做优雅排水(详见负载均衡)。
开源版没有内置主动健康检查:上面的
max_fails/fail_timeout是被动探测——只有真实请求打到故障节点失败后才会摘除,也就是说至少要”牺牲”几个真实请求才发现节点挂了。主动健康检查(周期性探活、故障节点不承接任何真实流量)需要 Nginx Plus 的health_check指令,或开源社区的nginx_upstream_check_module(需重新编译打补丁)。竞价这类对错误率极敏感的链路,建议在上游 LB / 服务网格层做主动探活,而不是只依赖 Nginx 开源版的被动摘除。
3.8 常见踩坑
1. proxy_pass 末尾斜杠影响 URI 改写
# 不带斜杠:/api/v1/foo → 后端收到 /api/v1/foo(路径原样透传)
proxy_pass http://app;
# 带斜杠:/api/v1/foo → 后端收到 /v1/foo(去掉 location 前缀 /api)
proxy_pass http://app/;
规则:proxy_pass 末尾带 /(或带路径)时,Nginx 会将 location 匹配前缀替换掉。行为不一致是生产中最常见的 404 来源之一。
2. worker_connections 要与 ulimit -n 对齐
worker_connections 是 Nginx 的软上限,OS 文件描述符上限(ulimit -n)是硬上限——若后者更低,实际可建连接数会被 OS 截断。生产建议在 /etc/security/limits.conf 或 systemd unit 中将 nofile 设置为不低于 worker_processes × worker_connections,并通过 ulimit -n 或 /proc/<pid>/limits 验证生效。
3. reload 与 restart 的区别
nginx -s reload 让 master 用新配置 fork 新 worker,旧 worker 优雅退出——已有连接不中断。restart 会先 stop 再 start,存量长连接被强制关闭。生产上应始终优先 reload,reload 前务必执行 nginx -t 确认语法无误。
4. proxy_buffering 与 SSE / 流式响应
Nginx 默认 proxy_buffering on,会将后端响应缓冲完整后再发给客户端,导致 SSE、流式 AI 生成等场景客户端长时间收不到数据。解决方式:
location /stream/ {
proxy_pass http://app;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s; # 长连接需要更大的读超时
chunked_transfer_encoding on;
}
4. 常用运维命令
# 校验配置文件语法(修改后必做)
nginx -t
# 热重载配置(不中断已有连接)
nginx -s reload
# 优雅关闭(等待当前请求处理完毕)
nginx -s quit
# 立即停止
nginx -s stop
若 Nginx 已注册为 systemd 服务:
systemctl start nginx # 启动
systemctl stop nginx # 停止
systemctl restart nginx # 重启
systemctl reload nginx # 热重载
5. 生产检查清单
上线或变更 Nginx 配置前,逐项确认。
通用清单:
-
nginx -t语法校验通过,无[emerg]/[crit]报错 -
worker_processes已设为auto,worker_connections与ulimit -n对齐 -
proxy_set_header已透传Host、X-Real-IP、X-Forwarded-For、X-Forwarded-Proto - 三段 proxy 超时(connect / read / send)均已显式配置,不依赖默认值
-
upstream节点均已配置max_fails与fail_timeout,备用节点用backup标注 - HTTPS server 已配
ssl_protocols TLSv1.2 TLSv1.3与现代 ECDHE-AEAD cipher,未直接照抄HIGH:!aNULL:!MD5 - HTTPS server 同时配置了 HTTP → HTTPS 强制跳转(
return 301 https://$host$request_uri) - 静态资源 location 设置了合理的
expires/Cache-Control响应头 - SSE / 流式接口的 location 已关闭
proxy_buffering,读超时已放大 -
proxy_pass末尾斜杠与 location 前缀对应关系已人工确认,无误截断 URI - 变更通过
nginx -s reload热重载,确认 access log 与 error log 无异常
小结
Nginx 在高性能系统中扮演流量入口的角色:静态资源直出减轻后端压力,proxy_pass + upstream 实现反向代理与负载均衡,limit_req 在边缘做第一道限流,SSL termination 统一卸载 TLS 开销。本系列前几篇讨论的负载均衡算法、缓存策略、限流机制,最终都要落到 Nginx(或其他网关)的配置上才能生效;其后的异步与削峰、连接与 I/O 模型与性能测试则分别回答「洪峰怎么削」「连接怎么撑」「容量怎么验」。