一、概述
1.1 背景介绍
Nginx 是目前使用最广泛的反向代理和负载均衡器。它采用事件驱动的异步非阻塞模型,单机即可处理数万并发连接,内存占用极低——实测 10000 个非活跃 HTTP keep-alive 连接仅消耗约 2.5MB 内存。
从 2018 年开始在生产环境全面使用 Nginx 替代 Apache,目前管理着超过 200 台 Nginx 实例,日均处理请求量超过 5 亿次。本文将基于这些实战经验,系统梳理反向代理、负载均衡、SSL/TLS、缓存、限流等核心场景的配置与最佳实践。
1.2 技术特点
- 事件驱动异步非阻塞:基于 epoll(Linux)/ kqueue(BSD)实现,单个 worker 进程可处理数千并发连接,避免了类似 Apache prefork 模式每个连接占用一个进程的资源消耗模式。
- 模块化架构:由核心模块(ngx_http_core_module)、官方模块及丰富的第三方模块(如 ngx_http_geoip2_module、lua-nginx-module)组成,支持按需编译,不加载多余功能。
- 热加载配置:通过
nginx -s reload 命令可实现配置热更新,不中断正在处理的连接,是线上变更实现零停机时间的关键。
- 低资源消耗:实测对比,在同等 QPS 下,Nginx 的内存占用约为 Apache 的 1/10,CPU 使用率低 30%-50%。
1.3 适用场景
- Web 服务反向代理:将外部客户端请求转发到内部应用服务器(如 Tomcat、Node.js、Go 服务等),隐藏后端拓扑结构,实现统一入口管理。
- API 网关:基于 location 路由规则将不同 API 路径分发到对应的微服务,配合
limit_req 等模块可实现接口级的精细限流。
- 静态资源服务:直接托管 HTML、CSS、JS、图片等静态文件,配合 gzip 压缩和 open_file_cache 缓存,其吞吐量远超各类应用服务器。
- SSL/TLS 终结:在 Nginx 层统一处理 HTTPS 的加解密工作,后端服务只需处理明文的 HTTP 流量,有效降低了后端的复杂度和 CPU 开销。
- 流量分发与灰度发布:通过 upstream 权重、
split_clients 模块或 Lua 脚本,可以实现按比例分流、A/B 测试等高级流量管理功能。
1.4 环境要求
| 组件 |
版本要求 |
说明 |
| 操作系统 |
CentOS 7+ / Ubuntu 20.04+ |
推荐 Ubuntu 22.04 LTS 或 Rocky Linux 9,内核 5.x+ 支持更好的 epoll 特性 |
| Nginx |
1.24.0+ / 1.26.0+(mainline) |
1.24 为当前稳定版,1.26 为主线版本,生产环境建议使用稳定版 |
| OpenSSL |
1.1.1+ (推荐 3.0+) |
TLS 1.3 支持需要 OpenSSL 1.1.1+,Ubuntu 22.04 自带 OpenSSL 3.0 |
| GCC |
4.8+ |
编译安装时需要,通过包管理器安装可忽略此项 |
| PCRE |
8.x+ |
正则表达式支持,location 匹配依赖此库 |
| 硬件配置 |
2C4G 起步 |
纯代理场景 2C4G 可应对约 5000 QPS,若涉及 SSL 终结建议 4C8G 起步 |
二、详细步骤
2.1 准备工作
2.1.1 系统检查
在安装前,建议对系统进行基础检查。
# 检查系统版本
cat /etc/os-release
# 检查内核版本(建议 5.x+)
uname -r
# 检查可用内存和磁盘
free -h
df -h
# 检查当前是否已安装 Nginx
nginx -v 2>/dev/null && echo "Nginx 已安装" || echo "Nginx 未安装"
# 检查 80/443 端口是否被占用
ss -tlnp | grep -E ':80|:443'
2.1.2 安装依赖
根据不同的操作系统安装编译和运行依赖。
Ubuntu/Debian 系统:
sudo apt update && sudo apt upgrade -y
# 编译安装所需依赖
sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g-dev \
libssl-dev libgd-dev libgeoip-dev libmaxminddb-dev \
curl wget gnupg2 ca-certificates lsb-release
CentOS/Rocky Linux 系统:
sudo yum install -y epel-release
sudo yum groupinstall -y "Development Tools"
sudo yum install -y pcre pcre-devel zlib zlib-devel openssl openssl-devel \
gd gd-devel GeoIP GeoIP-devel libmaxminddb-devel \
curl wget
2.2 安装 Nginx
2.2.1 方式一:包管理器安装(推荐快速部署)
适合不需要自定义模块的快速部署场景,安装便捷,升级管理方便。
Ubuntu 添加 Nginx 官方源:
# 导入 Nginx 官方 GPG 密钥
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
# 添加官方源(稳定版)
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
# 设置优先使用官方源而非系统自带源
echo -e "Package: *\nPin: origin nginx.org\nPin-Priority: 900" | sudo tee /etc/apt/preferences.d/99nginx
# 安装
sudo apt update
sudo apt install -y nginx
# 验证版本
nginx -v
CentOS/Rocky Linux 添加 Nginx 官方源:
cat > /etc/yum.repos.d/nginx.repo << 'EOF'
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
sudo yum install -y nginx
nginx -v
2.2.2 方式二:编译安装(需要自定义模块时使用)
在需要集成 GeoIP2、Brotli 压缩、VTS 监控等第三方模块时,选择编译安装。
# 下载 Nginx 源码
cd /usr/local/src
wget https://nginx.org/download/nginx-1.24.0.tar.gz
tar -zxvf nginx-1.24.0.tar.gz
# 下载第三方模块(按需)
git clone https://github.com/leev/ngx_http_geoip2_module.git
git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli && git submodule update --init && cd ..
git clone https://github.com/vozlt/nginx-module-vts.git
# 编译安装
cd nginx-1.24.0
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_auth_request_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-pcre \
--with-threads \
--with-file-aio \
--add-module=/usr/local/src/ngx_http_geoip2_module \
--add-module=/usr/local/src/ngx_brotli \
--add-module=/usr/local/src/nginx-module-vts
make -j$(nproc)
sudo make install
编译安装后创建 systemd 服务文件:
cat > /etc/systemd/system/nginx.service << 'EOF'
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable nginx
sudo systemctl start nginx
2.3 反向代理配置
2.3.1 基础反向代理
反向代理的核心指令是 proxy_pass,但生产环境的配置远不止这一行。以下是经过线上验证的完整配置模板:
server {
listen 80;
server_name api.example.com;
# 日志
access_log /var/log/nginx/api_access.log main;
error_log /var/log/nginx/api_error.log warn;
location / {
proxy_pass http://127.0.0.1:8080;
# 传递真实客户端信息(这几个 header 必须配置,否则后端应用无法获取真实客户端 IP)
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;
# 超时设置(单位:秒)
# 生产环境建议根据后端服务的实际响应时间进行调整,默认 60s 对某些慢接口可能不够
proxy_connect_timeout 10; # 与后端服务器建立连接的超时时间,10s 通常足够,太长往往说明后端有问题
proxy_read_timeout 60; # 等待后端服务器响应的超时时间,报表类接口可能需要设置到 120s
proxy_send_timeout 30; # 向后端服务器发送请求的超时时间
# Buffer 配置
# 默认 buffer 大小(4k/8k)可能过小,若后端返回大 header(如带长 JWT token 的 Set-Cookie)会导致 502 错误
proxy_buffer_size 16k; # 用于读取后端响应头的 buffer,生产环境建议 16k
proxy_buffers 4 32k; # 用于读取后端响应体的 buffer 数量和大小
proxy_busy_buffers_size 64k; # 在响应未完全读取时,可以发送给客户端的最大 buffer 大小
# HTTP 1.1 长连接(减少与后端服务器的 TCP 握手开销)
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
特别注意:proxy_pass 指令末尾是否有斜杠 / 会导致完全不同的转发行为,这是最常见的配置陷阱:
# 假设客户端请求是 GET /api/users
# 写法一:proxy_pass 没有 URI 部分
location /api/ {
proxy_pass http://backend;
}
# 转发到后端服务器的路径:/api/users(原样转发)
# 写法二:proxy_pass 带了 URI 部分(末尾有 /)
location /api/ {
proxy_pass http://backend/;
}
# 转发到后端服务器的路径:/users(location 匹配的 `/api/` 被替换为 `/`)
# 写法三:proxy_pass 带了其他 URI
location /api/ {
proxy_pass http://backend/v2/;
}
# 转发到后端服务器的路径:/v2/users(location 匹配的 `/api/` 被替换为 `/v2/`)
这个规则一旦搞错就会导致后端大量 404 错误,线上曾因此多次出事故,务必牢记。
2.3.2 proxy_pass 与 upstream 配合
单独使用 proxy_pass http://127.0.0.1:8080 只能代理到单台后端。生产环境必须与 upstream 模块配合,实现负载均衡和高可用。
upstream backend_api {
server 10.0.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
server 10.0.1.11:8080 weight=5 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 weight=3 max_fails=3 fail_timeout=30s;
# 长连接池(减少 TCP 握手开销,实测可提升 QPS 15%-20%)
keepalive 64;
keepalive_timeout 60s;
keepalive_requests 1000;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend_api;
proxy_http_version 1.1;
proxy_set_header Connection "";
# ... 其他 proxy 配置同上文基础反向代理部分
}
}
2.4 负载均衡策略
2.4.1 轮询(Round Robin)—— 默认策略
upstream backend {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
最简单,请求依次分配到每台后端服务器。适合后端服务器配置相同、无状态的场景。
2.4.2 加权轮询(Weighted Round Robin)
upstream backend {
server 10.0.1.10:8080 weight=5; # 配置较高(如 8C16G)的机器,分配更多权重
server 10.0.1.11:8080 weight=5; # 配置较高的机器
server 10.0.1.12:8080 weight=2; # 配置较低(如 4C8G)的机器,分配较少权重
}
当后端机器配置不同时,使用权重进行差异化分配。weight 值越大,分到的请求越多。实践中,通常会按 CPU 核数比例来设置权重。
2.4.3 IP Hash(会话保持)
upstream backend {
ip_hash;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
根据客户端 IP 计算哈希值,确保同一客户端的请求始终被转发到同一台后端服务器。适用于未使用 Redis 等集中存储 Session 的老系统,需要会话保持的场景。
注意:如果客户端请求前方存在 CDN 或其他代理层,所有请求的源 IP 都会变成代理服务器的 IP,此时 ip_hash 会导致所有流量被打到同一台后端。在这种情况下,应使用 hash $http_x_forwarded_for consistent; 来替代。
2.4.4 最少连接(Least Connections)
upstream backend {
least_conn;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
将新请求分配给当前活跃连接数最少的后端服务器。适合后端请求处理时间差异较大的场景(例如,有的接口 50ms 返回,有的需要 5s)。
2.4.5 一致性哈希
upstream backend {
hash $request_uri consistent;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
根据 $request_uri(或其他变量)计算哈希值,确保相同 URI 的请求始终路由到同一台后端。这适用于后端服务器有本地缓存(非共享缓存)的场景。添加 consistent 参数启用一致性哈希算法,在增减后端节点时,只有少量请求的路由会发生变化,影响面更小。
2.4.6 健康检查配置
Nginx 开源版默认提供被动式健康检查,通过 max_fails 和 fail_timeout 参数实现:
upstream backend {
server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 max_fails=3 fail_timeout=30s backup; # 备用节点
}
参数说明:
max_fails=3:在 fail_timeout 时间窗口内,连接失败 3 次后,标记该节点为不可用。
fail_timeout=30s:有两层含义:① 统计失败次数的时间窗口长度;② 节点被标记为不可用后,等待恢复的时间。
backup:标记为备用节点,只有在所有主节点都不可用时才会启用。
注意:被动健康检查存在延迟,节点故障后,最初的几个请求仍会失败。如果需要主动健康检查,要么使用 Nginx Plus(商业版),要么编译第三方模块 nginx_upstream_check_module:
upstream backend {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
# 主动健康检查(需要编译 nginx_upstream_check_module)
check interval=3000 rise=2 fall=3 timeout=2000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
2.5 SSL/TLS 配置
2.5.1 Let's Encrypt 证书申请
# 安装 certbot
sudo apt install -y certbot python3-certbot-nginx
# 申请证书(自动修改 Nginx 配置)
sudo certbot --nginx -d example.com -d www.example.com
# 或者只申请证书不修改配置(推荐,手动控制配置更安全)
sudo certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com
# 测试自动续期
sudo certbot renew --dry-run
# 设置自动续期定时任务
echo "0 3 * * * root certbot renew --quiet --post-hook 'systemctl reload nginx'" | sudo tee /etc/cron.d/certbot-renew
2.5.2 TLS 1.3 + 安全配置
server {
listen 443 ssl http2;
server_name example.com;
# 证书路径
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS 协议版本(只启用安全的 TLS 1.2 和 1.3,禁用 1.0/1.1)
ssl_protocols TLSv1.2 TLSv1.3;
# 加密套件(TLS 1.3 的套件由客户端和服务端自动协商,这里主要配置 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;
ssl_prefer_server_ciphers on;
# SSL 会话缓存(减少 TLS 握手开销)
ssl_session_cache shared:SSL:20m; # 20MB 缓存空间约可存储 80000 个会话
ssl_session_timeout 1d;
ssl_session_tickets off; # 禁用 session ticket,安全性更高
# OCSP Stapling(加速客户端证书验证)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS(强制浏览器使用 HTTPS 访问,max-age 建议至少 1 年)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}
# HTTP 强制跳转 HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
2.6 缓存配置
2.6.1 proxy_cache 配置
# 在 http 块中定义缓存路径和参数
http {
proxy_cache_path /var/cache/nginx/proxy_cache
levels=1:2 # 两级目录结构,避免单目录文件过多影响性能
keys_zone=my_cache:50m # 缓存 key 的共享内存存储区,50MB 约可存储 40 万个 key
max_size=10g # 缓存最大占用磁盘空间
inactive=60m # 60 分钟内未被访问的缓存条目自动清除
use_temp_path=off; # 直接写入缓存目录,不用临时目录(减少一次 IO 操作)
}
server {
listen 80;
server_name static.example.com;
location / {
proxy_pass http://backend;
# 启用缓存
proxy_cache my_cache;
proxy_cache_valid 200 302 10m; # 200/302 响应缓存 10 分钟
proxy_cache_valid 301 1h; # 301 响应缓存 1 小时
proxy_cache_valid 404 1m; # 404 响应缓存 1 分钟(防止缓存穿透攻击)
# 缓存 key(默认是 $scheme$proxy_host$request_uri)
proxy_cache_key $scheme$host$request_uri;
# 添加响应头,方便排查缓存是否命中
add_header X-Cache-Status $upstream_cache_status;
# 后端故障时,允许使用过期的缓存进行兜底
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# 防止缓存击穿:同一个 key 只允许一个请求回源,其他请求等待
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
}
# 不缓存带有 Cookie 或 Authorization 头的请求(通常为个性化请求)
location /api/ {
proxy_pass http://backend_api;
proxy_cache my_cache;
proxy_no_cache $http_authorization $cookie_session;
proxy_cache_bypass $http_authorization $cookie_session;
}
}
X-Cache-Status 响应头的值含义:
HIT:缓存命中
MISS:缓存未命中,已回源
EXPIRED:缓存已过期,已回源更新
STALE:使用了过期缓存(后端故障兜底)
BYPASS:跳过缓存直接回源
2.7 限流配置
2.7.1 请求速率限制(漏桶算法)
http {
# 定义限流区域:按客户端 IP 限流,每秒 10 个请求
# zone=api_limit:10m 表示分配 10MB 内存存储限流状态(约可存储 16 万个 IP 的状态)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# 针对 API 接口的更严格限流
limit_req_zone $binary_remote_addr zone=login_limit:5m rate=1r/s;
server {
listen 80;
server_name api.example.com;
location /api/ {
# burst=20:允许突发 20 个请求排队
# nodelay:排队的请求立即处理,不延迟(超过 burst 数量的请求直接返回 429)
limit_req zone=api_limit burst=20 nodelay;
limit_req_status 429; # 超过限制时返回 429 状态码,而非默认的 503
proxy_pass http://backend_api;
}
# 登录接口严格限流,防止暴力破解
location /api/login {
limit_req zone=login_limit burst=5 nodelay;
limit_req_status 429;
proxy_pass http://backend_api;
}
}
}
burst 和 nodelay 参数的区别:
- 不加
burst:超过 rate 的请求被直接拒绝。
- 加
burst 不加 nodelay:超过 rate 的请求进入队列,按 rate 速率依次处理。
- 加
burst 加 nodelay:超过 rate 但在 burst 范围内的请求立即处理(不排队),超过 burst 的直接拒绝。
生产环境通常推荐使用 burst=N nodelay 模式,既能应对合理的突发流量,又不会让用户等待过久。
2.7.2 连接数限制
http {
# 按 IP 限制并发连接数
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
# 每个 IP 最多 50 个并发连接
limit_conn conn_limit 50;
limit_conn_status 429;
# 限制下载速度(防止单个用户占满带宽)
location /download/ {
limit_conn conn_limit 5; # 下载目录每 IP 最多 5 个并发连接
limit_rate_after 10m; # 前 10MB 不限速
limit_rate 1m; # 10MB 之后限速 1MB/s
}
}
}
三、示例代码和配置
3.1 完整配置示例
3.1.1 生产级 nginx.conf 主配置文件
这份配置在线上环境稳定运行超过两年,单机曾扛住超过 30000 QPS 的流量压力。
# 文件路径:/etc/nginx/nginx.conf
# worker 进程数,auto 会自动设为 CPU 核数
worker_processes auto;
# 绑定 CPU 亲和性(减少 CPU 上下文切换,4 核示例)
# auto 参数在 1.9.10+ 可用,自动绑定
worker_cpu_affinity auto;
# 单个 worker 进程可打开的最大文件描述符数
# 这个值必须 >= worker_connections,否则高并发时会报 "too many open files"
worker_rlimit_nofile 65535;
# 错误日志级别,生产环境用 warn,排查问题时临时改为 info 或 debug
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
# 单个 worker 的最大并发连接数
# 总并发 = worker_processes × worker_connections
# 作为反向代理时,每个客户端连接会占用 2 个连接(客户端→Nginx + Nginx→后端)
# 所以实际可服务的客户端数 = worker_processes × worker_connections / 2
worker_connections 65535;
# 一次性接受所有新连接(高并发场景建议开启)
multi_accept on;
# Linux 下用 epoll,性能最好
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 自定义日志格式(包含 upstream 响应时间,排查慢请求必备)
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time urt=$upstream_response_time '
'ua=$upstream_addr us=$upstream_status '
'cs=$upstream_cache_status';
# 日志缓冲写入(减少磁盘 IO,实测 IOPS 降低 60%)
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
# 零拷贝发送文件(静态文件场景性能提升明显)
sendfile on;
# 配合 sendfile 使用,数据包攒够再发(减少网络包数量)
tcp_nopush on;
# 小数据包立即发送(与 tcp_nopush 不冲突,Nginx 会在最后一个包时启用 nodelay)
tcp_nodelay on;
# 长连接超时
keepalive_timeout 65;
keepalive_requests 1000;
# 隐藏 Nginx 版本号(安全加固,防止针对特定版本的攻击)
server_tokens off;
# 请求体大小限制(默认 1m,上传文件场景需要调大)
client_max_body_size 50m;
# 请求头 buffer(默认 1k,带大 Cookie 或长 URL 时会报 414/400 错误)
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;
# Gzip 压缩
gzip on;
gzip_min_length 1k; # 小于 1k 的内容不压缩(压缩后可能更大)
gzip_comp_level 4; # 压缩级别 1-9,4 是性价比最高的(实测)
gzip_types text/plain text/css text/javascript
application/json application/javascript application/xml
application/xml+rss image/svg+xml;
gzip_vary on; # 添加 Vary: Accept-Encoding 头
gzip_proxied any; # 对代理请求也启用压缩
gzip_disable "MSIE [1-6]\."; # IE6 不支持 gzip
# 文件描述符缓存(频繁访问的静态文件不用每次 open/stat)
open_file_cache max=65535 inactive=60s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# 加载虚拟主机配置
include /etc/nginx/conf.d/*.conf;
}
3.1.2 多后端路由配置
实际项目中,一个域名下通常有多个后端服务。以下是典型的前后端分离 + API 网关配置示例:
# 文件路径:/etc/nginx/conf.d/app.example.com.conf
# 后端 API 服务集群
upstream backend_api {
least_conn;
server 10.0.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
server 10.0.1.11:8080 weight=5 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 weight=3 max_fails=3 fail_timeout=30s;
keepalive 64;
keepalive_timeout 60s;
keepalive_requests 1000;
}
# 用户服务集群
upstream user_service {
server 10.0.2.10:9001 max_fails=3 fail_timeout=30s;
server 10.0.2.11:9001 max_fails=3 fail_timeout=30s;
keepalive 32;
}
# 订单服务集群
upstream order_service {
server 10.0.3.10:9002 max_fails=3 fail_timeout=30s;
server 10.0.3.11:9002 max_fails=3 fail_timeout=30s;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
# 前端静态文件服务
location / {
root /var/www/app/dist;
index index.html;
try_files $uri $uri/ /index.html; # 支持 SPA 单页应用路由
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
# API 总入口
location /api/ {
proxy_pass http://backend_api;
include /etc/nginx/snippets/proxy-params.conf;
}
# 用户服务路由
location /api/users/ {
proxy_pass http://user_service/;
include /etc/nginx/snippets/proxy-params.conf;
}
# 订单服务路由
location /api/orders/ {
proxy_pass http://order_service/;
include /etc/nginx/snippets/proxy-params.conf;
proxy_read_timeout 120s; # 订单服务有慢查询,超时时间设长一些
}
# 健康检查端点(供负载均衡器或监控系统探测)
location /health {
access_log off;
return 200 "OK\n";
add_header Content-Type text/plain;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
公共代理参数抽取为 snippet,避免重复配置:
# 文件路径:/etc/nginx/snippets/proxy-params.conf
proxy_http_version 1.1;
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 Connection "";
proxy_connect_timeout 10;
proxy_read_timeout 60;
proxy_send_timeout 30;
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_next_upstream error timeout http_500 http_502 http_503;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 10s;
3.1.3 WebSocket 代理配置
WebSocket 代理是个高频需求,配置不对会导致连接建立后立刻断开。关键在于正确传递 Upgrade 和 Connection 头。
# 文件路径:/etc/nginx/conf.d/ws.example.com.conf
# 用 map 指令动态设置 Connection 头
# 当客户端请求头包含 `Upgrade: websocket` 时,Connection 设为 "upgrade"
# 否则设为 "close"(普通 HTTP 请求使用长连接)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket_backend {
server 10.0.4.10:3000;
server 10.0.4.11:3000;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name ws.example.com;
ssl_certificate /etc/letsencrypt/live/ws.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ws.example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
location /ws/ {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
# WebSocket 代理必须设置的两个头
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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;
# WebSocket 连接超时设置
# 默认 60s 没有数据传输就断开,生产环境建议设长一些
# 需配合客户端心跳机制使用
proxy_read_timeout 3600s; # 1 小时
proxy_send_timeout 3600s;
}
# 普通 HTTP 请求
location / {
proxy_pass http://websocket_backend;
include /etc/nginx/snippets/proxy-params.conf;
}
}
注意:proxy_read_timeout 对 WebSocket 连接至关重要。如果客户端和服务端之间没有心跳机制,Nginx 会在 proxy_read_timeout 设定的时间后断开连接。建议客户端每 30 秒发送一次 ping 帧,并将 proxy_read_timeout 设置为 3600s。
3.1.4 多虚拟主机 HTTPS 配置(SNI)
在同一台 Nginx 服务器上托管多个 HTTPS 站点,依赖 SNI(Server Name Indication)扩展。现代浏览器和操作系统均已支持 SNI,无需担心兼容性问题。
# 文件路径:/etc/nginx/conf.d/multi-vhost.conf
# 站点一:主站
server {
listen 443 ssl http2;
server_name www.example.com example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
# 站点二:管理后台(限制内网访问)
server {
listen 443 ssl http2;
server_name admin.example.com;
ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
# 管理后台限制 IP 访问
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
location / {
proxy_pass http://127.0.0.1:8081;
include /etc/nginx/snippets/proxy-params.conf;
}
}
# 站点三:API 服务
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
location / {
proxy_pass http://backend_api;
include /etc/nginx/snippets/proxy-params.conf;
}
}
# 默认站点(未匹配到任何 server_name 的请求直接拒绝)
server {
listen 443 ssl http2 default_server;
server_name _;
ssl_certificate /etc/nginx/ssl/default.pem;
ssl_certificate_key /etc/nginx/ssl/default.key;
return 444; # Nginx 特殊状态码,直接关闭连接,不发送任何响应
}
SSL 公共参数 snippet:
# 文件路径:/etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1.2 TLSv1.3;
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;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
3.2 实际应用案例
案例一:灰度发布(按权重分流)
场景描述:新版本上线前,先将 10% 的流量切到新版本(v2),观察一段时间确认无问题后再全量切换。
实现代码:
# 新旧版本 upstream 定义
upstream backend_v1 {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
upstream backend_v2 {
server 10.0.2.10:8080;
server 10.0.2.11:8080;
}
# 按比例分流:10% 流量到 v2,90% 流量到 v1
split_clients $request_id $backend_version {
10% backend_v2;
* backend_v1;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://$backend_version;
include /etc/nginx/snippets/proxy-params.conf;
# 添加响应头标识版本,方便排查问题
add_header X-Backend-Version $backend_version;
}
}
运行验证:
# 多次请求查看分流效果
for i in $(seq 1 100); do
curl -s -o /dev/null -w "%{http_code} " -H "Host: app.example.com" http://localhost
done
# 输出结果中,大约有 90 次请求走 v1 版本,10 次走 v2 版本
案例二:基于 Cookie 的灰度发布
场景描述:内部测试人员通过设置特定的 Cookie 来访问新版本,普通用户继续访问稳定版本。
实现步骤:
map $cookie_canary $target_backend {
"true" backend_v2;
default backend_v1;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://$target_backend;
include /etc/nginx/snippets/proxy-params.conf;
}
}
测试人员在浏览器中设置 Cookie canary=true 后,其所有请求将被路由到新版本后端,无需修改任何前端代码或配置。
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 Worker 调优
-
worker_processes:建议设置为 auto,Nginx 会自动将其设置为 CPU 核数。手动设置时不应超过 CPU 核数,否则会增加不必要的上下文切换开销。
# 查看 CPU 核数
nproc
# 查看当前 Nginx worker 进程数
ps aux | grep "nginx: worker" | grep -v grep | wc -l
-
worker_rlimit_nofile:必须设置为 65535 或更高。如果未设置,worker 进程能打开的文件描述符数将受系统默认限制(通常为 1024),高并发时会导致 "too many open files" 错误。
# 同时修改系统级限制
cat >> /etc/security/limits.conf << 'EOF'
nginx soft nofile 65535
nginx hard nofile 65535
* soft nofile 65535
* hard nofile 65535
EOF
# 修改 systemd 服务限制:在 [Service] 段添加 `LimitNOFILE=65535`
-
worker_connections 计算方法:
- 纯静态文件服务:最大并发客户端数 =
worker_processes × worker_connections
- 反向代理服务:最大并发客户端数 =
worker_processes × worker_connections / 2 (每个客户端连接占用 2 个连接:客户端到 Nginx,Nginx 到后端)
- 生产环境通常设置为 65535 即可,瓶颈通常不在此处。
4.1.2 性能优化
-
sendfile + tcp_nopush + tcp_nodelay 三件套:
sendfile on; # 启用零拷贝,静态文件传输不经过用户态
tcp_nopush on; # 在数据包被填满后再发送,减少网络包数量(需配合 sendfile 使用)
tcp_nodelay on; # 最后一个数据包立即发送,减少延迟(与 tcp_nopush 不冲突)
Nginx 内部会协调这两个参数:发送大文件时利用 tcp_nopush 减少包数量,发送最后一个小包时启用 tcp_nodelay 降低延迟。实测可提升静态文件吞吐量 20%-30%。
-
Gzip 压缩配置:
gzip on;
gzip_min_length 1k;
gzip_comp_level 4; # 实测压缩级别 4 和 9 的压缩率差距不到 5%,但 CPU 开销相差 3 倍
gzip_types text/plain text/css text/javascript
application/json application/javascript
application/xml application/xml+rss
image/svg+xml;
gzip_vary on;
gzip_proxied any;
gzip_buffers 16 8k;
注意:不要对图片(jpg/png/gif)和已压缩文件(zip/gz)开启 gzip,因为它们本身已是压缩格式,再次压缩反而可能增加体积并浪费 CPU。
-
open_file_cache 文件缓存:
# 缓存文件描述符、文件大小、修改时间等信息
open_file_cache max=65535 inactive=60s;
open_file_cache_valid 30s; # 每 30s 检查一次缓存条目是否过期
open_file_cache_min_uses 2; # 文件至少被访问 2 次后才被缓存
open_file_cache_errors on; # 缓存文件不存在的查询结果(减少无效的磁盘查找)
对于静态资源服务器,此配置能显著减少高并发下的 stat() 和 open() 系统调用。实测可降低 CPU 使用率 10%-15%。
# 文件路径:/etc/nginx/snippets/security-headers.conf
# 防止页面被嵌入 iframe(防点击劫持)
add_header X-Frame-Options "SAMEORIGIN" always;
# 防止浏览器猜测 MIME 类型(防 XSS)
add_header X-Content-Type-Options "nosniff" always;
# 启用浏览器的 XSS 过滤(现代浏览器已内置,但加上无害)
add_header X-XSS-Protection "1; mode=block" always;
# 控制 Referer 头的发送策略,保护用户隐私
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 内容安全策略(需根据实际业务资源调整)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;
# 权限策略(禁用不需要的浏览器功能)
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
在 server 块中引用:
server {
# ...
include /etc/nginx/snippets/security-headers.conf;
}
4.1.4 高可用方案:Keepalived + VIP 双机热备
单台 Nginx 是单点故障。生产环境至少应部署两台,并使用 Keepalived 实现虚拟 IP(VIP)漂移,构成双机热备。
主节点配置(假设 IP 为 10.0.0.10):
- 安装 Keepalived:
sudo apt install -y keepalived
- 配置
/etc/keepalived/keepalived.conf:
global_defs {
router_id nginx_master
script_user root
enable_script_security
}
Nginx 健康检查脚本
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2 # 每 2 秒检查一次
weight -20 # 检查失败时优先级减 20
fall 3 # 连续失败 3 次才判定为故障
rise 2 # 连续成功 2 次才判定为恢复
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100 # 主节点优先级设为 100
advert_int 1 # VRRP 通告间隔 1 秒
authentication {
auth_type PASS
auth_pass K8s@Nginx2026 # 主备节点密码必须一致
}
virtual_ipaddress {
10.0.0.100/24 # 虚拟 IP(VIP)地址
}
track_script {
check_nginx
}
}
3. 创建健康检查脚本 `/etc/keepalived/check_nginx.sh`:
```bash
#!/bin/bash
if ! pidof nginx > /dev/null 2>&1; then
# Nginx 进程不存在,尝试重启
systemctl restart nginx
sleep 2
if ! pidof nginx > /dev/null 2>&1; then
# 重启失败,退出码非 0 将触发 VIP 漂移
exit 1
fi
fi
exit 0
chmod +x /etc/keepalived/check_nginx.sh
sudo systemctl enable keepalived
sudo systemctl start keepalived
备节点配置(假设 IP 为 10.0.0.11):与主节点配置基本相同,仅需修改以下参数:
state BACKUP
priority 90 (优先级低于主节点)
router_id nginx_backup
实测 VIP 漂移耗时约为 3-5 秒,对于大部分业务场景是可接受的。
4.1.5 日志优化
-
缓冲写入:默认每条请求都会立即写入磁盘,高并发下磁盘 IO 易成瓶颈。
# buffer=32k:攒够 32KB 日志数据再写入磁盘
# flush=5s:最多等待 5 秒强制刷盘(防止日志延迟太久)
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
-
自定义 log_format(务必包含上下游时间):
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time '
'urt=$upstream_response_time '
'ua=$upstream_addr '
'us=$upstream_status '
'cs=$upstream_cache_status';
$request_time 是从 Nginx 收到请求到返回响应的总耗时,$upstream_response_time 是后端服务器的处理耗时。两者的差值即为 Nginx 自身的处理开销。排查慢请求时这两个字段必不可少。
-
按天切割日志(使用 logrotate):
# 文件路径:/etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 nginx adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}
-
关闭不必要的访问日志:
# 健康检查、favicon 等请求不记录访问日志
location /health {
access_log off;
return 200 "OK\n";
}
location = /favicon.ico {
access_log off;
log_not_found off;
}
4.2 注意事项
4.2.1 配置注意事项
proxy_pass 末尾斜杠问题极易导致线上事故,修改配置前务必在测试环境充分验证。
location 匹配路径与 proxy_pass 的 URI 拼接规则容易混淆,修改前务必使用 curl -v 在测试环境验证实际转发路径。
nginx -t 命令仅检查配置文件语法,不检查后端服务器是否可达。修改配置后,应先执行 nginx -t,确认语法无误后再执行 nginx -s reload。
reload 操作不会中断正在处理的连接,但如果新配置存在语法错误,reload 会失败且不会影响当前正在运行的配置。
4.2.2 常见错误与排查
| 错误现象 |
原因分析 |
解决方案 |
| 502 Bad Gateway |
后端服务进程挂掉 / proxy_buffer_size 设置过小 / 后端连接数耗尽 |
检查后端服务进程状态;增大 proxy_buffer_size 至 16k 或 32k;检查并调整后端服务的最大连接数配置 |
| 504 Gateway Timeout |
proxy_read_timeout 设置过短 / 后端服务处理过慢或有慢查询 |
适当增大 proxy_read_timeout;优化后端应用代码或数据库慢查询 |
| 413 Request Entity Too Large |
请求体大小超过 client_max_body_size 默认值 (1m) |
根据业务需求调大,例如 client_max_body_size 50m; |
| 414 Request-URI Too Large |
请求 URI 过长,超过 large_client_header_buffers 限制 |
增大配置,例如 large_client_header_buffers 4 32k; |
| upstream timed out (110) |
后端服务器响应超时 |
检查后端服务负载情况;适当增大 proxy_read_timeout |
| no live upstreams |
upstream 中所有后端节点均被标记为不可用 |
检查后端服务健康状态;调整 max_fails 和 fail_timeout 参数 |
4.2.3 兼容性问题
- HTTP/2 与
proxy_pass:Nginx 作为反向代理时,到后端服务器的连接只支持 HTTP/1.1,不支持 HTTP/2。proxy_http_version 1.1; 是必须的配置项,不要尝试设置为 2.0。
- WebSocket 与 HTTP/2:在 HTTP/2 连接下代理 WebSocket 需要 Nginx 1.25.1+ 版本支持。低版本若需同时支持 HTTP/2 和 WebSocket,可能需要为 WebSocket 单独监听一个非 HTTP/2 的端口。
- TLS 1.3 与旧客户端:Android 4.x、IE 10 及以下版本不支持 TLS 1.2。如果业务必须兼容这些老旧设备,则需要在
ssl_protocols 中保留 TLSv1.2。
- gzip 与 ETag:Nginx 对响应内容进行 gzip 压缩后,会移除强验证器 ETag(因为内容已被改变)。如果客户端或下游服务依赖 ETag 进行缓存验证,需要注意这一行为。
五、故障排查和监控
5.1 故障排查
5.1.1 日志查看命令
# 实时查看错误日志(故障排查第一步)
sudo tail -f /var/log/nginx/error.log
# 实时查看访问日志
sudo tail -f /var/log/nginx/access.log
# 查看最近 50 条 5xx 错误请求
awk '$9 ~ /^5/' /var/log/nginx/access.log | tail -50
# 统计各 HTTP 状态码的数量
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 查看慢请求(响应时间超过 3 秒)
awk -F'rt=' '{split($2,a," "); if(a[1]+0 > 3) print $0}' /var/log/nginx/access.log | tail -20
# 查看后端响应时间排序(找出最慢的后端服务器)
awk -F'urt=' '{split($2,a," "); if(a[1]+0 > 0) print a[1], $0}' /var/log/nginx/access.log | sort -rn | head -20
5.1.2 常见问题排查流程
问题一:502 Bad Gateway
这是最常见的问题,原因通常有三类:
# 1. 检查后端服务进程是否存活
curl -v http://10.0.1.10:8080/health
# 2. 检查后端服务器连接数是否耗尽
ss -s
ss -tnp | grep 8080 | wc -l
# 3. 检查 Nginx 错误日志中的具体报错信息
grep "502" /var/log/nginx/error.log | tail -20
解决方案:
- 后端服务挂掉:重启后端服务,并检查其后端应用日志和系统日志,查找根本原因。
- 连接数耗尽:增大后端应用服务的最大连接数配置;在 Nginx 侧适当增大 upstream 的
keepalive 连接池大小。
- Buffer 不足:后端返回的 HTTP 头部过大(常见于携带大型 JWT 的
Set-Cookie 头),需增大 proxy_buffer_size 至 16k 或 32k。
proxy_buffer_size 32k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
问题二:upstream timed out (110: Connection timed out)
# 检查后端服务的实际响应时间
curl -o /dev/null -s -w "time_total: %{time_total}s\n" http://10.0.1.10:8080/api/slow-endpoint
# 检查 Nginx 当前的超时配置
nginx -T 2>/dev/null | grep -E "proxy_(connect|read|send)_timeout"
# 检查后端数据库或服务是否有慢查询
# 例如检查 MySQL 慢查询日志
tail -20 /var/log/mysql/slow.log
解决方案:
- 后端服务处理过慢:优化后端应用代码、SQL 查询或引入缓存,这是根本解决之道。
- 临时调整:适当增大
proxy_read_timeout,但切勿无限制调大,以免掩盖真实问题。
- 差异化配置:对于报表生成等已知的慢接口,可单独设置更长的超时时间。
location /api/reports/ {
proxy_pass http://backend_api;
proxy_read_timeout 300s; # 报表类接口允许 5 分钟超时
}
问题三:413 Request Entity Too Large
# 查看当前 Nginx 配置中 client_max_body_size 的值
nginx -T 2>/dev/null | grep client_max_body_size
解决方案:
# 在 http 或 server 块进行全局设置
client_max_body_size 50m;
# 或针对特定的上传接口单独设置
location /api/upload {
client_max_body_size 500m;
proxy_pass http://backend_api;
proxy_read_timeout 300s; # 大文件上传耗时较长
proxy_request_buffering off; # 禁用请求体缓冲,边接收边转发(节省 Nginx 内存)
}
问题四:SSL 证书问题排查
5.1.3 调试模式
# 临时开启 debug 级别日志(会产生大量日志,排查完毕后请立即关闭)
# 注意:Nginx 需在编译时已添加 --with-debug 参数
# 在 nginx.conf 的 main 段设置:
error_log /var/log/nginx/error.log debug;
# 仅对特定 IP 或网段开启 debug 连接日志(推荐,减少日志量)
events {
debug_connection 10.0.0.100;
debug_connection 192.168.1.0/24;
}
# 查看完整的 Nginx 配置(包含所有 include 文件展开后的结果)
nginx -T
# 测试配置文件语法
nginx -t
5.2 性能监控
5.2.1 stub_status 基础监控
Nginx 内置的 stub_status 模块可提供基础的连接状态信息,成本为零。
# 在 server 块中添加(务必限制只允许内网或本机访问)
server {
listen 8080;
server_name localhost;
allow 10.0.0.0/8;
allow 127.0.0.1;
deny all;
location /nginx_status {
stub_status on;
access_log off;
}
}
访问验证:
curl http://127.0.0.1:8080/nginx_status
输出示例:
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
各字段含义:
Active connections:当前活跃连接总数(包含 Waiting 状态的连接)。
accepts:Nginx 已经接受的总连接数。
handled:Nginx 已经处理的总连接数(正常情况下应等于 accepts)。
requests:Nginx 已经处理的总请求数(一个连接上可以发起多个请求)。
Reading:正在读取请求头的连接数。
Writing:正在向客户端发送响应的连接数。
Waiting:保持活跃(keep-alive)且当前空闲等待请求的连接数。
5.2.2 Prometheus + Grafana 监控
生产环境推荐使用 nginx-prometheus-exporter 采集指标,并集成到 Prometheus 和 Grafana 中。
-
安装并启动 nginx-prometheus-exporter:
wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v1.1.0/nginx-prometheus-exporter_1.1.0_linux_amd64.tar.gz
tar -zxvf nginx-prometheus-exporter_1.1.0_linux_amd64.tar.gz
sudo mv nginx-prometheus-exporter /usr/local/bin/
# 启动 exporter,指向 stub_status 地址
nginx-prometheus-exporter -nginx.scrape-uri=http://127.0.0.1:8080/nginx_status -web.listen-address=:9113
-
创建 systemd 服务文件 (/etc/systemd/system/nginx-exporter.service):
[Unit]
Description=Nginx Prometheus Exporter
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/nginx-prometheus-exporter \
-nginx.scrape-uri=http://127.0.0.1:8080/nginx_status \
-web.listen-address=:9113
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
-
在 Prometheus 配置中新增抓取任务 (prometheus.yml):
scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['10.0.0.10:9113', '10.0.0.11:9113']
labels:
env: 'production'
5.2.3 关键监控指标说明
| 指标名称 |
正常范围 |
告警阈值 |
说明 |
| Active connections |
< worker_connections 总数的 70% |
> 80% |
接近上限时需要扩容服务器或优化配置 |
| 5xx 错误率 |
< 0.1% |
> 1% |
持续高于 1% 通常表明后端服务存在严重问题 |
| 请求延迟 P99 |
< 500ms |
> 2s |
通过 access_log 中的 $request_time 统计 |
| upstream 响应时间 P99 |
< 300ms |
> 1s |
通过 access_log 中的 $upstream_response_time 统计 |
| 连接丢弃率 |
0 |
> 0 |
accepts - handled > 0 说明有连接被异常丢弃 |
5.2.4 Prometheus 告警规则示例
# 文件路径:/etc/prometheus/rules/nginx-alerts.yml
groups:
- name: nginx_alerts
rules:
- alert: NginxDown
expr: nginx_up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Nginx 实例 {{ $labels.instance }} 宕机"
- alert: NginxHighConnections
expr: nginx_connections_active / nginx_connections_accepted > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "Nginx 活跃连接数过高: {{ $value | humanizePercentage }}"
- alert: NginxHighRequestRate
expr: rate(nginx_http_requests_total[5m]) > 10000
for: 5m
labels:
severity: warning
annotations:
summary: "Nginx QPS 超过 10000: {{ $value | humanize }}"
六、总结
6.1 技术要点回顾
- 反向代理配置:
proxy_pass 配合正确的 proxy_set_header 是基础,proxy_buffer_size 和各种超时参数是生产环境必须调优的项,proxy_pass 末尾斜杠的 URI 替换规则必须清晰掌握。
- 负载均衡策略选择:无状态服务优先使用
least_conn;需要会话保持可选用 ip_hash 或 hash;若后端有本地缓存,则一致性哈希是更优选择。健康检查参数 max_fails 和 fail_timeout 应根据业务对故障的容忍度进行设置。
- SSL/TLS 安全配置:只启用 TLS 1.2 和 1.3,配置 HSTS 和 OCSP Stapling,证书文件务必使用包含完整证书链的
fullchain.pem。
- 性能调优组合:
worker_processes auto + worker_connections 65535 + sendfile/tcp_nopush/tcp_nodelay 三件套 + 合理的 gzip 压缩 + open_file_cache,这套组合拳实测能让单机 QPS 提升 50% 以上。
- 高可用架构:采用 Keepalived + VIP 实现双机热备,VIP 漂移可在 3-5 秒内完成,再结合 upstream 的健康检查机制,可实现后端故障的自动摘除与恢复。
6.2 进阶学习方向
- OpenResty / Lua 扩展:基于
lua-nginx-module 可以实现复杂的业务逻辑,如动态路由、自定义鉴权、复杂限流等,比纯 Nginx 配置灵活得多。
- 学习资源:OpenResty 官方文档。
- 实践建议:从简单的
access_by_lua_block 实现鉴权开始,逐步深入。
- Nginx Plus 商业版特性:主动健康检查、动态 upstream 管理、JWT 鉴权、实时监控 Dashboard 等高级功能。
- 学习资源:Nginx Plus 官方文档。
- 实践建议:如果团队规模较大、对系统稳定性和可观测性要求极高,商业版的特性值得投入。
- Service Mesh 与 Nginx:在 Kubernetes 环境中,Nginx Ingress Controller 是最常用的入口网关之一。理解其与 Service Mesh(如 Istio、Linkerd)的协作模式是云原生架构下的重要技能。
6.3 参考资料
- Nginx 官方文档
nginx.org - 最权威的配置指令参考。
- Mozilla SSL 配置生成器
ssl-config.mozilla.org - 可根据兼容性需求自动生成 SSL 配置。
- 本文涉及的相关配置与脚本,可在
云栈社区 等技术论坛交流获取。
参考资料
[1] Nginx 反向代理与负载均衡配置详解(2026 最新版), 微信公众号:https://mp.weixin.qq.com/s/Z8zIe8JZk0RzQdfTKHuQ0g
版权声明:本文由 云栈社区 整理发布,版权归原作者所有。