Nginx 作为现代 Web 架构的基石,已经成为每个开发者必须掌握的技能。我第一次接触 Nginx 是在 2013 年,当时还在用 Apache 做负载均衡,切换后发现性能直接提升了 3 倍。对于新手来说,理解 Nginx 的核心定位至关重要——它本质上是一个高性能的事件驱动型 Web 服务器,但通过模块化设计实现了远超传统服务器的功能扩展性。
在实际生产环境中,Nginx 通常同时扮演着多重角色:
静态资源服务器:这是最基础的功能。Nginx 处理静态文件的性能是 Apache 的 10 倍以上,我的个人博客在切换到 Nginx 后,TTFB(首字节时间)从 200ms 降到了 50ms 以内。关键配置在 location 块中的 root 或 alias 指令,配合 expires 设置缓存策略。
反向代理服务器:这是现代微服务架构中的关键组件。当用户请求到达 Nginx 时,它会根据配置将请求转发到后端的应用服务器(如 Node.js、Spring Boot 等)。这里最易出错的是 proxy_set_header 的配置,我曾因为漏掉 Host 头导致后端服务无法正确处理请求。
负载均衡器:通过 upstream 模块,Nginx 可以将流量分发到多个后端服务器。在我的电商项目实践中,采用 least_conn(最少连接)算法比默认的轮询(round-robin)在高峰期减少了 15% 的响应时间。
SSL 终端:处理 HTTPS 加密解密工作,减轻后端服务器负担。Let's Encrypt 证书配合 Nginx 的 ssl_stapling 配置,可以使 TLS 握手时间缩短 30%。
早期我同时维护 Apache 和 Nginx 的服务器,通过对比发现几个决定性差异:
资源占用:相同流量下,Nginx 的内存消耗只有 Apache 的 1/5。在 1GB 内存的 VPS 上,Apache 在 1000 并发时就崩溃了,而 Nginx 轻松应对 5000+ 并发。
事件模型:Nginx 使用异步非阻塞模型,而 Apache 是多进程/多线程模型。这就像餐厅服务模式的区别——Apache 是每个顾客配一个服务员(进程),而 Nginx 是一个服务员同时照顾多个顾客(事件驱动)。
配置语法:Nginx 的配置更加简洁直观。Apache 的 .htaccess 虽然灵活,但在高性能场景下反而成为负担。我迁移一个 WordPress 站点时,去掉 .htaccess 后性能提升了 40%。
关键经验:新项目直接上 Nginx,老项目如果使用 Apache 的特性模块(如 mod_php)才考虑保留 Apache。
经过多年运维经验,我强烈推荐 Ubuntu LTS 或 CentOS Stream 作为生产环境系统。特别是 Ubuntu 22.04 LTS,其对 Nginx 的支持非常完善。在安装前务必执行:
bash复制sudo apt update && sudo apt upgrade -y # Ubuntu
sudo yum update -y # CentOS
很多教程建议使用系统自带源安装,这是个大坑!系统源的 Nginx 版本往往落后官方 1-2 个大版本。以下是 Ubuntu 22.04 添加官方源的正确姿势:
bash复制# 安装必备工具
sudo apt install -y curl gnupg2 ca-certificates lsb-release
# 导入官方签名密钥(关键安全步骤)
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: release o=nginx\nPin-Priority: 900" | sudo tee /etc/apt/preferences.d/99nginx
# 安装Nginx
sudo apt update
sudo apt install nginx
安装后验证版本:
bash复制nginx -v
# 应该显示类似:nginx version: nginx/1.25.3
对于测试环境,Docker 是最快捷的方式。这是我优化过的启动命令:
bash复制docker run -d --name nginx-prod \
-p 80:80 -p 443:443 \
-v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /path/to/html:/usr/share/nginx/html:ro \
-v /path/to/certs:/etc/ssl/certs:ro \
-v /path/to/logs:/var/log/nginx \
--restart unless-stopped \
nginx:1.25-alpine
避坑提示:生产环境一定要挂载日志目录,否则容器重启后日志全丢。我曾因此浪费 3 小时排查问题。
首次安装后,立即进行以下安全加固:
bash复制sudo rm /etc/nginx/conf.d/default.conf
bash复制sudo useradd -r -s /sbin/nologin nginxuser
sudo chown -R nginxuser:nginxuser /var/log/nginx
bash复制sudo chmod 640 /etc/nginx/nginx.conf
sudo chmod 750 /etc/nginx/{conf.d,sites-available,sites-enabled}
Nginx 配置采用树状结构,理解层级关系是掌握配置的关键。这是我总结的配置脑图:
code复制nginx.conf # 主配置文件
├── events { ... } # 连接处理参数
├── http { # HTTP 服务配置
│ ├── upstream { ... } # 后端服务器组
│ ├── server { # 虚拟主机配置
│ │ ├── location / { # 请求处理规则
│ │ │ ├── proxy_pass
│ │ │ ├── root
│ │ │ └── ...
│ │ }
│ └── ...
}
worker_processes:
设置工作进程数,通常设为 CPU 核心数。通过 lscpu 查看核心数后配置:
nginx复制worker_processes auto; # 自动检测
worker_connections:
每个进程最大连接数,计算公式:
nginx复制events {
worker_connections 1024; # 默认值太小
# 最大并发 = worker_processes × worker_connections
}
keepalive_timeout:
保持连接时间,对性能影响很大。我的电商站优化经验:
nginx复制keepalive_timeout 65s; # 移动端可缩短到30s
keepalive_requests 100; # 单个连接最大请求数
生产环境推荐这样组织配置文件:
code复制/etc/nginx/
├── nginx.conf # 主配置
├── conf.d/
│ ├── gzip.conf # 压缩配置
│ └── security.conf # 安全头配置
├── sites-available/ # 可用站点配置
│ └── example.com.conf
├── sites-enabled/ # 启用站点的符号链接
│ └── example.com.conf -> ../sites-available/example.com.conf
└── snippets/ # 可复用配置片段
├── ssl-params.conf
└── proxy-headers.conf
在 nginx.conf 中通过 include 引入:
nginx复制http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
这是我优化了 3 年的静态站点配置模板:
nginx复制server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 强制HTTPS(后面会配置)
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL配置(下节详述)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 安全增强
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";
# 根目录设置
root /var/www/example.com/public;
index index.html;
# 主location块
location / {
try_files $uri $uri/ /index.html;
# 缓存控制
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
# 静态资源优化
location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|svg|woff2)$ {
expires 365d;
access_log off;
add_header Cache-Control "public, immutable";
# Brotli压缩优先
brotli_static on;
gzip_static on;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 错误页面
error_page 404 /404.html;
location = /404.html {
internal;
}
}
关键优化点:
immutable 缓存避免重复验证针对 Node.js 或 Spring Boot 应用的反向代理配置:
nginx复制upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
# 连接池优化
keepalive 32;
keepalive_timeout 60s;
keepalive_requests 1000;
}
server {
listen 443 ssl;
server_name api.example.com;
# SSL配置...
# 全局代理设置
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 30s;
proxy_send_timeout 30s;
# 缓冲区优化
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 24k;
proxy_temp_file_write_size 32k;
# 主location
location / {
proxy_pass http://backend;
# 限流保护(100请求/秒/IP)
limit_req zone=api_limit burst=50 nodelay;
}
# 健康检查端点
location /nginx-health {
access_log off;
return 200 "healthy\n";
}
# 大文件上传
location /upload {
client_max_body_size 100M;
proxy_pass http://backend;
}
}
# 限流区域定义
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
性能关键点:
keepalive 连接池减少 TCP 握手开销使用 Let's Encrypt 证书的基础命令:
bash复制sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
然后手动优化 SSL 配置:
nginx复制ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 1.1.1.1 valid=300s;
resolver_timeout 5s;
# HSTS 增强安全(谨慎开启)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
证书自动续期:
bash复制# 测试续期
sudo certbot renew --dry-run
# 实际添加cronjob
0 0 */60 * * certbot renew --quiet --post-hook "systemctl reload nginx"
worker 配置优化:
nginx复制worker_processes auto; # 自动匹配CPU核心
worker_rlimit_nofile 100000; # 提高文件描述符限制
events {
worker_connections 4096; # 每个进程连接数
multi_accept on; # 同时接受多个连接
use epoll; # Linux高性能事件模型
}
内核参数调优(/etc/sysctl.conf):
bash复制# 最大打开文件数
fs.file-max = 100000
# TCP优化
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65536
应用修改:
bash复制sudo sysctl -p
自定义日志格式:
nginx复制log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$host" $request_time $upstream_response_time '
'$upstream_cache_status';
access_log /var/log/nginx/access.log main_ext;
常用分析命令:
bash复制# 统计HTTP状态码
awk '{print $9}' access.log | sort | uniq -c | sort -rn
# 响应时间TOP 100
awk '{print $1, $NF}' access.log | sort -k2 -rn | head -100
# 实时监控500错误
tail -f access.log | awk '$9 == 500 {print $0}'
502 Bad Gateway:
curl -v http://backend:portsudo ufw statustail -f /var/log/nginx/error.log413 Request Entity Too Large:
nginx复制# 在http或server块中添加
client_max_body_size 100M;
SSL 握手失败:
openssl s_client -connect example.com:443 -showcertsnmap --script ssl-enum-ciphers -p 443 example.com禁用 Server 头信息:
nginx复制server_tokens off;
more_clear_headers Server;
限制 HTTP 方法:
nginx复制location / {
limit_except GET POST PUT DELETE {
deny all;
}
}
防目录遍历:
nginx复制location ~* \.(php|asp|aspx|jsp)$ {
deny all;
}
限流设置:
nginx复制# 定义限流区域
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
# 应用限流
location / {
limit_req zone=req_limit burst=20 nodelay;
}
连接数限制:
nginx复制limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
location / {
limit_conn conn_limit 10;
}
使用 Nginx + Lua 实现基础 WAF:
nginx复制location / {
access_by_lua_block {
local uri = ngx.var.request_uri
if string.match(uri, "[<>%'%$%*%(%)%;%+]") then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
}
启用 Stub Status 模块:
nginx复制location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
访问输出示例:
code复制Active connections: 3
server accepts handled requests
100 100 200
Reading: 0 Writing: 1 Waiting: 2
Prometheus 监控配置:
nginx复制location /metrics {
stub_status on;
access_log off;
allow 192.168.1.0/24;
deny all;
}
使用 wrk 进行基准测试:
bash复制wrk -t4 -c1000 -d60s --latency https://example.com
参数说明:
-t4:4个线程-c1000:1000个并发连接-d60s:持续60秒--latency:显示延迟分布代理缓存配置:
nginx复制proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m inactive=60m use_temp_path=off;
server {
location / {
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating;
add_header X-Cache-Status $upstream_cache_status;
}
}
FastCGI 缓存(PHP 场景):
nginx复制fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=phpcache:100m inactive=60m;
location ~ \.php$ {
fastcgi_cache phpcache;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_valid 200 301 302 30m;
}
API 网关模式:
nginx复制location /user-service/ {
proxy_pass http://user-service/;
}
location /order-service/ {
proxy_pass http://order-service/;
}
location /payment-service/ {
proxy_pass http://payment-service/;
}
金丝雀发布配置:
nginx复制upstream backend {
server 10.0.0.1:8080; # v1.0
server 10.0.0.2:8080; # v2.0
}
location / {
if ($http_x_canary = "true") {
proxy_pass http://10.0.0.2:8080;
}
proxy_pass http://backend;
}
基础 Ingress 配置示例:
yaml复制apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: example.com
http:
paths:
- path: /service1(/|$)(.*)
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
Lua 脚本示例:
nginx复制location /hello {
content_by_lua_block {
local name = ngx.var.arg_name or "anonymous"
ngx.say("Hello, ", name)
}
}
JWT 验证:
nginx复制location /protected {
access_by_lua_block {
local jwt = require "resty.jwt"
local auth = ngx.var.http_Authorization
if not auth then
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
local token = string.match(auth, "Bearer%s+(.+)")
local jwt_obj = jwt:verify("your-secret", token)
if not jwt_obj.verified then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
}
nginx -t 通过配置测试server_name 已正确配置官方文档:
进阶书籍:
实战课程:
社区支持:
经过 10 年的 Nginx 使用经验,我发现最有效的学习方式就是:先按照标准模板部署,然后逐步调整参数观察影响,最后阅读官方文档理解原理。建议每 6 个月回顾一次配置,因为 Nginx 的更新经常会引入新的优化点。